diff --git a/action/ActionHelper.cpp b/action/ActionHelper.cpp index dc6bd498..a367af16 100644 --- a/action/ActionHelper.cpp +++ b/action/ActionHelper.cpp @@ -1,110 +1,110 @@ -#include -#include -#include - -ActionHelper::ActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue) : - owner(setOwner), queueToUse(useThisQueue), ipcStore(nullptr) { -} - -ActionHelper::~ActionHelper() { -} - -ReturnValue_t ActionHelper::handleActionMessage(CommandMessage* command) { - if (command->getCommand() == ActionMessage::EXECUTE_ACTION) { - ActionId_t currentAction = ActionMessage::getActionId(command); - prepareExecution(command->getSender(), currentAction, - ActionMessage::getStoreId(command)); - return HasReturnvaluesIF::RETURN_OK; - } else { - return CommandMessage::UNKNOWN_COMMAND; - } -} - -ReturnValue_t ActionHelper::initialize(MessageQueueIF* queueToUse_) { - ipcStore = objectManager->get(objects::IPC_STORE); - if (ipcStore == nullptr) { - return HasReturnvaluesIF::RETURN_FAILED; - } - if(queueToUse_ != nullptr) { - setQueueToUse(queueToUse_); - } - - return HasReturnvaluesIF::RETURN_OK; -} - -void ActionHelper::step(uint8_t step, MessageQueueId_t reportTo, ActionId_t commandId, ReturnValue_t result) { - CommandMessage reply; - ActionMessage::setStepReply(&reply, commandId, step + STEP_OFFSET, result); - queueToUse->sendMessage(reportTo, &reply); -} - -void ActionHelper::finish(MessageQueueId_t reportTo, ActionId_t commandId, ReturnValue_t result) { - CommandMessage reply; - ActionMessage::setCompletionReply(&reply, commandId, result); - queueToUse->sendMessage(reportTo, &reply); -} - -void ActionHelper::setQueueToUse(MessageQueueIF* queue) { - queueToUse = queue; -} - -void ActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId, - store_address_t dataAddress) { - const uint8_t* dataPtr = NULL; - size_t size = 0; - ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size); - if (result != HasReturnvaluesIF::RETURN_OK) { - CommandMessage reply; - ActionMessage::setStepReply(&reply, actionId, 0, result); - queueToUse->sendMessage(commandedBy, &reply); - return; - } - result = owner->executeAction(actionId, commandedBy, dataPtr, size); - ipcStore->deleteData(dataAddress); - if (result != HasReturnvaluesIF::RETURN_OK) { - CommandMessage reply; - ActionMessage::setStepReply(&reply, actionId, 0, result); - queueToUse->sendMessage(commandedBy, &reply); - return; - } -} - -ReturnValue_t ActionHelper::reportData(MessageQueueId_t reportTo, - ActionId_t replyId, SerializeIF* data, bool hideSender) { - CommandMessage reply; - store_address_t storeAddress; - uint8_t *dataPtr; - size_t maxSize = data->getSerializedSize(); - if (maxSize == 0) { - //No error, there's simply nothing to report. - return HasReturnvaluesIF::RETURN_OK; - } - size_t size = 0; - ReturnValue_t result = ipcStore->getFreeElement(&storeAddress, maxSize, - &dataPtr); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - result = data->serialize(&dataPtr, &size, maxSize, SerializeIF::Endianness::BIG); - if (result != HasReturnvaluesIF::RETURN_OK) { - ipcStore->deleteData(storeAddress); - return result; - } - //We don't need to report the objectId, as we receive REQUESTED data before the completion success message. - //True aperiodic replies need to be reported with another dedicated message. - ActionMessage::setDataReply(&reply, replyId, storeAddress); - - //TODO Service Implementation sucks at the moment - if (hideSender){ - result = MessageQueueSenderIF::sendMessage(reportTo, &reply); - } else { - result = queueToUse->sendMessage(reportTo, &reply); - } - if ( result != HasReturnvaluesIF::RETURN_OK){ - ipcStore->deleteData(storeAddress); - } - return result; -} - -void ActionHelper::resetHelper() { -} +#include "../action/ActionHelper.h" +#include "../action/HasActionsIF.h" +#include "../objectmanager/ObjectManagerIF.h" + +ActionHelper::ActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue) : + owner(setOwner), queueToUse(useThisQueue), ipcStore(nullptr) { +} + +ActionHelper::~ActionHelper() { +} + +ReturnValue_t ActionHelper::handleActionMessage(CommandMessage* command) { + if (command->getCommand() == ActionMessage::EXECUTE_ACTION) { + ActionId_t currentAction = ActionMessage::getActionId(command); + prepareExecution(command->getSender(), currentAction, + ActionMessage::getStoreId(command)); + return HasReturnvaluesIF::RETURN_OK; + } else { + return CommandMessage::UNKNOWN_COMMAND; + } +} + +ReturnValue_t ActionHelper::initialize(MessageQueueIF* queueToUse_) { + ipcStore = objectManager->get(objects::IPC_STORE); + if (ipcStore == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + if(queueToUse_ != nullptr) { + setQueueToUse(queueToUse_); + } + + return HasReturnvaluesIF::RETURN_OK; +} + +void ActionHelper::step(uint8_t step, MessageQueueId_t reportTo, ActionId_t commandId, ReturnValue_t result) { + CommandMessage reply; + ActionMessage::setStepReply(&reply, commandId, step + STEP_OFFSET, result); + queueToUse->sendMessage(reportTo, &reply); +} + +void ActionHelper::finish(MessageQueueId_t reportTo, ActionId_t commandId, ReturnValue_t result) { + CommandMessage reply; + ActionMessage::setCompletionReply(&reply, commandId, result); + queueToUse->sendMessage(reportTo, &reply); +} + +void ActionHelper::setQueueToUse(MessageQueueIF* queue) { + queueToUse = queue; +} + +void ActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId, + store_address_t dataAddress) { + const uint8_t* dataPtr = NULL; + size_t size = 0; + ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size); + if (result != HasReturnvaluesIF::RETURN_OK) { + CommandMessage reply; + ActionMessage::setStepReply(&reply, actionId, 0, result); + queueToUse->sendMessage(commandedBy, &reply); + return; + } + result = owner->executeAction(actionId, commandedBy, dataPtr, size); + ipcStore->deleteData(dataAddress); + if (result != HasReturnvaluesIF::RETURN_OK) { + CommandMessage reply; + ActionMessage::setStepReply(&reply, actionId, 0, result); + queueToUse->sendMessage(commandedBy, &reply); + return; + } +} + +ReturnValue_t ActionHelper::reportData(MessageQueueId_t reportTo, + ActionId_t replyId, SerializeIF* data, bool hideSender) { + CommandMessage reply; + store_address_t storeAddress; + uint8_t *dataPtr; + size_t maxSize = data->getSerializedSize(); + if (maxSize == 0) { + //No error, there's simply nothing to report. + return HasReturnvaluesIF::RETURN_OK; + } + size_t size = 0; + ReturnValue_t result = ipcStore->getFreeElement(&storeAddress, maxSize, + &dataPtr); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = data->serialize(&dataPtr, &size, maxSize, SerializeIF::Endianness::BIG); + if (result != HasReturnvaluesIF::RETURN_OK) { + ipcStore->deleteData(storeAddress); + return result; + } + //We don't need to report the objectId, as we receive REQUESTED data before the completion success message. + //True aperiodic replies need to be reported with another dedicated message. + ActionMessage::setDataReply(&reply, replyId, storeAddress); + + //TODO Service Implementation sucks at the moment + if (hideSender){ + result = MessageQueueSenderIF::sendMessage(reportTo, &reply); + } else { + result = queueToUse->sendMessage(reportTo, &reply); + } + if ( result != HasReturnvaluesIF::RETURN_OK){ + ipcStore->deleteData(storeAddress); + } + return result; +} + +void ActionHelper::resetHelper() { +} diff --git a/action/ActionHelper.h b/action/ActionHelper.h index 3d8351d6..f528b031 100644 --- a/action/ActionHelper.h +++ b/action/ActionHelper.h @@ -1,93 +1,93 @@ -#ifndef ACTIONHELPER_H_ -#define ACTIONHELPER_H_ - -#include -#include -#include -/** - * \brief Action Helper is a helper class which handles action messages - * - * Components which use the HasActionIF this helper can be used to handle the action messages. - * It does handle step messages as well as other answers to action calls. It uses the executeAction function - * of its owner as callback. The call of the initialize function is mandatory and it needs a valid messageQueueIF pointer! - */ -class HasActionsIF; - -class ActionHelper { -public: - /** - * Constructor of the action helper - * @param setOwner Pointer to the owner of the interface - * @param useThisQueue messageQueue to be used, can be set during initialize function as well. - */ - ActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue); - - virtual ~ActionHelper(); - /** - * 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 executeAction function from HasActionsIF. - * If the message is invalid or the callback fails a message reply will be send to the sender of the message automatically. - * - * @param command Pointer to a command message received by the owner - * @return HasReturnvaluesIF::RETURN_OK if the message is a action message, CommandMessage::UNKNOW_COMMAND if this message ID is unkown - */ - ReturnValue_t handleActionMessage(CommandMessage* command); - /** - * Helper initialize function. Must be called before use of any other helper function - * @param queueToUse_ Pointer to the messageQueue to be used - * @return Returns RETURN_OK if successful - */ - ReturnValue_t initialize(MessageQueueIF* queueToUse_ = nullptr); - /** - * Function to be called from the owner to send a step message. Success or failure will be determined by the result value. - * - * @param step Number of steps already done - * @param reportTo The messageQueueId to report the step message to - * @param commandId ID of the executed command - * @param result Result of the execution - */ - void step(uint8_t step, MessageQueueId_t reportTo, ActionId_t commandId, ReturnValue_t result = HasReturnvaluesIF::RETURN_OK); - /** - * 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 commandId ID of the executed command - * @param result Result of the execution - */ - void finish(MessageQueueId_t reportTo, ActionId_t commandId, ReturnValue_t result = HasReturnvaluesIF::RETURN_OK); - /** - * Function to be called by the owner if an action does report data - * - * @param reportTo MessageQueueId_t to report the action completion message to - * @param replyId ID of the executed command - * @param data Pointer to the data - * @return Returns RETURN_OK if successful, otherwise failure code - */ - ReturnValue_t reportData(MessageQueueId_t reportTo, ActionId_t replyId, SerializeIF* data, bool hideSender = false); - /** - * Function to setup the MessageQueueIF* of the helper. Can be used to set the messageQueueIF* if - * message queue is unavailable at construction and initialize but must be setup before first call of other functions. - * @param queue Queue to be used by the helper - */ - void setQueueToUse(MessageQueueIF *queue); -protected: - static const uint8_t STEP_OFFSET = 1;//!< Increase of value of this per step - HasActionsIF* owner;//!< Pointer to the owner - MessageQueueIF* queueToUse;//!< Queue to be used as response sender, has to be set with - StorageManagerIF* ipcStore;//!< Pointer to an IPC Store, initialized during construction or initialize(MessageQueueIF* queueToUse_) or with setQueueToUse(MessageQueueIF *queue) - /** - *Internal function called by handleActionMessage(CommandMessage* command) - * - * @param commandedBy MessageQueueID of Commander - * @param actionId ID of action to be done - * @param dataAddress Address of additional data in IPC Store - */ - virtual void prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId, store_address_t dataAddress); - /** - * - */ - virtual void resetHelper(); -}; - -#endif /* ACTIONHELPER_H_ */ +#ifndef ACTIONHELPER_H_ +#define ACTIONHELPER_H_ + +#include "../action/ActionMessage.h" +#include "../serialize/SerializeIF.h" +#include "../ipc/MessageQueueIF.h" +/** + * \brief Action Helper is a helper class which handles action messages + * + * Components which use the HasActionIF this helper can be used to handle the action messages. + * It does handle step messages as well as other answers to action calls. It uses the executeAction function + * of its owner as callback. The call of the initialize function is mandatory and it needs a valid messageQueueIF pointer! + */ +class HasActionsIF; + +class ActionHelper { +public: + /** + * Constructor of the action helper + * @param setOwner Pointer to the owner of the interface + * @param useThisQueue messageQueue to be used, can be set during initialize function as well. + */ + ActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue); + + virtual ~ActionHelper(); + /** + * 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 executeAction function from HasActionsIF. + * If the message is invalid or the callback fails a message reply will be send to the sender of the message automatically. + * + * @param command Pointer to a command message received by the owner + * @return HasReturnvaluesIF::RETURN_OK if the message is a action message, CommandMessage::UNKNOW_COMMAND if this message ID is unkown + */ + ReturnValue_t handleActionMessage(CommandMessage* command); + /** + * Helper initialize function. Must be called before use of any other helper function + * @param queueToUse_ Pointer to the messageQueue to be used + * @return Returns RETURN_OK if successful + */ + ReturnValue_t initialize(MessageQueueIF* queueToUse_ = nullptr); + /** + * Function to be called from the owner to send a step message. Success or failure will be determined by the result value. + * + * @param step Number of steps already done + * @param reportTo The messageQueueId to report the step message to + * @param commandId ID of the executed command + * @param result Result of the execution + */ + void step(uint8_t step, MessageQueueId_t reportTo, ActionId_t commandId, ReturnValue_t result = HasReturnvaluesIF::RETURN_OK); + /** + * 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 commandId ID of the executed command + * @param result Result of the execution + */ + void finish(MessageQueueId_t reportTo, ActionId_t commandId, ReturnValue_t result = HasReturnvaluesIF::RETURN_OK); + /** + * Function to be called by the owner if an action does report data + * + * @param reportTo MessageQueueId_t to report the action completion message to + * @param replyId ID of the executed command + * @param data Pointer to the data + * @return Returns RETURN_OK if successful, otherwise failure code + */ + ReturnValue_t reportData(MessageQueueId_t reportTo, ActionId_t replyId, SerializeIF* data, bool hideSender = false); + /** + * Function to setup the MessageQueueIF* of the helper. Can be used to set the messageQueueIF* if + * message queue is unavailable at construction and initialize but must be setup before first call of other functions. + * @param queue Queue to be used by the helper + */ + void setQueueToUse(MessageQueueIF *queue); +protected: + static const uint8_t STEP_OFFSET = 1;//!< Increase of value of this per step + HasActionsIF* owner;//!< Pointer to the owner + MessageQueueIF* queueToUse;//!< Queue to be used as response sender, has to be set with + StorageManagerIF* ipcStore;//!< Pointer to an IPC Store, initialized during construction or initialize(MessageQueueIF* queueToUse_) or with setQueueToUse(MessageQueueIF *queue) + /** + *Internal function called by handleActionMessage(CommandMessage* command) + * + * @param commandedBy MessageQueueID of Commander + * @param actionId ID of action to be done + * @param dataAddress Address of additional data in IPC Store + */ + virtual void prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId, store_address_t dataAddress); + /** + * + */ + virtual void resetHelper(); +}; + +#endif /* ACTIONHELPER_H_ */ diff --git a/action/ActionMessage.cpp b/action/ActionMessage.cpp index 96ff59b6..5743cc74 100644 --- a/action/ActionMessage.cpp +++ b/action/ActionMessage.cpp @@ -1,79 +1,79 @@ -#include -#include -#include - -ActionMessage::ActionMessage() { -} - -ActionMessage::~ActionMessage() { -} - -void ActionMessage::setCommand(CommandMessage* message, ActionId_t fid, - store_address_t parameters) { - message->setCommand(EXECUTE_ACTION); - message->setParameter(fid); - message->setParameter2(parameters.raw); -} - -ActionId_t ActionMessage::getActionId(const CommandMessage* message) { - return ActionId_t(message->getParameter()); -} - -store_address_t ActionMessage::getStoreId(const CommandMessage* message) { - store_address_t temp; - temp.raw = message->getParameter2(); - return temp; -} - -void ActionMessage::setStepReply(CommandMessage* message, ActionId_t fid, uint8_t step, - ReturnValue_t result) { - if (result == HasReturnvaluesIF::RETURN_OK) { - message->setCommand(STEP_SUCCESS); - } else { - message->setCommand(STEP_FAILED); - } - message->setParameter(fid); - message->setParameter2((step << 16) + result); -} - -uint8_t ActionMessage::getStep(const CommandMessage* message) { - return uint8_t((message->getParameter2() >> 16) & 0xFF); -} - -ReturnValue_t ActionMessage::getReturnCode(const CommandMessage* message) { - return message->getParameter2() & 0xFFFF; -} - -void ActionMessage::setDataReply(CommandMessage* message, ActionId_t actionId, - store_address_t data) { - message->setCommand(DATA_REPLY); - message->setParameter(actionId); - message->setParameter2(data.raw); -} - -void ActionMessage::setCompletionReply(CommandMessage* message, - ActionId_t fid, ReturnValue_t result) { - if (result == HasReturnvaluesIF::RETURN_OK) { - message->setCommand(COMPLETION_SUCCESS); - } else { - message->setCommand(COMPLETION_FAILED); - } - message->setParameter(fid); - message->setParameter2(result); -} - -void ActionMessage::clear(CommandMessage* message) { - switch(message->getCommand()) { - case EXECUTE_ACTION: - case DATA_REPLY: { - StorageManagerIF *ipcStore = objectManager->get( - objects::IPC_STORE); - if (ipcStore != NULL) { - ipcStore->deleteData(getStoreId(message)); - } - break; - } - default: - break; - } -} +#include "../action/ActionMessage.h" +#include "../objectmanager/ObjectManagerIF.h" +#include "../storagemanager/StorageManagerIF.h" + +ActionMessage::ActionMessage() { +} + +ActionMessage::~ActionMessage() { +} + +void ActionMessage::setCommand(CommandMessage* message, ActionId_t fid, + store_address_t parameters) { + message->setCommand(EXECUTE_ACTION); + message->setParameter(fid); + message->setParameter2(parameters.raw); +} + +ActionId_t ActionMessage::getActionId(const CommandMessage* message) { + return ActionId_t(message->getParameter()); +} + +store_address_t ActionMessage::getStoreId(const CommandMessage* message) { + store_address_t temp; + temp.raw = message->getParameter2(); + return temp; +} + +void ActionMessage::setStepReply(CommandMessage* message, ActionId_t fid, uint8_t step, + ReturnValue_t result) { + if (result == HasReturnvaluesIF::RETURN_OK) { + message->setCommand(STEP_SUCCESS); + } else { + message->setCommand(STEP_FAILED); + } + message->setParameter(fid); + message->setParameter2((step << 16) + result); +} + +uint8_t ActionMessage::getStep(const CommandMessage* message) { + return uint8_t((message->getParameter2() >> 16) & 0xFF); +} + +ReturnValue_t ActionMessage::getReturnCode(const CommandMessage* message) { + return message->getParameter2() & 0xFFFF; +} + +void ActionMessage::setDataReply(CommandMessage* message, ActionId_t actionId, + store_address_t data) { + message->setCommand(DATA_REPLY); + message->setParameter(actionId); + message->setParameter2(data.raw); +} + +void ActionMessage::setCompletionReply(CommandMessage* message, + ActionId_t fid, ReturnValue_t result) { + if (result == HasReturnvaluesIF::RETURN_OK) { + message->setCommand(COMPLETION_SUCCESS); + } else { + message->setCommand(COMPLETION_FAILED); + } + message->setParameter(fid); + message->setParameter2(result); +} + +void ActionMessage::clear(CommandMessage* message) { + switch(message->getCommand()) { + case EXECUTE_ACTION: + case DATA_REPLY: { + StorageManagerIF *ipcStore = objectManager->get( + objects::IPC_STORE); + if (ipcStore != NULL) { + ipcStore->deleteData(getStoreId(message)); + } + break; + } + default: + break; + } +} diff --git a/action/ActionMessage.h b/action/ActionMessage.h index 59ad619e..aae44e16 100644 --- a/action/ActionMessage.h +++ b/action/ActionMessage.h @@ -1,32 +1,32 @@ -#ifndef ACTIONMESSAGE_H_ -#define ACTIONMESSAGE_H_ - -#include -#include -#include -typedef uint32_t ActionId_t; - -class ActionMessage { -private: - ActionMessage(); -public: - static const uint8_t MESSAGE_ID = messagetypes::ACTION; - 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_FAILED = MAKE_COMMAND_ID(3); - 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_FAILED = MAKE_COMMAND_ID(6); - virtual ~ActionMessage(); - static void setCommand(CommandMessage* message, ActionId_t fid, store_address_t parameters); - static ActionId_t getActionId(const CommandMessage* message ); - static store_address_t getStoreId(const CommandMessage* message ); - static void setStepReply(CommandMessage* message, ActionId_t fid, uint8_t step, ReturnValue_t result = HasReturnvaluesIF::RETURN_OK); - static uint8_t getStep(const CommandMessage* message ); - static ReturnValue_t getReturnCode(const CommandMessage* message ); - static void setDataReply(CommandMessage* message, ActionId_t actionId, store_address_t data); - static void setCompletionReply(CommandMessage* message, ActionId_t fid, ReturnValue_t result = HasReturnvaluesIF::RETURN_OK); - static void clear(CommandMessage* message); -}; - -#endif /* ACTIONMESSAGE_H_ */ +#ifndef ACTIONMESSAGE_H_ +#define ACTIONMESSAGE_H_ + +#include "../ipc/CommandMessage.h" +#include "../objectmanager/ObjectManagerIF.h" +#include "../storagemanager/StorageManagerIF.h" +typedef uint32_t ActionId_t; + +class ActionMessage { +private: + ActionMessage(); +public: + static const uint8_t MESSAGE_ID = messagetypes::ACTION; + 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_FAILED = MAKE_COMMAND_ID(3); + 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_FAILED = MAKE_COMMAND_ID(6); + virtual ~ActionMessage(); + static void setCommand(CommandMessage* message, ActionId_t fid, store_address_t parameters); + static ActionId_t getActionId(const CommandMessage* message ); + static store_address_t getStoreId(const CommandMessage* message ); + static void setStepReply(CommandMessage* message, ActionId_t fid, uint8_t step, ReturnValue_t result = HasReturnvaluesIF::RETURN_OK); + static uint8_t getStep(const CommandMessage* message ); + static ReturnValue_t getReturnCode(const CommandMessage* message ); + static void setDataReply(CommandMessage* message, ActionId_t actionId, store_address_t data); + static void setCompletionReply(CommandMessage* message, ActionId_t fid, ReturnValue_t result = HasReturnvaluesIF::RETURN_OK); + static void clear(CommandMessage* message); +}; + +#endif /* ACTIONMESSAGE_H_ */ diff --git a/action/CommandActionHelper.cpp b/action/CommandActionHelper.cpp index 70ffbbde..d8d506aa 100644 --- a/action/CommandActionHelper.cpp +++ b/action/CommandActionHelper.cpp @@ -1,127 +1,127 @@ -#include -#include -#include -#include -#include - -CommandActionHelper::CommandActionHelper(CommandsActionsIF *setOwner) : - owner(setOwner), queueToUse(NULL), ipcStore( - NULL), commandCount(0), lastTarget(0) { -} - -CommandActionHelper::~CommandActionHelper() { -} - -ReturnValue_t CommandActionHelper::commandAction(object_id_t commandTo, - ActionId_t actionId, SerializeIF *data) { - HasActionsIF *receiver = objectManager->get(commandTo); - if (receiver == NULL) { - return CommandsActionsIF::OBJECT_HAS_NO_FUNCTIONS; - } - store_address_t storeId; - uint8_t *storePointer; - size_t maxSize = data->getSerializedSize(); - ReturnValue_t result = ipcStore->getFreeElement(&storeId, maxSize, - &storePointer); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - size_t size = 0; - result = data->serialize(&storePointer, &size, maxSize, - SerializeIF::Endianness::BIG); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - return sendCommand(receiver->getCommandQueue(), actionId, storeId); -} - -ReturnValue_t CommandActionHelper::commandAction(object_id_t commandTo, - ActionId_t actionId, const uint8_t *data, uint32_t size) { -// if (commandCount != 0) { -// return CommandsFunctionsIF::ALREADY_COMMANDING; -// } - HasActionsIF *receiver = objectManager->get(commandTo); - if (receiver == NULL) { - return CommandsActionsIF::OBJECT_HAS_NO_FUNCTIONS; - } - store_address_t storeId; - ReturnValue_t result = ipcStore->addData(&storeId, data, size); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - return sendCommand(receiver->getCommandQueue(), actionId, storeId); -} - -ReturnValue_t CommandActionHelper::sendCommand(MessageQueueId_t queueId, - ActionId_t actionId, store_address_t storeId) { - CommandMessage command; - ActionMessage::setCommand(&command, actionId, storeId); - ReturnValue_t result = queueToUse->sendMessage(queueId, &command); - if (result != HasReturnvaluesIF::RETURN_OK) { - ipcStore->deleteData(storeId); - } - lastTarget = queueId; - commandCount++; - return result; -} - -ReturnValue_t CommandActionHelper::initialize() { - ipcStore = objectManager->get(objects::IPC_STORE); - if (ipcStore == NULL) { - return HasReturnvaluesIF::RETURN_FAILED; - } - - queueToUse = owner->getCommandQueuePtr(); - if (queueToUse == NULL) { - return HasReturnvaluesIF::RETURN_FAILED; - } - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t CommandActionHelper::handleReply(CommandMessage *reply) { - if (reply->getSender() != lastTarget) { - return HasReturnvaluesIF::RETURN_FAILED; - } - switch (reply->getCommand()) { - case ActionMessage::COMPLETION_SUCCESS: - commandCount--; - owner->completionSuccessfulReceived(ActionMessage::getActionId(reply)); - return HasReturnvaluesIF::RETURN_OK; - case ActionMessage::COMPLETION_FAILED: - commandCount--; - owner->completionFailedReceived(ActionMessage::getActionId(reply), - ActionMessage::getReturnCode(reply)); - return HasReturnvaluesIF::RETURN_OK; - case ActionMessage::STEP_SUCCESS: - owner->stepSuccessfulReceived(ActionMessage::getActionId(reply), - ActionMessage::getStep(reply)); - return HasReturnvaluesIF::RETURN_OK; - case ActionMessage::STEP_FAILED: - commandCount--; - owner->stepFailedReceived(ActionMessage::getActionId(reply), - ActionMessage::getStep(reply), - ActionMessage::getReturnCode(reply)); - return HasReturnvaluesIF::RETURN_OK; - case ActionMessage::DATA_REPLY: - extractDataForOwner(ActionMessage::getActionId(reply), - ActionMessage::getStoreId(reply)); - return HasReturnvaluesIF::RETURN_OK; - default: - return HasReturnvaluesIF::RETURN_FAILED; - } -} - -uint8_t CommandActionHelper::getCommandCount() const { - return commandCount; -} - -void CommandActionHelper::extractDataForOwner(ActionId_t actionId, store_address_t storeId) { - const uint8_t * data = NULL; - size_t size = 0; - ReturnValue_t result = ipcStore->getData(storeId, &data, &size); - if (result != HasReturnvaluesIF::RETURN_OK) { - return; - } - owner->dataReceived(actionId, data, size); - ipcStore->deleteData(storeId); -} +#include "../action/ActionMessage.h" +#include "../action/CommandActionHelper.h" +#include "../action/CommandsActionsIF.h" +#include "../action/HasActionsIF.h" +#include "../objectmanager/ObjectManagerIF.h" + +CommandActionHelper::CommandActionHelper(CommandsActionsIF *setOwner) : + owner(setOwner), queueToUse(NULL), ipcStore( + NULL), commandCount(0), lastTarget(0) { +} + +CommandActionHelper::~CommandActionHelper() { +} + +ReturnValue_t CommandActionHelper::commandAction(object_id_t commandTo, + ActionId_t actionId, SerializeIF *data) { + HasActionsIF *receiver = objectManager->get(commandTo); + if (receiver == NULL) { + return CommandsActionsIF::OBJECT_HAS_NO_FUNCTIONS; + } + store_address_t storeId; + uint8_t *storePointer; + size_t maxSize = data->getSerializedSize(); + ReturnValue_t result = ipcStore->getFreeElement(&storeId, maxSize, + &storePointer); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + size_t size = 0; + result = data->serialize(&storePointer, &size, maxSize, + SerializeIF::Endianness::BIG); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return sendCommand(receiver->getCommandQueue(), actionId, storeId); +} + +ReturnValue_t CommandActionHelper::commandAction(object_id_t commandTo, + ActionId_t actionId, const uint8_t *data, uint32_t size) { +// if (commandCount != 0) { +// return CommandsFunctionsIF::ALREADY_COMMANDING; +// } + HasActionsIF *receiver = objectManager->get(commandTo); + if (receiver == NULL) { + return CommandsActionsIF::OBJECT_HAS_NO_FUNCTIONS; + } + store_address_t storeId; + ReturnValue_t result = ipcStore->addData(&storeId, data, size); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return sendCommand(receiver->getCommandQueue(), actionId, storeId); +} + +ReturnValue_t CommandActionHelper::sendCommand(MessageQueueId_t queueId, + ActionId_t actionId, store_address_t storeId) { + CommandMessage command; + ActionMessage::setCommand(&command, actionId, storeId); + ReturnValue_t result = queueToUse->sendMessage(queueId, &command); + if (result != HasReturnvaluesIF::RETURN_OK) { + ipcStore->deleteData(storeId); + } + lastTarget = queueId; + commandCount++; + return result; +} + +ReturnValue_t CommandActionHelper::initialize() { + ipcStore = objectManager->get(objects::IPC_STORE); + if (ipcStore == NULL) { + return HasReturnvaluesIF::RETURN_FAILED; + } + + queueToUse = owner->getCommandQueuePtr(); + if (queueToUse == NULL) { + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t CommandActionHelper::handleReply(CommandMessage *reply) { + if (reply->getSender() != lastTarget) { + return HasReturnvaluesIF::RETURN_FAILED; + } + switch (reply->getCommand()) { + case ActionMessage::COMPLETION_SUCCESS: + commandCount--; + owner->completionSuccessfulReceived(ActionMessage::getActionId(reply)); + return HasReturnvaluesIF::RETURN_OK; + case ActionMessage::COMPLETION_FAILED: + commandCount--; + owner->completionFailedReceived(ActionMessage::getActionId(reply), + ActionMessage::getReturnCode(reply)); + return HasReturnvaluesIF::RETURN_OK; + case ActionMessage::STEP_SUCCESS: + owner->stepSuccessfulReceived(ActionMessage::getActionId(reply), + ActionMessage::getStep(reply)); + return HasReturnvaluesIF::RETURN_OK; + case ActionMessage::STEP_FAILED: + commandCount--; + owner->stepFailedReceived(ActionMessage::getActionId(reply), + ActionMessage::getStep(reply), + ActionMessage::getReturnCode(reply)); + return HasReturnvaluesIF::RETURN_OK; + case ActionMessage::DATA_REPLY: + extractDataForOwner(ActionMessage::getActionId(reply), + ActionMessage::getStoreId(reply)); + return HasReturnvaluesIF::RETURN_OK; + default: + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +uint8_t CommandActionHelper::getCommandCount() const { + return commandCount; +} + +void CommandActionHelper::extractDataForOwner(ActionId_t actionId, store_address_t storeId) { + const uint8_t * data = NULL; + size_t size = 0; + ReturnValue_t result = ipcStore->getData(storeId, &data, &size); + if (result != HasReturnvaluesIF::RETURN_OK) { + return; + } + owner->dataReceived(actionId, data, size); + ipcStore->deleteData(storeId); +} diff --git a/action/CommandActionHelper.h b/action/CommandActionHelper.h index 24d0380c..edbcaadd 100644 --- a/action/CommandActionHelper.h +++ b/action/CommandActionHelper.h @@ -1,36 +1,36 @@ -#ifndef COMMANDACTIONHELPER_H_ -#define COMMANDACTIONHELPER_H_ - -#include -#include -#include -#include -#include -#include - -class CommandsActionsIF; - -class CommandActionHelper { - friend class CommandsActionsIF; -public: - CommandActionHelper(CommandsActionsIF* owner); - virtual ~CommandActionHelper(); - ReturnValue_t commandAction(object_id_t commandTo, - ActionId_t actionId, const uint8_t* data, uint32_t size); - ReturnValue_t commandAction(object_id_t commandTo, - ActionId_t actionId, SerializeIF* data); - ReturnValue_t initialize(); - ReturnValue_t handleReply(CommandMessage* reply); - uint8_t getCommandCount() const; -private: - CommandsActionsIF* owner; - MessageQueueIF* queueToUse; - StorageManagerIF* ipcStore; - uint8_t commandCount; - MessageQueueId_t lastTarget; - void extractDataForOwner(ActionId_t actionId, store_address_t storeId); - ReturnValue_t sendCommand(MessageQueueId_t queueId, ActionId_t actionId, - store_address_t storeId); -}; - -#endif /* COMMANDACTIONHELPER_H_ */ +#ifndef COMMANDACTIONHELPER_H_ +#define COMMANDACTIONHELPER_H_ + +#include "../action/ActionMessage.h" +#include "../objectmanager/ObjectManagerIF.h" +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../serialize/SerializeIF.h" +#include "../storagemanager/StorageManagerIF.h" +#include "../ipc/MessageQueueIF.h" + +class CommandsActionsIF; + +class CommandActionHelper { + friend class CommandsActionsIF; +public: + CommandActionHelper(CommandsActionsIF* owner); + virtual ~CommandActionHelper(); + ReturnValue_t commandAction(object_id_t commandTo, + ActionId_t actionId, const uint8_t* data, uint32_t size); + ReturnValue_t commandAction(object_id_t commandTo, + ActionId_t actionId, SerializeIF* data); + ReturnValue_t initialize(); + ReturnValue_t handleReply(CommandMessage* reply); + uint8_t getCommandCount() const; +private: + CommandsActionsIF* owner; + MessageQueueIF* queueToUse; + StorageManagerIF* ipcStore; + uint8_t commandCount; + MessageQueueId_t lastTarget; + void extractDataForOwner(ActionId_t actionId, store_address_t storeId); + ReturnValue_t sendCommand(MessageQueueId_t queueId, ActionId_t actionId, + store_address_t storeId); +}; + +#endif /* COMMANDACTIONHELPER_H_ */ diff --git a/action/CommandsActionsIF.h b/action/CommandsActionsIF.h index db76fb50..bead3140 100644 --- a/action/CommandsActionsIF.h +++ b/action/CommandsActionsIF.h @@ -1,34 +1,34 @@ -#ifndef COMMANDSACTIONSIF_H_ -#define COMMANDSACTIONSIF_H_ - -#include -#include -#include - -/** - * Interface to separate commanding actions of other objects. - * In next iteration, IF should be shortened to three calls: - * - dataReceived(data) - * - successReceived(id, step) - * - failureReceived(id, step, cause) - * or even - * - replyReceived(id, step, cause) (if cause == OK, it's a success). - */ -class CommandsActionsIF { - friend class CommandActionHelper; -public: - 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 ALREADY_COMMANDING = MAKE_RETURN_CODE(2); - virtual ~CommandsActionsIF() {} - virtual MessageQueueIF* getCommandQueuePtr() = 0; -protected: - virtual void stepSuccessfulReceived(ActionId_t actionId, uint8_t step) = 0; - virtual void stepFailedReceived(ActionId_t actionId, uint8_t step, ReturnValue_t returnCode) = 0; - virtual void dataReceived(ActionId_t actionId, const uint8_t* data, uint32_t size) = 0; - virtual void completionSuccessfulReceived(ActionId_t actionId) = 0; - virtual void completionFailedReceived(ActionId_t actionId, ReturnValue_t returnCode) = 0; -}; - - -#endif /* COMMANDSACTIONSIF_H_ */ +#ifndef COMMANDSACTIONSIF_H_ +#define COMMANDSACTIONSIF_H_ + +#include "../action/CommandActionHelper.h" +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../ipc/MessageQueueIF.h" + +/** + * Interface to separate commanding actions of other objects. + * In next iteration, IF should be shortened to three calls: + * - dataReceived(data) + * - successReceived(id, step) + * - failureReceived(id, step, cause) + * or even + * - replyReceived(id, step, cause) (if cause == OK, it's a success). + */ +class CommandsActionsIF { + friend class CommandActionHelper; +public: + 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 ALREADY_COMMANDING = MAKE_RETURN_CODE(2); + virtual ~CommandsActionsIF() {} + virtual MessageQueueIF* getCommandQueuePtr() = 0; +protected: + virtual void stepSuccessfulReceived(ActionId_t actionId, uint8_t step) = 0; + virtual void stepFailedReceived(ActionId_t actionId, uint8_t step, ReturnValue_t returnCode) = 0; + virtual void dataReceived(ActionId_t actionId, const uint8_t* data, uint32_t size) = 0; + virtual void completionSuccessfulReceived(ActionId_t actionId) = 0; + virtual void completionFailedReceived(ActionId_t actionId, ReturnValue_t returnCode) = 0; +}; + + +#endif /* COMMANDSACTIONSIF_H_ */ diff --git a/action/HasActionsIF.h b/action/HasActionsIF.h index 008d9eaf..283664a3 100644 --- a/action/HasActionsIF.h +++ b/action/HasActionsIF.h @@ -1,60 +1,60 @@ -#ifndef FRAMEWORK_ACTION_HASACTIONSIF_H_ -#define FRAMEWORK_ACTION_HASACTIONSIF_H_ - -#include -#include -#include -#include -#include -/** - * @brief - * Interface for component which uses actions - * - * @details - * This interface is used to execute actions in the component. Actions, in the - * sense of this interface, are activities with a well-defined beginning and - * end in time. They may adjust sub-states of components, but are not supposed - * to change the main mode of operation, which is handled with the HasModesIF - * described below. - * - * The HasActionsIF allows components to define such actions and make them - * available for other components to use. Implementing the interface is - * straightforward: There’s a single executeAction call, which provides an - * identifier for the action to execute, as well as arbitrary parameters for - * input. - * Aside from direct, software-based actions, it is used in device handler - * components as an interface to forward commands to devices. - * Implementing components of the interface are supposed to check identifier - * (ID) and parameters and immediately start execution of the action. - * It is, however, not required to immediately finish execution. - * Instead, this may be deferred to a later point in time, at which the - * component needs to inform the caller about finished or failed execution. - * - * @ingroup interfaces - */ -class HasActionsIF { -public: - 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 INVALID_PARAMETERS = MAKE_RETURN_CODE(2); - static const ReturnValue_t EXECUTION_FINISHED = MAKE_RETURN_CODE(3); - static const ReturnValue_t INVALID_ACTION_ID = MAKE_RETURN_CODE(4); - virtual ~HasActionsIF() { } - /** - * Function to get the MessageQueueId_t of the implementing object - * @return MessageQueueId_t of the object - */ - virtual MessageQueueId_t getCommandQueue() const = 0; - /** - * Execute or initialize the execution of a certain function. - * Returning #EXECUTION_FINISHED or a failure code, nothing else needs to - * be done. When needing more steps, return RETURN_OK and issue steps and - * completion manually. - * One "step failed" or completion report must be issued! - */ - virtual ReturnValue_t executeAction(ActionId_t actionId, - MessageQueueId_t commandedBy, const uint8_t* data, size_t size) = 0; -}; - - -#endif /* FRAMEWORK_ACTION_HASACTIONSIF_H_ */ +#ifndef FRAMEWORK_ACTION_HASACTIONSIF_H_ +#define FRAMEWORK_ACTION_HASACTIONSIF_H_ + +#include "../action/ActionHelper.h" +#include "../action/ActionMessage.h" +#include "../action/SimpleActionHelper.h" +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../ipc/MessageQueueIF.h" +/** + * @brief + * Interface for component which uses actions + * + * @details + * This interface is used to execute actions in the component. Actions, in the + * sense of this interface, are activities with a well-defined beginning and + * end in time. They may adjust sub-states of components, but are not supposed + * to change the main mode of operation, which is handled with the HasModesIF + * described below. + * + * The HasActionsIF allows components to define such actions and make them + * available for other components to use. Implementing the interface is + * straightforward: There’s a single executeAction call, which provides an + * identifier for the action to execute, as well as arbitrary parameters for + * input. + * Aside from direct, software-based actions, it is used in device handler + * components as an interface to forward commands to devices. + * Implementing components of the interface are supposed to check identifier + * (ID) and parameters and immediately start execution of the action. + * It is, however, not required to immediately finish execution. + * Instead, this may be deferred to a later point in time, at which the + * component needs to inform the caller about finished or failed execution. + * + * @ingroup interfaces + */ +class HasActionsIF { +public: + 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 INVALID_PARAMETERS = MAKE_RETURN_CODE(2); + static const ReturnValue_t EXECUTION_FINISHED = MAKE_RETURN_CODE(3); + static const ReturnValue_t INVALID_ACTION_ID = MAKE_RETURN_CODE(4); + virtual ~HasActionsIF() { } + /** + * Function to get the MessageQueueId_t of the implementing object + * @return MessageQueueId_t of the object + */ + virtual MessageQueueId_t getCommandQueue() const = 0; + /** + * Execute or initialize the execution of a certain function. + * Returning #EXECUTION_FINISHED or a failure code, nothing else needs to + * be done. When needing more steps, return RETURN_OK and issue steps and + * completion manually. + * One "step failed" or completion report must be issued! + */ + virtual ReturnValue_t executeAction(ActionId_t actionId, + MessageQueueId_t commandedBy, const uint8_t* data, size_t size) = 0; +}; + + +#endif /* FRAMEWORK_ACTION_HASACTIONSIF_H_ */ diff --git a/action/SimpleActionHelper.cpp b/action/SimpleActionHelper.cpp index 6861fc28..83ce3c85 100644 --- a/action/SimpleActionHelper.cpp +++ b/action/SimpleActionHelper.cpp @@ -1,74 +1,74 @@ -#include -#include -SimpleActionHelper::SimpleActionHelper(HasActionsIF* setOwner, - MessageQueueIF* useThisQueue) : - ActionHelper(setOwner, useThisQueue), isExecuting(false), lastCommander( - 0), lastAction(0), stepCount(0) { -} - -SimpleActionHelper::~SimpleActionHelper() { -} - -void SimpleActionHelper::step(ReturnValue_t result) { - //STEP_OFFESET is subtracted to compensate for adding offset in base method, which is not necessary here. - ActionHelper::step(stepCount - STEP_OFFSET, lastCommander, lastAction, - result); - if (result != HasReturnvaluesIF::RETURN_OK) { - resetHelper(); - } -} - -void SimpleActionHelper::finish(ReturnValue_t result) { - ActionHelper::finish(lastCommander, lastAction, result); - resetHelper(); -} - -ReturnValue_t SimpleActionHelper::reportData(SerializeIF* data) { - return ActionHelper::reportData(lastCommander, lastAction, data); -} - -void SimpleActionHelper::resetHelper() { - stepCount = 0; - isExecuting = false; - lastAction = 0; - lastCommander = 0; -} - -void SimpleActionHelper::prepareExecution(MessageQueueId_t commandedBy, - ActionId_t actionId, store_address_t dataAddress) { - CommandMessage reply; - if (isExecuting) { - ipcStore->deleteData(dataAddress); - ActionMessage::setStepReply(&reply, actionId, 0, - HasActionsIF::IS_BUSY); - queueToUse->sendMessage(commandedBy, &reply); - } - const uint8_t* dataPtr = NULL; - size_t size = 0; - ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size); - if (result != HasReturnvaluesIF::RETURN_OK) { - ActionMessage::setStepReply(&reply, actionId, 0, result); - queueToUse->sendMessage(commandedBy, &reply); - return; - } - lastCommander = commandedBy; - lastAction = actionId; - result = owner->executeAction(actionId, commandedBy, dataPtr, size); - ipcStore->deleteData(dataAddress); - switch (result) { - case HasReturnvaluesIF::RETURN_OK: - isExecuting = true; - stepCount++; - break; - case HasActionsIF::EXECUTION_FINISHED: - ActionMessage::setCompletionReply(&reply, actionId, - HasReturnvaluesIF::RETURN_OK); - queueToUse->sendMessage(commandedBy, &reply); - break; - default: - ActionMessage::setStepReply(&reply, actionId, 0, result); - queueToUse->sendMessage(commandedBy, &reply); - break; - } - -} +#include "../action/HasActionsIF.h" +#include "../action/SimpleActionHelper.h" +SimpleActionHelper::SimpleActionHelper(HasActionsIF* setOwner, + MessageQueueIF* useThisQueue) : + ActionHelper(setOwner, useThisQueue), isExecuting(false), lastCommander( + 0), lastAction(0), stepCount(0) { +} + +SimpleActionHelper::~SimpleActionHelper() { +} + +void SimpleActionHelper::step(ReturnValue_t result) { + //STEP_OFFESET is subtracted to compensate for adding offset in base method, which is not necessary here. + ActionHelper::step(stepCount - STEP_OFFSET, lastCommander, lastAction, + result); + if (result != HasReturnvaluesIF::RETURN_OK) { + resetHelper(); + } +} + +void SimpleActionHelper::finish(ReturnValue_t result) { + ActionHelper::finish(lastCommander, lastAction, result); + resetHelper(); +} + +ReturnValue_t SimpleActionHelper::reportData(SerializeIF* data) { + return ActionHelper::reportData(lastCommander, lastAction, data); +} + +void SimpleActionHelper::resetHelper() { + stepCount = 0; + isExecuting = false; + lastAction = 0; + lastCommander = 0; +} + +void SimpleActionHelper::prepareExecution(MessageQueueId_t commandedBy, + ActionId_t actionId, store_address_t dataAddress) { + CommandMessage reply; + if (isExecuting) { + ipcStore->deleteData(dataAddress); + ActionMessage::setStepReply(&reply, actionId, 0, + HasActionsIF::IS_BUSY); + queueToUse->sendMessage(commandedBy, &reply); + } + const uint8_t* dataPtr = NULL; + size_t size = 0; + ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size); + if (result != HasReturnvaluesIF::RETURN_OK) { + ActionMessage::setStepReply(&reply, actionId, 0, result); + queueToUse->sendMessage(commandedBy, &reply); + return; + } + lastCommander = commandedBy; + lastAction = actionId; + result = owner->executeAction(actionId, commandedBy, dataPtr, size); + ipcStore->deleteData(dataAddress); + switch (result) { + case HasReturnvaluesIF::RETURN_OK: + isExecuting = true; + stepCount++; + break; + case HasActionsIF::EXECUTION_FINISHED: + ActionMessage::setCompletionReply(&reply, actionId, + HasReturnvaluesIF::RETURN_OK); + queueToUse->sendMessage(commandedBy, &reply); + break; + default: + ActionMessage::setStepReply(&reply, actionId, 0, result); + queueToUse->sendMessage(commandedBy, &reply); + break; + } + +} diff --git a/action/SimpleActionHelper.h b/action/SimpleActionHelper.h index 71e73c5a..05025f82 100644 --- a/action/SimpleActionHelper.h +++ b/action/SimpleActionHelper.h @@ -1,24 +1,24 @@ -#ifndef SIMPLEACTIONHELPER_H_ -#define SIMPLEACTIONHELPER_H_ - -#include - -class SimpleActionHelper: public ActionHelper { -public: - SimpleActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue); - virtual ~SimpleActionHelper(); - void step(ReturnValue_t result = HasReturnvaluesIF::RETURN_OK); - void finish(ReturnValue_t result = HasReturnvaluesIF::RETURN_OK); - ReturnValue_t reportData(SerializeIF* data); - -protected: - void prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId, store_address_t dataAddress); - virtual void resetHelper(); -private: - bool isExecuting; - MessageQueueId_t lastCommander; - ActionId_t lastAction; - uint8_t stepCount; -}; - -#endif /* SIMPLEACTIONHELPER_H_ */ +#ifndef SIMPLEACTIONHELPER_H_ +#define SIMPLEACTIONHELPER_H_ + +#include "../action/ActionHelper.h" + +class SimpleActionHelper: public ActionHelper { +public: + SimpleActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue); + virtual ~SimpleActionHelper(); + void step(ReturnValue_t result = HasReturnvaluesIF::RETURN_OK); + void finish(ReturnValue_t result = HasReturnvaluesIF::RETURN_OK); + ReturnValue_t reportData(SerializeIF* data); + +protected: + void prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId, store_address_t dataAddress); + virtual void resetHelper(); +private: + bool isExecuting; + MessageQueueId_t lastCommander; + ActionId_t lastAction; + uint8_t stepCount; +}; + +#endif /* SIMPLEACTIONHELPER_H_ */ diff --git a/container/ArrayList.h b/container/ArrayList.h index 8138864b..436dc716 100644 --- a/container/ArrayList.h +++ b/container/ArrayList.h @@ -1,247 +1,247 @@ -#ifndef FRAMEWORK_CONTAINER_ARRAYLIST_H_ -#define FRAMEWORK_CONTAINER_ARRAYLIST_H_ - -#include -#include -#include - -/** - * @brief A List that stores its values in an array. - * @details - * The underlying storage is an array that can be allocated by the class - * itself or supplied via ctor. - * - * @ingroup container - */ -template -class ArrayList { - template friend class SerialArrayListAdapter; -public: - static const uint8_t INTERFACE_ID = CLASS_ID::ARRAY_LIST; - static const ReturnValue_t FULL = MAKE_RETURN_CODE(0x01); - - /** - * Copying is forbiden by declaring copy ctor and copy assignment deleted - * It is too ambigous in this case. - * (Allocate a new backend? Use the same? What to do in an modifying call?) - */ - ArrayList(const ArrayList& other) = delete; - const ArrayList& operator=(const ArrayList& other) = delete; - - /** - * Number of Elements stored in this List - */ - count_t size; - - /** - * This is the allocating constructor; - * - * It allocates an array of the specified size. - * - * @param maxSize - */ - ArrayList(count_t maxSize) : - size(0), maxSize_(maxSize), allocated(true) { - entries = new T[maxSize]; - } - - /** - * This is the non-allocating constructor - * - * It expects a pointer to an array of a certain size and initializes itself to it. - * - * @param storage the array to use as backend - * @param maxSize size of storage - * @param size size of data already present in storage - */ - ArrayList(T *storage, count_t maxSize, count_t size = 0) : - size(size), entries(storage), maxSize_(maxSize), allocated(false) { - } - - /** - * Destructor, if the allocating constructor was used, it deletes the array. - */ - virtual ~ArrayList() { - if (allocated) { - delete[] entries; - } - } - - /** - * An Iterator to go trough an ArrayList - * - * It stores a pointer to an element and increments the - * pointer when incremented itself. - */ - class Iterator { - public: - /** - * Empty ctor, points to NULL - */ - Iterator(): value(0) {} - - /** - * Initializes the Iterator to point to an element - * - * @param initialize - */ - Iterator(T *initialize) { - value = initialize; - } - - /** - * The current element the iterator points to - */ - T *value; - - Iterator& operator++() { - value++; - return *this; - } - - Iterator operator++(int) { - Iterator tmp(*this); - operator++(); - return tmp; - } - - Iterator& operator--() { - value--; - return *this; - } - - Iterator operator--(int) { - Iterator tmp(*this); - operator--(); - return tmp; - } - - T operator*() { - return *value; - } - - T *operator->() { - return value; - } - - const T *operator->() const{ - return value; - } - - //SHOULDDO this should be implemented as non-member - bool operator==(const typename ArrayList::Iterator& other) const{ - return (value == other.value); - } - - //SHOULDDO this should be implemented as non-member - bool operator!=(const typename ArrayList::Iterator& other) const { - return !(*this == other); - } - }; - - /** - * Iterator pointing to the first stored elmement - * - * @return Iterator to the first element - */ - Iterator begin() const { - return Iterator(&entries[0]); - } - - /** - * returns an Iterator pointing to the element after the last stored entry - * - * @return Iterator to the element after the last entry - */ - Iterator end() const { - return Iterator(&entries[size]); - } - - T & operator[](count_t i) const { - return entries[i]; - } - - /** - * The first element - * - * @return pointer to the first stored element - */ - T *front() { - return entries; - } - - /** - * The last element - * - * does not return a valid pointer if called on an empty list. - * - * @return pointer to the last stored element - */ - T *back() { - return &entries[size - 1]; - //Alternative solution - //return const_cast(static_cast(*this).back()); - } - - const T* back() const{ - return &entries[size-1]; - } - - /** - * The maximum number of elements this List can contain - * - * @return maximum number of elements - */ - uint32_t maxSize() const { - return this->maxSize_; - } - - /** - * Insert a new element into the list. - * - * The new element is inserted after the last stored element. - * - * @param entry - * @return - * -@c FULL if the List is full - * -@c RETURN_OK else - */ - ReturnValue_t insert(T entry) { - if (size >= maxSize_) { - return FULL; - } - entries[size] = entry; - ++size; - return HasReturnvaluesIF::RETURN_OK; - } - - /** - * clear the List - * - * This does not actually clear all entries, it only sets the size to 0. - */ - void clear() { - size = 0; - } - - count_t remaining() { - return (maxSize_ - size); - } - -protected: - /** - * pointer to the array in which the entries are stored - */ - T *entries; - /** - * remembering the maximum size - */ - uint32_t maxSize_; - - /** - * true if the array was allocated and needs to be deleted in the destructor. - */ - bool allocated; -}; - -#endif /* ARRAYLIST_H_ */ +#ifndef FRAMEWORK_CONTAINER_ARRAYLIST_H_ +#define FRAMEWORK_CONTAINER_ARRAYLIST_H_ + +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../serialize/SerializeAdapter.h" +#include "../serialize/SerializeIF.h" + +/** + * @brief A List that stores its values in an array. + * @details + * The underlying storage is an array that can be allocated by the class + * itself or supplied via ctor. + * + * @ingroup container + */ +template +class ArrayList { + template friend class SerialArrayListAdapter; +public: + static const uint8_t INTERFACE_ID = CLASS_ID::ARRAY_LIST; + static const ReturnValue_t FULL = MAKE_RETURN_CODE(0x01); + + /** + * Copying is forbiden by declaring copy ctor and copy assignment deleted + * It is too ambigous in this case. + * (Allocate a new backend? Use the same? What to do in an modifying call?) + */ + ArrayList(const ArrayList& other) = delete; + const ArrayList& operator=(const ArrayList& other) = delete; + + /** + * Number of Elements stored in this List + */ + count_t size; + + /** + * This is the allocating constructor; + * + * It allocates an array of the specified size. + * + * @param maxSize + */ + ArrayList(count_t maxSize) : + size(0), maxSize_(maxSize), allocated(true) { + entries = new T[maxSize]; + } + + /** + * This is the non-allocating constructor + * + * It expects a pointer to an array of a certain size and initializes itself to it. + * + * @param storage the array to use as backend + * @param maxSize size of storage + * @param size size of data already present in storage + */ + ArrayList(T *storage, count_t maxSize, count_t size = 0) : + size(size), entries(storage), maxSize_(maxSize), allocated(false) { + } + + /** + * Destructor, if the allocating constructor was used, it deletes the array. + */ + virtual ~ArrayList() { + if (allocated) { + delete[] entries; + } + } + + /** + * An Iterator to go trough an ArrayList + * + * It stores a pointer to an element and increments the + * pointer when incremented itself. + */ + class Iterator { + public: + /** + * Empty ctor, points to NULL + */ + Iterator(): value(0) {} + + /** + * Initializes the Iterator to point to an element + * + * @param initialize + */ + Iterator(T *initialize) { + value = initialize; + } + + /** + * The current element the iterator points to + */ + T *value; + + Iterator& operator++() { + value++; + return *this; + } + + Iterator operator++(int) { + Iterator tmp(*this); + operator++(); + return tmp; + } + + Iterator& operator--() { + value--; + return *this; + } + + Iterator operator--(int) { + Iterator tmp(*this); + operator--(); + return tmp; + } + + T operator*() { + return *value; + } + + T *operator->() { + return value; + } + + const T *operator->() const{ + return value; + } + + //SHOULDDO this should be implemented as non-member + bool operator==(const typename ArrayList::Iterator& other) const{ + return (value == other.value); + } + + //SHOULDDO this should be implemented as non-member + bool operator!=(const typename ArrayList::Iterator& other) const { + return !(*this == other); + } + }; + + /** + * Iterator pointing to the first stored elmement + * + * @return Iterator to the first element + */ + Iterator begin() const { + return Iterator(&entries[0]); + } + + /** + * returns an Iterator pointing to the element after the last stored entry + * + * @return Iterator to the element after the last entry + */ + Iterator end() const { + return Iterator(&entries[size]); + } + + T & operator[](count_t i) const { + return entries[i]; + } + + /** + * The first element + * + * @return pointer to the first stored element + */ + T *front() { + return entries; + } + + /** + * The last element + * + * does not return a valid pointer if called on an empty list. + * + * @return pointer to the last stored element + */ + T *back() { + return &entries[size - 1]; + //Alternative solution + //return const_cast(static_cast(*this).back()); + } + + const T* back() const{ + return &entries[size-1]; + } + + /** + * The maximum number of elements this List can contain + * + * @return maximum number of elements + */ + uint32_t maxSize() const { + return this->maxSize_; + } + + /** + * Insert a new element into the list. + * + * The new element is inserted after the last stored element. + * + * @param entry + * @return + * -@c FULL if the List is full + * -@c RETURN_OK else + */ + ReturnValue_t insert(T entry) { + if (size >= maxSize_) { + return FULL; + } + entries[size] = entry; + ++size; + return HasReturnvaluesIF::RETURN_OK; + } + + /** + * clear the List + * + * This does not actually clear all entries, it only sets the size to 0. + */ + void clear() { + size = 0; + } + + count_t remaining() { + return (maxSize_ - size); + } + +protected: + /** + * pointer to the array in which the entries are stored + */ + T *entries; + /** + * remembering the maximum size + */ + uint32_t maxSize_; + + /** + * true if the array was allocated and needs to be deleted in the destructor. + */ + bool allocated; +}; + +#endif /* ARRAYLIST_H_ */ diff --git a/container/DynamicFIFO.h b/container/DynamicFIFO.h index 59adfb3a..b63cee65 100644 --- a/container/DynamicFIFO.h +++ b/container/DynamicFIFO.h @@ -1,42 +1,42 @@ -#ifndef FRAMEWORK_CONTAINER_DYNAMICFIFO_H_ -#define FRAMEWORK_CONTAINER_DYNAMICFIFO_H_ - -#include -#include - -/** - * @brief Simple First-In-First-Out data structure. The maximum size - * can be set in the constructor. - * @details - * The maximum capacity can be determined at run-time, so this container - * performs dynamic memory allocation! - * The public interface of FIFOBase exposes the user interface for the FIFO. - * @tparam T Entry Type - * @tparam capacity Maximum capacity - */ -template -class DynamicFIFO: public FIFOBase { -public: - DynamicFIFO(size_t maxCapacity): FIFOBase(nullptr, maxCapacity), - fifoVector(maxCapacity) { - // trying to pass the pointer of the uninitialized vector - // to the FIFOBase constructor directly lead to a super evil bug. - // So we do it like this now. - this->setData(fifoVector.data()); - }; - - /** - * @brief Custom copy constructor which prevents setting the - * underlying pointer wrong. - */ - DynamicFIFO(const DynamicFIFO& other): FIFOBase(other), - fifoVector(other.maxCapacity) { - this->setData(fifoVector.data()); - } - - -private: - std::vector fifoVector; -}; - -#endif /* FRAMEWORK_CONTAINER_DYNAMICFIFO_H_ */ +#ifndef FRAMEWORK_CONTAINER_DYNAMICFIFO_H_ +#define FRAMEWORK_CONTAINER_DYNAMICFIFO_H_ + +#include "../container/FIFOBase.h" +#include + +/** + * @brief Simple First-In-First-Out data structure. The maximum size + * can be set in the constructor. + * @details + * The maximum capacity can be determined at run-time, so this container + * performs dynamic memory allocation! + * The public interface of FIFOBase exposes the user interface for the FIFO. + * @tparam T Entry Type + * @tparam capacity Maximum capacity + */ +template +class DynamicFIFO: public FIFOBase { +public: + DynamicFIFO(size_t maxCapacity): FIFOBase(nullptr, maxCapacity), + fifoVector(maxCapacity) { + // trying to pass the pointer of the uninitialized vector + // to the FIFOBase constructor directly lead to a super evil bug. + // So we do it like this now. + this->setData(fifoVector.data()); + }; + + /** + * @brief Custom copy constructor which prevents setting the + * underlying pointer wrong. + */ + DynamicFIFO(const DynamicFIFO& other): FIFOBase(other), + fifoVector(other.maxCapacity) { + this->setData(fifoVector.data()); + } + + +private: + std::vector fifoVector; +}; + +#endif /* FRAMEWORK_CONTAINER_DYNAMICFIFO_H_ */ diff --git a/container/FIFO.h b/container/FIFO.h index 2e332dc2..a870e773 100644 --- a/container/FIFO.h +++ b/container/FIFO.h @@ -1,34 +1,34 @@ -#ifndef FRAMEWORK_CONTAINER_FIFO_H_ -#define FRAMEWORK_CONTAINER_FIFO_H_ - -#include -#include -#include - -/** - * @brief Simple First-In-First-Out data structure with size fixed at - * compile time - * @details - * Performs no dynamic memory allocation. - * The public interface of FIFOBase exposes the user interface for the FIFO. - * @tparam T Entry Type - * @tparam capacity Maximum capacity - */ -template -class FIFO: public FIFOBase { -public: - FIFO(): FIFOBase(fifoArray.data(), capacity) {}; - - /** - * @brief Custom copy constructor to set pointer correctly. - * @param other - */ - FIFO(const FIFO& other): FIFOBase(other) { - this->setData(fifoArray.data()); - } - -private: - std::array fifoArray; -}; - -#endif /* FRAMEWORK_CONTAINERS_STATICFIFO_H_ */ +#ifndef FRAMEWORK_CONTAINER_FIFO_H_ +#define FRAMEWORK_CONTAINER_FIFO_H_ + +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../container/FIFOBase.h" +#include + +/** + * @brief Simple First-In-First-Out data structure with size fixed at + * compile time + * @details + * Performs no dynamic memory allocation. + * The public interface of FIFOBase exposes the user interface for the FIFO. + * @tparam T Entry Type + * @tparam capacity Maximum capacity + */ +template +class FIFO: public FIFOBase { +public: + FIFO(): FIFOBase(fifoArray.data(), capacity) {}; + + /** + * @brief Custom copy constructor to set pointer correctly. + * @param other + */ + FIFO(const FIFO& other): FIFOBase(other) { + this->setData(fifoArray.data()); + } + +private: + std::array fifoArray; +}; + +#endif /* FRAMEWORK_CONTAINERS_STATICFIFO_H_ */ diff --git a/container/FIFOBase.h b/container/FIFOBase.h index 7f8bde96..ddccbdd4 100644 --- a/container/FIFOBase.h +++ b/container/FIFOBase.h @@ -1,65 +1,65 @@ -#ifndef FRAMEWORK_CONTAINER_FIFOBASE_H_ -#define FRAMEWORK_CONTAINER_FIFOBASE_H_ - -#include -#include -#include - -template -class FIFOBase { -public: - static const uint8_t INTERFACE_ID = CLASS_ID::FIFO_CLASS; - static const ReturnValue_t FULL = MAKE_RETURN_CODE(1); - static const ReturnValue_t EMPTY = MAKE_RETURN_CODE(2); - - /** Default ctor, takes pointer to first entry of underlying container - * and maximum capacity */ - FIFOBase(T* values, const size_t maxCapacity); - - /** - * Insert value into FIFO - * @param value - * @return - */ - ReturnValue_t insert(T value); - /** - * Retrieve item from FIFO. This removes the item from the FIFO. - * @param value - * @return - */ - ReturnValue_t retrieve(T *value); - /** - * Retrieve item from FIFO without removing it from FIFO. - * @param value - * @return - */ - ReturnValue_t peek(T * value); - /** - * Remove item from FIFO. - * @return - */ - ReturnValue_t pop(); - - bool empty(); - bool full(); - size_t size(); - - - size_t getMaxCapacity() const; - -protected: - void setData(T* data); - size_t maxCapacity = 0; - - T* values; - - size_t readIndex = 0; - size_t writeIndex = 0; - size_t currentSize = 0; - - size_t next(size_t current); -}; - -#include - -#endif /* FRAMEWORK_CONTAINER_FIFOBASE_H_ */ +#ifndef FRAMEWORK_CONTAINER_FIFOBASE_H_ +#define FRAMEWORK_CONTAINER_FIFOBASE_H_ + +#include "../returnvalues/HasReturnvaluesIF.h" +#include +#include + +template +class FIFOBase { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::FIFO_CLASS; + static const ReturnValue_t FULL = MAKE_RETURN_CODE(1); + static const ReturnValue_t EMPTY = MAKE_RETURN_CODE(2); + + /** Default ctor, takes pointer to first entry of underlying container + * and maximum capacity */ + FIFOBase(T* values, const size_t maxCapacity); + + /** + * Insert value into FIFO + * @param value + * @return + */ + ReturnValue_t insert(T value); + /** + * Retrieve item from FIFO. This removes the item from the FIFO. + * @param value + * @return + */ + ReturnValue_t retrieve(T *value); + /** + * Retrieve item from FIFO without removing it from FIFO. + * @param value + * @return + */ + ReturnValue_t peek(T * value); + /** + * Remove item from FIFO. + * @return + */ + ReturnValue_t pop(); + + bool empty(); + bool full(); + size_t size(); + + + size_t getMaxCapacity() const; + +protected: + void setData(T* data); + size_t maxCapacity = 0; + + T* values; + + size_t readIndex = 0; + size_t writeIndex = 0; + size_t currentSize = 0; + + size_t next(size_t current); +}; + +#include "../container/FIFOBase.tpp" + +#endif /* FRAMEWORK_CONTAINER_FIFOBASE_H_ */ diff --git a/container/FixedArrayList.h b/container/FixedArrayList.h index a2d2fa25..70a1d5e2 100644 --- a/container/FixedArrayList.h +++ b/container/FixedArrayList.h @@ -1,57 +1,57 @@ -#ifndef FIXEDARRAYLIST_H_ -#define FIXEDARRAYLIST_H_ - -#include - -/** - * @brief Array List with a fixed maximum size - * @ingroup container - */ -template -class FixedArrayList: public ArrayList { -private: - T data[MAX_SIZE]; -public: - /** - * (Robin) Maybe we should also implement move assignment and move ctor. - * Or at least delete them. - */ - FixedArrayList() : - ArrayList(data, MAX_SIZE) { - } - - // (Robin): We could create a constructor to initialize the fixed array list - // with data and the known size field - // so it can be used for serialization too (with SerialFixedArrrayListAdapter) - // is this feasible? - /** - * Initialize a fixed array list with data and number of data fields. - * Endianness of entries can be swapped optionally. - * @param data_ - * @param count - * @param swapArrayListEndianess - */ - FixedArrayList(T * data_, count_t count): - ArrayList(data, MAX_SIZE) { - memcpy(this->data, data_, count * sizeof(T)); - this->size = count; - } - - FixedArrayList(const FixedArrayList& other) : - ArrayList(data, MAX_SIZE) { - memcpy(this->data, other.data, sizeof(this->data)); - this->entries = data; - } - - FixedArrayList& operator=(FixedArrayList other) { - memcpy(this->data, other.data, sizeof(this->data)); - this->entries = data; - return *this; - } - - virtual ~FixedArrayList() { - } - -}; - -#endif /* FIXEDARRAYLIST_H_ */ +#ifndef FIXEDARRAYLIST_H_ +#define FIXEDARRAYLIST_H_ + +#include "../container/ArrayList.h" + +/** + * @brief Array List with a fixed maximum size + * @ingroup container + */ +template +class FixedArrayList: public ArrayList { +private: + T data[MAX_SIZE]; +public: + /** + * (Robin) Maybe we should also implement move assignment and move ctor. + * Or at least delete them. + */ + FixedArrayList() : + ArrayList(data, MAX_SIZE) { + } + + // (Robin): We could create a constructor to initialize the fixed array list + // with data and the known size field + // so it can be used for serialization too (with SerialFixedArrrayListAdapter) + // is this feasible? + /** + * Initialize a fixed array list with data and number of data fields. + * Endianness of entries can be swapped optionally. + * @param data_ + * @param count + * @param swapArrayListEndianess + */ + FixedArrayList(T * data_, count_t count): + ArrayList(data, MAX_SIZE) { + memcpy(this->data, data_, count * sizeof(T)); + this->size = count; + } + + FixedArrayList(const FixedArrayList& other) : + ArrayList(data, MAX_SIZE) { + memcpy(this->data, other.data, sizeof(this->data)); + this->entries = data; + } + + FixedArrayList& operator=(FixedArrayList other) { + memcpy(this->data, other.data, sizeof(this->data)); + this->entries = data; + return *this; + } + + virtual ~FixedArrayList() { + } + +}; + +#endif /* FIXEDARRAYLIST_H_ */ diff --git a/container/FixedMap.h b/container/FixedMap.h index 7ef4d7ae..a3afc023 100644 --- a/container/FixedMap.h +++ b/container/FixedMap.h @@ -1,225 +1,225 @@ -#ifndef FIXEDMAP_H_ -#define FIXEDMAP_H_ - -#include -#include -#include - -/** - * @brief Map implementation for maps with a pre-defined size. - * @details Can be initialized with desired maximum size. - * Iterator is used to access pair and - * iterate through map entries. Complexity O(n). - * @ingroup container - */ -template -class FixedMap: public SerializeIF { -public: - 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 MAP_FULL = MAKE_RETURN_CODE(0x02); - static const ReturnValue_t KEY_DOES_NOT_EXIST = MAKE_RETURN_CODE(0x03); - -private: - static const key_t EMPTY_SLOT = -1; - ArrayList, uint32_t> theMap; - uint32_t _size; - - uint32_t findIndex(key_t key) const { - if (_size == 0) { - return 1; - } - uint32_t i = 0; - for (i = 0; i < _size; ++i) { - if (theMap[i].first == key) { - return i; - } - } - return i; - } -public: - FixedMap(uint32_t maxSize) : - theMap(maxSize), _size(0) { - } - - class Iterator: public ArrayList, uint32_t>::Iterator { - public: - Iterator() : - ArrayList, uint32_t>::Iterator() { - } - - Iterator(std::pair *pair) : - ArrayList, uint32_t>::Iterator(pair) { - } - - T operator*() { - return ArrayList, uint32_t>::Iterator::value->second; - } - - // -> operator overloaded, can be used to access value - T *operator->() { - return &ArrayList, uint32_t>::Iterator::value->second; - } - - // Can be used to access the key of the iterator - key_t first() { - return ArrayList, uint32_t>::Iterator::value->first; - } - - // Alternative to access value, similar to std::map implementation - T second() { - return ArrayList, uint32_t>::Iterator::value->second; - } - }; - - - - Iterator begin() const { - return Iterator(&theMap[0]); - } - - Iterator end() const { - return Iterator(&theMap[_size]); - } - - uint32_t size() const { - return _size; - } - - ReturnValue_t insert(key_t key, T value, Iterator *storedValue = NULL) { - if (exists(key) == HasReturnvaluesIF::RETURN_OK) { - return FixedMap::KEY_ALREADY_EXISTS; - } - if (_size == theMap.maxSize()) { - return FixedMap::MAP_FULL; - } - theMap[_size].first = key; - theMap[_size].second = value; - if (storedValue != NULL) { - *storedValue = Iterator(&theMap[_size]); - } - ++_size; - return HasReturnvaluesIF::RETURN_OK; - } - - ReturnValue_t insert(std::pair pair) { - return insert(pair.first, pair.second); - } - - ReturnValue_t exists(key_t key) const { - ReturnValue_t result = KEY_DOES_NOT_EXIST; - if (findIndex(key) < _size) { - result = HasReturnvaluesIF::RETURN_OK; - } - return result; - } - - ReturnValue_t erase(Iterator *iter) { - uint32_t i; - if ((i = findIndex((*iter).value->first)) >= _size) { - return KEY_DOES_NOT_EXIST; - } - theMap[i] = theMap[_size - 1]; - --_size; - --((*iter).value); - return HasReturnvaluesIF::RETURN_OK; - } - - ReturnValue_t erase(key_t key) { - uint32_t i; - if ((i = findIndex(key)) >= _size) { - return KEY_DOES_NOT_EXIST; - } - theMap[i] = theMap[_size - 1]; - --_size; - return HasReturnvaluesIF::RETURN_OK; - } - - T *findValue(key_t key) const { - return &theMap[findIndex(key)].second; - } - - Iterator find(key_t key) const { - ReturnValue_t result = exists(key); - if (result != HasReturnvaluesIF::RETURN_OK) { - return end(); - } - return Iterator(&theMap[findIndex(key)]); - } - - ReturnValue_t find(key_t key, T **value) const { - ReturnValue_t result = exists(key); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - *value = &theMap[findIndex(key)].second; - return HasReturnvaluesIF::RETURN_OK; - } - - void clear() { - _size = 0; - } - - uint32_t maxSize() const { - return theMap.maxSize(); - } - - - bool full() { - if(_size == theMap.maxSize()) { - return true; - } - else { - return false; - } - } - - virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) const { - ReturnValue_t result = SerializeAdapter::serialize(&this->_size, - buffer, size, maxSize, streamEndianness); - uint32_t i = 0; - while ((result == HasReturnvaluesIF::RETURN_OK) && (i < this->_size)) { - result = SerializeAdapter::serialize(&theMap[i].first, buffer, - size, maxSize, streamEndianness); - result = SerializeAdapter::serialize(&theMap[i].second, buffer, size, - maxSize, streamEndianness); - ++i; - } - return result; - } - - virtual size_t getSerializedSize() const { - uint32_t printSize = sizeof(_size); - uint32_t i = 0; - - for (i = 0; i < _size; ++i) { - printSize += SerializeAdapter::getSerializedSize( - &theMap[i].first); - printSize += SerializeAdapter::getSerializedSize(&theMap[i].second); - } - - return printSize; - } - - virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - Endianness streamEndianness) { - ReturnValue_t result = SerializeAdapter::deSerialize(&this->_size, - buffer, size, streamEndianness); - if (this->_size > theMap.maxSize()) { - return SerializeIF::TOO_MANY_ELEMENTS; - } - uint32_t i = 0; - while ((result == HasReturnvaluesIF::RETURN_OK) && (i < this->_size)) { - result = SerializeAdapter::deSerialize(&theMap[i].first, buffer, - size, streamEndianness); - result = SerializeAdapter::deSerialize(&theMap[i].second, buffer, size, - streamEndianness); - ++i; - } - return result; - } - -}; - -#endif /* FIXEDMAP_H_ */ +#ifndef FIXEDMAP_H_ +#define FIXEDMAP_H_ + +#include "../container/ArrayList.h" +#include "../returnvalues/HasReturnvaluesIF.h" +#include + +/** + * @brief Map implementation for maps with a pre-defined size. + * @details Can be initialized with desired maximum size. + * Iterator is used to access pair and + * iterate through map entries. Complexity O(n). + * @ingroup container + */ +template +class FixedMap: public SerializeIF { +public: + 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 MAP_FULL = MAKE_RETURN_CODE(0x02); + static const ReturnValue_t KEY_DOES_NOT_EXIST = MAKE_RETURN_CODE(0x03); + +private: + static const key_t EMPTY_SLOT = -1; + ArrayList, uint32_t> theMap; + uint32_t _size; + + uint32_t findIndex(key_t key) const { + if (_size == 0) { + return 1; + } + uint32_t i = 0; + for (i = 0; i < _size; ++i) { + if (theMap[i].first == key) { + return i; + } + } + return i; + } +public: + FixedMap(uint32_t maxSize) : + theMap(maxSize), _size(0) { + } + + class Iterator: public ArrayList, uint32_t>::Iterator { + public: + Iterator() : + ArrayList, uint32_t>::Iterator() { + } + + Iterator(std::pair *pair) : + ArrayList, uint32_t>::Iterator(pair) { + } + + T operator*() { + return ArrayList, uint32_t>::Iterator::value->second; + } + + // -> operator overloaded, can be used to access value + T *operator->() { + return &ArrayList, uint32_t>::Iterator::value->second; + } + + // Can be used to access the key of the iterator + key_t first() { + return ArrayList, uint32_t>::Iterator::value->first; + } + + // Alternative to access value, similar to std::map implementation + T second() { + return ArrayList, uint32_t>::Iterator::value->second; + } + }; + + + + Iterator begin() const { + return Iterator(&theMap[0]); + } + + Iterator end() const { + return Iterator(&theMap[_size]); + } + + uint32_t size() const { + return _size; + } + + ReturnValue_t insert(key_t key, T value, Iterator *storedValue = NULL) { + if (exists(key) == HasReturnvaluesIF::RETURN_OK) { + return FixedMap::KEY_ALREADY_EXISTS; + } + if (_size == theMap.maxSize()) { + return FixedMap::MAP_FULL; + } + theMap[_size].first = key; + theMap[_size].second = value; + if (storedValue != NULL) { + *storedValue = Iterator(&theMap[_size]); + } + ++_size; + return HasReturnvaluesIF::RETURN_OK; + } + + ReturnValue_t insert(std::pair pair) { + return insert(pair.first, pair.second); + } + + ReturnValue_t exists(key_t key) const { + ReturnValue_t result = KEY_DOES_NOT_EXIST; + if (findIndex(key) < _size) { + result = HasReturnvaluesIF::RETURN_OK; + } + return result; + } + + ReturnValue_t erase(Iterator *iter) { + uint32_t i; + if ((i = findIndex((*iter).value->first)) >= _size) { + return KEY_DOES_NOT_EXIST; + } + theMap[i] = theMap[_size - 1]; + --_size; + --((*iter).value); + return HasReturnvaluesIF::RETURN_OK; + } + + ReturnValue_t erase(key_t key) { + uint32_t i; + if ((i = findIndex(key)) >= _size) { + return KEY_DOES_NOT_EXIST; + } + theMap[i] = theMap[_size - 1]; + --_size; + return HasReturnvaluesIF::RETURN_OK; + } + + T *findValue(key_t key) const { + return &theMap[findIndex(key)].second; + } + + Iterator find(key_t key) const { + ReturnValue_t result = exists(key); + if (result != HasReturnvaluesIF::RETURN_OK) { + return end(); + } + return Iterator(&theMap[findIndex(key)]); + } + + ReturnValue_t find(key_t key, T **value) const { + ReturnValue_t result = exists(key); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + *value = &theMap[findIndex(key)].second; + return HasReturnvaluesIF::RETURN_OK; + } + + void clear() { + _size = 0; + } + + uint32_t maxSize() const { + return theMap.maxSize(); + } + + + bool full() { + if(_size == theMap.maxSize()) { + return true; + } + else { + return false; + } + } + + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + size_t maxSize, Endianness streamEndianness) const { + ReturnValue_t result = SerializeAdapter::serialize(&this->_size, + buffer, size, maxSize, streamEndianness); + uint32_t i = 0; + while ((result == HasReturnvaluesIF::RETURN_OK) && (i < this->_size)) { + result = SerializeAdapter::serialize(&theMap[i].first, buffer, + size, maxSize, streamEndianness); + result = SerializeAdapter::serialize(&theMap[i].second, buffer, size, + maxSize, streamEndianness); + ++i; + } + return result; + } + + virtual size_t getSerializedSize() const { + uint32_t printSize = sizeof(_size); + uint32_t i = 0; + + for (i = 0; i < _size; ++i) { + printSize += SerializeAdapter::getSerializedSize( + &theMap[i].first); + printSize += SerializeAdapter::getSerializedSize(&theMap[i].second); + } + + return printSize; + } + + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + Endianness streamEndianness) { + ReturnValue_t result = SerializeAdapter::deSerialize(&this->_size, + buffer, size, streamEndianness); + if (this->_size > theMap.maxSize()) { + return SerializeIF::TOO_MANY_ELEMENTS; + } + uint32_t i = 0; + while ((result == HasReturnvaluesIF::RETURN_OK) && (i < this->_size)) { + result = SerializeAdapter::deSerialize(&theMap[i].first, buffer, + size, streamEndianness); + result = SerializeAdapter::deSerialize(&theMap[i].second, buffer, size, + streamEndianness); + ++i; + } + return result; + } + +}; + +#endif /* FIXEDMAP_H_ */ diff --git a/container/FixedOrderedMultimap.h b/container/FixedOrderedMultimap.h index 3dd20a74..5bc007ef 100644 --- a/container/FixedOrderedMultimap.h +++ b/container/FixedOrderedMultimap.h @@ -1,181 +1,181 @@ -#ifndef FRAMEWORK_CONTAINER_FIXEDORDEREDMULTIMAP_H_ -#define FRAMEWORK_CONTAINER_FIXEDORDEREDMULTIMAP_H_ - -#include -#include -#include -/** - * \ingroup container - */ -template> -class FixedOrderedMultimap { -public: - static const uint8_t INTERFACE_ID = CLASS_ID::FIXED_MULTIMAP; - 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 KEY_DOES_NOT_EXIST = MAKE_RETURN_CODE(0x03); - -private: - typedef KEY_COMPARE compare; - compare myComp; - ArrayList, uint32_t> theMap; - uint32_t _size; - - uint32_t findFirstIndex(key_t key, uint32_t startAt = 0) const { - if (startAt >= _size) { - return startAt + 1; - } - uint32_t i = startAt; - for (i = startAt; i < _size; ++i) { - if (theMap[i].first == key) { - return i; - } - } - return i; - } - - uint32_t findNicePlace(key_t key) const { - uint32_t i = 0; - for (i = 0; i < _size; ++i) { - if (myComp(key, theMap[i].first)) { - return i; - } - } - return i; - } - - void removeFromPosition(uint32_t position) { - if (_size <= position) { - return; - } - memmove(&theMap[position], &theMap[position + 1], - (_size - position - 1) * sizeof(std::pair)); - --_size; - } -public: - FixedOrderedMultimap(uint32_t maxSize) : - theMap(maxSize), _size(0) { - } - virtual ~FixedOrderedMultimap() { - } - - class Iterator: public ArrayList, uint32_t>::Iterator { - public: - Iterator() : - ArrayList, uint32_t>::Iterator() { - } - - Iterator(std::pair *pair) : - ArrayList, uint32_t>::Iterator(pair) { - } - - T operator*() { - return ArrayList, uint32_t>::Iterator::value->second; - } - - T *operator->() { - return &ArrayList, uint32_t>::Iterator::value->second; - } - - }; - - Iterator begin() const { - return Iterator(&theMap[0]); - } - - Iterator end() const { - return Iterator(&theMap[_size]); - } - - uint32_t size() const { - return _size; - } - - ReturnValue_t insert(key_t key, T value, Iterator *storedValue = NULL) { - if (_size == theMap.maxSize()) { - return MAP_FULL; - } - uint32_t position = findNicePlace(key); - memmove(&theMap[position + 1], &theMap[position], - (_size - position) * sizeof(std::pair)); - theMap[position].first = key; - theMap[position].second = value; - ++_size; - if (storedValue != NULL) { - *storedValue = Iterator(&theMap[position]); - } - return HasReturnvaluesIF::RETURN_OK; - } - - ReturnValue_t insert(std::pair pair) { - return insert(pair.fist, pair.second); - } - - ReturnValue_t exists(key_t key) const { - ReturnValue_t result = KEY_DOES_NOT_EXIST; - if (findFirstIndex(key) < _size) { - result = HasReturnvaluesIF::RETURN_OK; - } - return result; - } - - ReturnValue_t erase(Iterator *iter) { - uint32_t i; - if ((i = findFirstIndex((*iter).value->first)) >= _size) { - return KEY_DOES_NOT_EXIST; - } - removeFromPosition(i); - if (*iter != begin()) { - (*iter)--; - } else { - *iter = begin(); - } - return HasReturnvaluesIF::RETURN_OK; - } - - ReturnValue_t erase(key_t key) { - uint32_t i; - if ((i = findFirstIndex(key)) >= _size) { - return KEY_DOES_NOT_EXIST; - } - do { - removeFromPosition(i); - i = findFirstIndex(key, i); - } while (i < _size); - return HasReturnvaluesIF::RETURN_OK; - } - - //This is potentially unsafe -// T *findValue(key_t key) const { -// return &theMap[findFirstIndex(key)].second; -// } - - - Iterator find(key_t key) const { - ReturnValue_t result = exists(key); - if (result != HasReturnvaluesIF::RETURN_OK) { - return end(); - } - return Iterator(&theMap[findFirstIndex(key)]); - } - - ReturnValue_t find(key_t key, T **value) const { - ReturnValue_t result = exists(key); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - *value = &theMap[findFirstIndex(key)].second; - return HasReturnvaluesIF::RETURN_OK; - } - - void clear() { - _size = 0; - } - - uint32_t maxSize() const { - return theMap.maxSize(); - } - -}; - -#endif /* FRAMEWORK_CONTAINER_FIXEDORDEREDMULTIMAP_H_ */ +#ifndef FRAMEWORK_CONTAINER_FIXEDORDEREDMULTIMAP_H_ +#define FRAMEWORK_CONTAINER_FIXEDORDEREDMULTIMAP_H_ + +#include "../container/ArrayList.h" +#include +#include +/** + * \ingroup container + */ +template> +class FixedOrderedMultimap { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::FIXED_MULTIMAP; + 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 KEY_DOES_NOT_EXIST = MAKE_RETURN_CODE(0x03); + +private: + typedef KEY_COMPARE compare; + compare myComp; + ArrayList, uint32_t> theMap; + uint32_t _size; + + uint32_t findFirstIndex(key_t key, uint32_t startAt = 0) const { + if (startAt >= _size) { + return startAt + 1; + } + uint32_t i = startAt; + for (i = startAt; i < _size; ++i) { + if (theMap[i].first == key) { + return i; + } + } + return i; + } + + uint32_t findNicePlace(key_t key) const { + uint32_t i = 0; + for (i = 0; i < _size; ++i) { + if (myComp(key, theMap[i].first)) { + return i; + } + } + return i; + } + + void removeFromPosition(uint32_t position) { + if (_size <= position) { + return; + } + memmove(&theMap[position], &theMap[position + 1], + (_size - position - 1) * sizeof(std::pair)); + --_size; + } +public: + FixedOrderedMultimap(uint32_t maxSize) : + theMap(maxSize), _size(0) { + } + virtual ~FixedOrderedMultimap() { + } + + class Iterator: public ArrayList, uint32_t>::Iterator { + public: + Iterator() : + ArrayList, uint32_t>::Iterator() { + } + + Iterator(std::pair *pair) : + ArrayList, uint32_t>::Iterator(pair) { + } + + T operator*() { + return ArrayList, uint32_t>::Iterator::value->second; + } + + T *operator->() { + return &ArrayList, uint32_t>::Iterator::value->second; + } + + }; + + Iterator begin() const { + return Iterator(&theMap[0]); + } + + Iterator end() const { + return Iterator(&theMap[_size]); + } + + uint32_t size() const { + return _size; + } + + ReturnValue_t insert(key_t key, T value, Iterator *storedValue = NULL) { + if (_size == theMap.maxSize()) { + return MAP_FULL; + } + uint32_t position = findNicePlace(key); + memmove(&theMap[position + 1], &theMap[position], + (_size - position) * sizeof(std::pair)); + theMap[position].first = key; + theMap[position].second = value; + ++_size; + if (storedValue != NULL) { + *storedValue = Iterator(&theMap[position]); + } + return HasReturnvaluesIF::RETURN_OK; + } + + ReturnValue_t insert(std::pair pair) { + return insert(pair.fist, pair.second); + } + + ReturnValue_t exists(key_t key) const { + ReturnValue_t result = KEY_DOES_NOT_EXIST; + if (findFirstIndex(key) < _size) { + result = HasReturnvaluesIF::RETURN_OK; + } + return result; + } + + ReturnValue_t erase(Iterator *iter) { + uint32_t i; + if ((i = findFirstIndex((*iter).value->first)) >= _size) { + return KEY_DOES_NOT_EXIST; + } + removeFromPosition(i); + if (*iter != begin()) { + (*iter)--; + } else { + *iter = begin(); + } + return HasReturnvaluesIF::RETURN_OK; + } + + ReturnValue_t erase(key_t key) { + uint32_t i; + if ((i = findFirstIndex(key)) >= _size) { + return KEY_DOES_NOT_EXIST; + } + do { + removeFromPosition(i); + i = findFirstIndex(key, i); + } while (i < _size); + return HasReturnvaluesIF::RETURN_OK; + } + + //This is potentially unsafe +// T *findValue(key_t key) const { +// return &theMap[findFirstIndex(key)].second; +// } + + + Iterator find(key_t key) const { + ReturnValue_t result = exists(key); + if (result != HasReturnvaluesIF::RETURN_OK) { + return end(); + } + return Iterator(&theMap[findFirstIndex(key)]); + } + + ReturnValue_t find(key_t key, T **value) const { + ReturnValue_t result = exists(key); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + *value = &theMap[findFirstIndex(key)].second; + return HasReturnvaluesIF::RETURN_OK; + } + + void clear() { + _size = 0; + } + + uint32_t maxSize() const { + return theMap.maxSize(); + } + +}; + +#endif /* FRAMEWORK_CONTAINER_FIXEDORDEREDMULTIMAP_H_ */ diff --git a/container/HybridIterator.h b/container/HybridIterator.h index f2fd6b28..11881326 100644 --- a/container/HybridIterator.h +++ b/container/HybridIterator.h @@ -1,90 +1,90 @@ -#ifndef FRAMEWORK_CONTAINER_HYBRIDITERATOR_H_ -#define FRAMEWORK_CONTAINER_HYBRIDITERATOR_H_ - -#include -#include - -template -class HybridIterator: public LinkedElement::Iterator, - public ArrayList::Iterator { -public: - HybridIterator() {} - - HybridIterator(typename LinkedElement::Iterator *iter) : - LinkedElement::Iterator(*iter), value(iter->value), - linked(true) { - - } - - HybridIterator(LinkedElement *start) : - LinkedElement::Iterator(start), value(start->value), - linked(true) { - - } - - HybridIterator(typename ArrayList::Iterator start, - typename ArrayList::Iterator end) : - ArrayList::Iterator(start), value(start.value), - linked(false), end(end.value) { - if (value == this->end) { - value = NULL; - } - } - - HybridIterator(T *firstElement, T *lastElement) : - ArrayList::Iterator(firstElement), value(firstElement), - linked(false), end(++lastElement) { - if (value == end) { - value = NULL; - } - } - - HybridIterator& operator++() { - if (linked) { - LinkedElement::Iterator::operator++(); - if (LinkedElement::Iterator::value != nullptr) { - value = LinkedElement::Iterator::value->value; - } else { - value = nullptr; - } - } else { - ArrayList::Iterator::operator++(); - value = ArrayList::Iterator::value; - - if (value == end) { - value = nullptr; - } - } - return *this; - } - - HybridIterator operator++(int) { - HybridIterator tmp(*this); - operator++(); - return tmp; - } - - bool operator==(const HybridIterator& other) const { - return value == other.value; - } - - bool operator!=(const HybridIterator& other) const { - return !(*this == other); - } - - T operator*() { - return *value; - } - - T *operator->() { - return value; - } - - T* value = nullptr; - -private: - bool linked = false; - T *end = nullptr; -}; - -#endif /* FRAMEWORK_CONTAINER_HYBRIDITERATOR_H_ */ +#ifndef FRAMEWORK_CONTAINER_HYBRIDITERATOR_H_ +#define FRAMEWORK_CONTAINER_HYBRIDITERATOR_H_ + +#include "../container/ArrayList.h" +#include "../container/SinglyLinkedList.h" + +template +class HybridIterator: public LinkedElement::Iterator, + public ArrayList::Iterator { +public: + HybridIterator() {} + + HybridIterator(typename LinkedElement::Iterator *iter) : + LinkedElement::Iterator(*iter), value(iter->value), + linked(true) { + + } + + HybridIterator(LinkedElement *start) : + LinkedElement::Iterator(start), value(start->value), + linked(true) { + + } + + HybridIterator(typename ArrayList::Iterator start, + typename ArrayList::Iterator end) : + ArrayList::Iterator(start), value(start.value), + linked(false), end(end.value) { + if (value == this->end) { + value = NULL; + } + } + + HybridIterator(T *firstElement, T *lastElement) : + ArrayList::Iterator(firstElement), value(firstElement), + linked(false), end(++lastElement) { + if (value == end) { + value = NULL; + } + } + + HybridIterator& operator++() { + if (linked) { + LinkedElement::Iterator::operator++(); + if (LinkedElement::Iterator::value != nullptr) { + value = LinkedElement::Iterator::value->value; + } else { + value = nullptr; + } + } else { + ArrayList::Iterator::operator++(); + value = ArrayList::Iterator::value; + + if (value == end) { + value = nullptr; + } + } + return *this; + } + + HybridIterator operator++(int) { + HybridIterator tmp(*this); + operator++(); + return tmp; + } + + bool operator==(const HybridIterator& other) const { + return value == other.value; + } + + bool operator!=(const HybridIterator& other) const { + return !(*this == other); + } + + T operator*() { + return *value; + } + + T *operator->() { + return value; + } + + T* value = nullptr; + +private: + bool linked = false; + T *end = nullptr; +}; + +#endif /* FRAMEWORK_CONTAINER_HYBRIDITERATOR_H_ */ diff --git a/container/IndexedRingMemoryArray.h b/container/IndexedRingMemoryArray.h index d433df62..282916e1 100644 --- a/container/IndexedRingMemoryArray.h +++ b/container/IndexedRingMemoryArray.h @@ -1,721 +1,721 @@ -#ifndef FRAMEWORK_CONTAINER_INDEXEDRINGMEMORY_H_ -#define FRAMEWORK_CONTAINER_INDEXEDRINGMEMORY_H_ - -#include -#include -#include -#include -#include -#include - -/** - * Index is the Type used for the list of indices. - * - * @tparam T Type which destribes the index. Needs to be a child of SerializeIF - * to be able to make it persistent - */ -template -class Index: public SerializeIF{ - /** - * - */ - static_assert(std::is_base_of::value, - "Wrong Type for Index, Type must implement SerializeIF"); -public: - Index():blockStartAddress(0),size(0),storedPackets(0){} - - Index(uint32_t startAddress):blockStartAddress(startAddress), - size(0),storedPackets(0) { - } - - void setBlockStartAddress(uint32_t newAddress) { - this->blockStartAddress = newAddress; - } - - uint32_t getBlockStartAddress() const { - return blockStartAddress; - } - - const T* getIndexType() const { - return &indexType; - } - - T* modifyIndexType() { - return &indexType; - } - /** - * Updates the index Type. Uses = operator - * @param indexType Type to copy from - */ - void setIndexType(T* indexType) { - this->indexType = *indexType; - } - - uint32_t getSize() const { - return size; - } - - void setSize(uint32_t size) { - this->size = size; - } - - void addSize(uint32_t size){ - this->size += size; - } - - void setStoredPackets(uint32_t newStoredPackets){ - this->storedPackets = newStoredPackets; - } - - void addStoredPackets(uint32_t packets){ - this->storedPackets += packets; - } - - uint32_t getStoredPackets() const{ - return this->storedPackets; - } - - ReturnValue_t serialize(uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) const { - ReturnValue_t result = SerializeAdapter::serialize(&blockStartAddress,buffer,size,maxSize,streamEndianness); - if(result != HasReturnvaluesIF::RETURN_OK){ - return result; - } - result = indexType.serialize(buffer,size,maxSize,streamEndianness); - if(result != HasReturnvaluesIF::RETURN_OK){ - return result; - } - result = SerializeAdapter::serialize(&this->size,buffer,size,maxSize,streamEndianness); - if(result != HasReturnvaluesIF::RETURN_OK){ - return result; - } - result = SerializeAdapter::serialize(&this->storedPackets,buffer,size,maxSize,streamEndianness); - return result; - } - - ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - Endianness streamEndianness){ - ReturnValue_t result = SerializeAdapter::deSerialize(&blockStartAddress,buffer,size,streamEndianness); - if(result != HasReturnvaluesIF::RETURN_OK){ - return result; - } - result = indexType.deSerialize(buffer,size,streamEndianness); - if(result != HasReturnvaluesIF::RETURN_OK){ - return result; - } - result = SerializeAdapter::deSerialize(&this->size,buffer,size,streamEndianness); - if(result != HasReturnvaluesIF::RETURN_OK){ - return result; - } - result = SerializeAdapter::deSerialize(&this->storedPackets,buffer,size,streamEndianness); - if(result != HasReturnvaluesIF::RETURN_OK){ - return result; - } - return result; - } - - size_t getSerializedSize() const { - uint32_t size = SerializeAdapter::getSerializedSize(&blockStartAddress); - size += indexType.getSerializedSize(); - size += SerializeAdapter::getSerializedSize(&this->size); - size += SerializeAdapter::getSerializedSize(&this->storedPackets); - return size; - } - - - bool operator==(const Index& other){ - return ((blockStartAddress == other.getBlockStartAddress()) && (size==other.getSize())) && (indexType == *(other.getIndexType())); - } - -private: - uint32_t blockStartAddress; - uint32_t size; - uint32_t storedPackets; - T indexType; -}; - - -/** - * @brief Indexed Ring Memory Array is a class for a ring memory with indices. - * @details - * It assumes that the newest data comes in last - * It uses the currentWriteBlock as pointer to the current writing position - * The currentReadBlock must be set manually - * @tparam T - */ -template -class IndexedRingMemoryArray: public SerializeIF, public ArrayList, uint32_t>{ - /** - * - */ -public: - IndexedRingMemoryArray(uint32_t startAddress, uint32_t size, uint32_t bytesPerBlock, - SerializeIF* additionalInfo, bool overwriteOld): - ArrayList,uint32_t>(NULL,(uint32_t)10,(uint32_t)0),totalSize(size), - indexAddress(startAddress),currentReadSize(0),currentReadBlockSizeCached(0), - lastBlockToReadSize(0), additionalInfo(additionalInfo),overwriteOld(overwriteOld) - { - //Calculate the maximum number of indices needed for this blocksize - uint32_t maxNrOfIndices = floor(static_cast(size)/static_cast(bytesPerBlock)); - - //Calculate the Size needeed for the index itself - size_t serializedSize = 0; - if(additionalInfo!=NULL) { - serializedSize += additionalInfo->getSerializedSize(); - } - - //Size of current iterator type - Index tempIndex; - serializedSize += tempIndex.getSerializedSize(); - - //Add Size of Array - serializedSize += sizeof(uint32_t); //size of array - serializedSize += (tempIndex.getSerializedSize() * maxNrOfIndices); //size of elements - serializedSize += sizeof(uint16_t); //size of crc - - //Calculate new size after index - if(serializedSize > totalSize){ - error << "IndexedRingMemory: Store is too small for index" << std::endl; - } - uint32_t useableSize = totalSize - serializedSize; - - //Update the totalSize for calculations - totalSize = useableSize; - - //True StartAddress - uint32_t trueStartAddress = indexAddress + serializedSize; - - //Calculate True number of Blocks and reset size of true Number of Blocks - uint32_t trueNumberOfBlocks = floor(static_cast(totalSize) / static_cast(bytesPerBlock)); - - //allocate memory now - this->entries = new Index[trueNumberOfBlocks]; - this->size = trueNumberOfBlocks; - this->maxSize_ = trueNumberOfBlocks; - this->allocated = true; - - //Check trueNumberOfBlocks - if(trueNumberOfBlocks<1) { - error << "IndexedRingMemory: Invalid Number of Blocks: " << trueNumberOfBlocks; - } - - //Fill address into index - uint32_t address = trueStartAddress; - for (typename IndexedRingMemoryArray::Iterator it = this->begin();it!=this->end();++it) { - it->setBlockStartAddress(address); - it->setSize(0); - it->setStoredPackets(0); - address += bytesPerBlock; - } - - //Initialize iterators - currentWriteBlock = this->begin(); - currentReadBlock = this->begin(); - lastBlockToRead = this->begin(); - - //Check last blockSize - uint32_t lastBlockSize = (trueStartAddress + useableSize) - (this->back()->getBlockStartAddress()); - if((lastBlockSizesize > 1)){ - //remove the last Block so the second last block has more size - this->size -= 1; - debug << "IndexedRingMemory: Last Block is smaller than bytesPerBlock, removed last block" << std::endl; - } - } - - /** - * Resets the whole index, the iterators and executes the given reset function on every index type - * @param typeResetFnc static reset function which accepts a pointer to the index Type - */ - void reset(void (*typeResetFnc)(T*)){ - currentReadBlock = this->begin(); - currentWriteBlock = this->begin(); - lastBlockToRead = this->begin(); - currentReadSize = 0; - currentReadBlockSizeCached = 0; - lastBlockToReadSize = 0; - for(typename IndexedRingMemoryArray::Iterator it = this->begin();it!=this->end();++it){ - it->setSize(0); - it->setStoredPackets(0); - (*typeResetFnc)(it->modifyIndexType()); - } - } - - void resetBlock(typename IndexedRingMemoryArray::Iterator it,void (*typeResetFnc)(T*)){ - it->setSize(0); - it->setStoredPackets(0); - (*typeResetFnc)(it->modifyIndexType()); - } - - /** - * Reading - * @param it - */ - void setCurrentReadBlock(typename IndexedRingMemoryArray::Iterator it){ - currentReadBlock = it; - currentReadBlockSizeCached = it->getSize(); - } - - void resetRead(){ - currentReadBlock = this->begin(); - currentReadSize = 0; - currentReadBlockSizeCached = this->begin()->getSize(); - lastBlockToRead = currentWriteBlock; - lastBlockToReadSize = currentWriteBlock->getSize(); - } - - /** - * Sets the last block to read to this iterator. - * Can be used to dump until block x - * @param it The iterator for the last read block - */ - void setLastBlockToRead(typename IndexedRingMemoryArray::Iterator it){ - lastBlockToRead = it; - lastBlockToReadSize = it->getSize(); - } - - /** - * Set the read pointer to the first written Block, which is the first non empty block in front of the write block - * Can be the currentWriteBlock as well - */ - void readOldest(){ - resetRead(); - currentReadBlock = getNextNonEmptyBlock(); - currentReadBlockSizeCached = currentReadBlock->getSize(); - - } - - /** - * Sets the current read iterator to the next Block and resets the current read size - * The current size of the block will be cached to avoid race condition between write and read - * If the end of the ring is reached the read pointer will be set to the begin - */ - void readNext(){ - currentReadSize = 0; - if((this->size != 0) && (currentReadBlock.value ==this->back())){ - currentReadBlock = this->begin(); - }else{ - currentReadBlock++; - } - - currentReadBlockSizeCached = currentReadBlock->getSize(); - } - - /** - * Returns the address which is currently read from - * @return Address to read from - */ - uint32_t getCurrentReadAddress() const { - return getAddressOfCurrentReadBlock() + currentReadSize; - } - - /** - * Adds readSize to the current size and checks if the read has no more data - * left and advances the read block. - * @param readSize The size that was read - * @return Returns true if the read can go on - */ - bool addReadSize(uint32_t readSize) { - if(currentReadBlock == lastBlockToRead) { - //The current read block is the last to read - if((currentReadSize+readSize) return true - currentReadSize += readSize; - return true; - } - else { - //Reached end of read -> return false - currentReadSize = lastBlockToReadSize; - return false; - } - } - else { - //We are not in the last Block - if((currentReadSize + readSize)::Iterator it(currentReadBlock); - //Search if any block between this and the last block is not empty - for(;it!=lastBlockToRead;++it){ - if(it == this->end()){ - //This is the end, next block is the begin - it = this->begin(); - if(it == lastBlockToRead){ - //Break if the begin is the lastBlockToRead - break; - } - } - if(it->getSize()!=0){ - //This is a non empty block. Go on reading with this block - currentReadBlock = it; - currentReadBlockSizeCached = it->getSize(); - return true; - } - } - //reached lastBlockToRead and every block was empty, check if the last block is also empty - if(lastBlockToReadSize!=0){ - //go on with last Block - currentReadBlock = lastBlockToRead; - currentReadBlockSizeCached = lastBlockToReadSize; - return true; - } - //There is no non empty block left - return false; - } - //Size is larger than 0 - return true; - } - } - } - uint32_t getRemainigSizeOfCurrentReadBlock() const{ - if(currentReadBlock == lastBlockToRead){ - return (lastBlockToReadSize - currentReadSize); - }else{ - return (currentReadBlockSizeCached - currentReadSize); - } - } - - uint32_t getAddressOfCurrentReadBlock() const { - return currentReadBlock->getBlockStartAddress(); - } - - /** - * Gets the next non empty Block after the current write block, - * @return Returns the iterator to the block. If there is non, the current write block is returned - */ - typename IndexedRingMemoryArray::Iterator getNextNonEmptyBlock() const { - for(typename IndexedRingMemoryArray::Iterator it = getNextWrite();it!=currentWriteBlock;++it){ - if(it == this->end()){ - it = this->begin(); - if(it == currentWriteBlock){ - break; - } - } - if(it->getSize()!=0){ - return it; - } - } - return currentWriteBlock; - } - - /** - * Returns a copy of the oldest Index type - * @return Type of Index - */ - T* getOldest(){ - return (getNextNonEmptyBlock()->modifyIndexType()); - } - - - /* - * Writing - */ - uint32_t getAddressOfCurrentWriteBlock() const{ - return currentWriteBlock->getBlockStartAddress(); - } - - uint32_t getSizeOfCurrentWriteBlock() const{ - return currentWriteBlock->getSize(); - } - - uint32_t getCurrentWriteAddress() const{ - return getAddressOfCurrentWriteBlock() + getSizeOfCurrentWriteBlock(); - } - - void clearCurrentWriteBlock(){ - currentWriteBlock->setSize(0); - currentWriteBlock->setStoredPackets(0); - } - - void addCurrentWriteBlock(uint32_t size, uint32_t storedPackets){ - currentWriteBlock->addSize(size); - currentWriteBlock->addStoredPackets(storedPackets); - } - - T* modifyCurrentWriteBlockIndexType(){ - return currentWriteBlock->modifyIndexType(); - } - - void updatePreviousWriteSize(uint32_t size, uint32_t storedPackets){ - typename IndexedRingMemoryArray::Iterator it = getPreviousBlock(currentWriteBlock); - it->addSize(size); - it->addStoredPackets(storedPackets); - } - - /** - * Checks if the block has enough space for sizeToWrite - * @param sizeToWrite The data to be written in the Block - * @return Returns true if size to write is smaller the remaining size of the block - */ - bool hasCurrentWriteBlockEnoughSpace(uint32_t sizeToWrite){ - typename IndexedRingMemoryArray::Iterator next = getNextWrite(); - uint32_t addressOfNextBlock = next->getBlockStartAddress(); - uint32_t availableSize = - ( ( addressOfNextBlock + totalSize ) - - (getAddressOfCurrentWriteBlock() + getSizeOfCurrentWriteBlock())) - % totalSize; - return (sizeToWrite < availableSize); - } - - /** - * Checks if the store is full if overwrite old is false - * @return Returns true if it is writeable and false if not - */ - bool isNextBlockWritable(){ - //First check if this is the end of the list - typename IndexedRingMemoryArray::Iterator next; - next = getNextWrite(); - if((next->getSize()!=0) && (!overwriteOld)){ - return false; - } - return true; - } - - /** - * Updates current write Block Index Type - * @param infoOfNewBlock - */ - void updateCurrentBlock(T* infoOfNewBlock){ - currentWriteBlock->setIndexType(infoOfNewBlock); - } - - - /** - * Succeed to next block, returns FAILED if overwrite is false and the store is full - * @return - */ - ReturnValue_t writeNext(){ - //Check Next Block - if(!isNextBlockWritable()){ - //The Index is full and does not overwrite old - return HasReturnvaluesIF::RETURN_FAILED; - } - //Next block can be written, update Metadata - currentWriteBlock = getNextWrite(); - currentWriteBlock->setSize(0); - currentWriteBlock->setStoredPackets(0); - return HasReturnvaluesIF::RETURN_OK; - } - - /** - * Serializes the Index and calculates the CRC. - * Parameters according to HasSerializeIF - * @param buffer - * @param size - * @param maxSize - * @param streamEndianness - * @return - */ - ReturnValue_t serialize(uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) const{ - uint8_t* crcBuffer = *buffer; - uint32_t oldSize = *size; - if(additionalInfo!=NULL){ - additionalInfo->serialize(buffer,size,maxSize,streamEndianness); - } - ReturnValue_t result = currentWriteBlock->serialize(buffer,size,maxSize,streamEndianness); - if(result != HasReturnvaluesIF::RETURN_OK){ - return result; - } - result = SerializeAdapter::serialize(&this->size,buffer,size,maxSize,streamEndianness); - if(result != HasReturnvaluesIF::RETURN_OK){ - return result; - } - - uint32_t i = 0; - while ((result == HasReturnvaluesIF::RETURN_OK) && (i < this->size)) { - result = SerializeAdapter::serialize(&this->entries[i], buffer, size, - maxSize, streamEndianness); - ++i; - } - if(result != HasReturnvaluesIF::RETURN_OK){ - return result; - } - uint16_t crc = Calculate_CRC(crcBuffer,(*size-oldSize)); - result = SerializeAdapter::serialize(&crc,buffer,size,maxSize,streamEndianness); - return result; - } - - - /** - * Get the serialized Size of the index - * @return The serialized size of the index - */ - size_t getSerializedSize() const { - - size_t size = 0; - if(additionalInfo!=NULL){ - size += additionalInfo->getSerializedSize(); - } - size += currentWriteBlock->getSerializedSize(); - size += SerializeAdapter::getSerializedSize(&this->size); - size += (this->entries[0].getSerializedSize()) * this->size; - uint16_t crc = 0; - size += SerializeAdapter::getSerializedSize(&crc); - return size; - } - /** - * DeSerialize the Indexed Ring from a buffer, deSerializes the current write iterator - * CRC Has to be checked before! - * @param buffer - * @param size - * @param streamEndianness - * @return - */ - - ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - Endianness streamEndianness){ - - ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; - if(additionalInfo!=NULL){ - result = additionalInfo->deSerialize(buffer,size,streamEndianness); - } - if(result != HasReturnvaluesIF::RETURN_OK){ - return result; - } - - Index tempIndex; - result = tempIndex.deSerialize(buffer,size,streamEndianness); - if(result != HasReturnvaluesIF::RETURN_OK){ - return result; - } - uint32_t tempSize = 0; - result = SerializeAdapter::deSerialize(&tempSize,buffer,size,streamEndianness); - if(result != HasReturnvaluesIF::RETURN_OK){ - return result; - } - if(this->size != tempSize){ - return HasReturnvaluesIF::RETURN_FAILED; - } - uint32_t i = 0; - while ((result == HasReturnvaluesIF::RETURN_OK) && (i < this->size)) { - result = SerializeAdapter::deSerialize( - &this->entries[i], buffer, size, - streamEndianness); - ++i; - } - if(result != HasReturnvaluesIF::RETURN_OK){ - return result; - } - typename IndexedRingMemoryArray::Iterator cmp(&tempIndex); - for(typename IndexedRingMemoryArray::Iterator it= this->begin();it!=this->end();++it){ - if(*(cmp.value) == *(it.value)){ - currentWriteBlock = it; - return HasReturnvaluesIF::RETURN_OK; - } - } - //Reached if current write block iterator is not found - return HasReturnvaluesIF::RETURN_FAILED; - } - - uint32_t getIndexAddress() const { - return indexAddress; - } - - - /* - * Statistics - */ - uint32_t getStoredPackets() const { - uint32_t size = 0; - for(typename IndexedRingMemoryArray::Iterator it= this->begin();it!=this->end();++it){ - size += it->getStoredPackets(); - } - return size; - } - - uint32_t getTotalSize() const { - return totalSize; - } - - uint32_t getCurrentSize() const{ - uint32_t size = 0; - for(typename IndexedRingMemoryArray::Iterator it= this->begin();it!=this->end();++it){ - size += it->getSize(); - } - return size; - } - - bool isEmpty() const{ - return getCurrentSize()==0; - } - - double getPercentageFilled() const{ - uint32_t filledSize = 0; - for(typename IndexedRingMemoryArray::Iterator it= this->begin();it!=this->end();++it){ - filledSize += it->getSize(); - } - - return (double)filledSize/(double)this->totalSize; - } - - typename IndexedRingMemoryArray::Iterator getCurrentWriteBlock() const{ - return currentWriteBlock; - } - /** - * Get the next block of the currentWriteBlock. - * Returns the first one if currentWriteBlock is the last one - * @return Iterator pointing to the next block after currentWriteBlock - */ - typename IndexedRingMemoryArray::Iterator getNextWrite() const{ - typename IndexedRingMemoryArray::Iterator next(currentWriteBlock); - if((this->size != 0) && (currentWriteBlock.value == this->back())){ - next = this->begin(); - }else{ - ++next; - } - return next; - } - /** - * Get the block in front of the Iterator - * Returns the last block if it is the first block - * @param it iterator which you want the previous block from - * @return pointing to the block before it - */ - typename IndexedRingMemoryArray::Iterator getPreviousBlock(typename IndexedRingMemoryArray::Iterator it) { - if(this->begin() == it){ - typename IndexedRingMemoryArray::Iterator next((this->back())); - return next; - } - typename IndexedRingMemoryArray::Iterator next(it); - --next; - return next; - } -private: - //The total size used by the blocks (without index) - uint32_t totalSize; - - //The address of the index - const uint32_t indexAddress; - - //The iterators for writing and reading - typename IndexedRingMemoryArray::Iterator currentWriteBlock; - typename IndexedRingMemoryArray::Iterator currentReadBlock; - - //How much of the current read block is read already - uint32_t currentReadSize; - - //Cached Size of current read block - uint32_t currentReadBlockSizeCached; - - //Last block of current write (should be write block) - typename IndexedRingMemoryArray::Iterator lastBlockToRead; - //current size of last Block to read - uint32_t lastBlockToReadSize; - - //Additional Info to be serialized with the index - SerializeIF* additionalInfo; - - //Does it overwrite old blocks? - const bool overwriteOld; - -}; - -#endif /* FRAMEWORK_CONTAINER_INDEXEDRINGMEMORY_H_ */ +#ifndef FRAMEWORK_CONTAINER_INDEXEDRINGMEMORY_H_ +#define FRAMEWORK_CONTAINER_INDEXEDRINGMEMORY_H_ + +#include "../container/ArrayList.h" +#include "../globalfunctions/CRC.h" +#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../serialize/SerialArrayListAdapter.h" +#include + +/** + * Index is the Type used for the list of indices. + * + * @tparam T Type which destribes the index. Needs to be a child of SerializeIF + * to be able to make it persistent + */ +template +class Index: public SerializeIF{ + /** + * + */ + static_assert(std::is_base_of::value, + "Wrong Type for Index, Type must implement SerializeIF"); +public: + Index():blockStartAddress(0),size(0),storedPackets(0){} + + Index(uint32_t startAddress):blockStartAddress(startAddress), + size(0),storedPackets(0) { + } + + void setBlockStartAddress(uint32_t newAddress) { + this->blockStartAddress = newAddress; + } + + uint32_t getBlockStartAddress() const { + return blockStartAddress; + } + + const T* getIndexType() const { + return &indexType; + } + + T* modifyIndexType() { + return &indexType; + } + /** + * Updates the index Type. Uses = operator + * @param indexType Type to copy from + */ + void setIndexType(T* indexType) { + this->indexType = *indexType; + } + + uint32_t getSize() const { + return size; + } + + void setSize(uint32_t size) { + this->size = size; + } + + void addSize(uint32_t size){ + this->size += size; + } + + void setStoredPackets(uint32_t newStoredPackets){ + this->storedPackets = newStoredPackets; + } + + void addStoredPackets(uint32_t packets){ + this->storedPackets += packets; + } + + uint32_t getStoredPackets() const{ + return this->storedPackets; + } + + ReturnValue_t serialize(uint8_t** buffer, size_t* size, + size_t maxSize, Endianness streamEndianness) const { + ReturnValue_t result = SerializeAdapter::serialize(&blockStartAddress,buffer,size,maxSize,streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK){ + return result; + } + result = indexType.serialize(buffer,size,maxSize,streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK){ + return result; + } + result = SerializeAdapter::serialize(&this->size,buffer,size,maxSize,streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK){ + return result; + } + result = SerializeAdapter::serialize(&this->storedPackets,buffer,size,maxSize,streamEndianness); + return result; + } + + ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + Endianness streamEndianness){ + ReturnValue_t result = SerializeAdapter::deSerialize(&blockStartAddress,buffer,size,streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK){ + return result; + } + result = indexType.deSerialize(buffer,size,streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK){ + return result; + } + result = SerializeAdapter::deSerialize(&this->size,buffer,size,streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK){ + return result; + } + result = SerializeAdapter::deSerialize(&this->storedPackets,buffer,size,streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK){ + return result; + } + return result; + } + + size_t getSerializedSize() const { + uint32_t size = SerializeAdapter::getSerializedSize(&blockStartAddress); + size += indexType.getSerializedSize(); + size += SerializeAdapter::getSerializedSize(&this->size); + size += SerializeAdapter::getSerializedSize(&this->storedPackets); + return size; + } + + + bool operator==(const Index& other){ + return ((blockStartAddress == other.getBlockStartAddress()) && (size==other.getSize())) && (indexType == *(other.getIndexType())); + } + +private: + uint32_t blockStartAddress; + uint32_t size; + uint32_t storedPackets; + T indexType; +}; + + +/** + * @brief Indexed Ring Memory Array is a class for a ring memory with indices. + * @details + * It assumes that the newest data comes in last + * It uses the currentWriteBlock as pointer to the current writing position + * The currentReadBlock must be set manually + * @tparam T + */ +template +class IndexedRingMemoryArray: public SerializeIF, public ArrayList, uint32_t>{ + /** + * + */ +public: + IndexedRingMemoryArray(uint32_t startAddress, uint32_t size, uint32_t bytesPerBlock, + SerializeIF* additionalInfo, bool overwriteOld): + ArrayList,uint32_t>(NULL,(uint32_t)10,(uint32_t)0),totalSize(size), + indexAddress(startAddress),currentReadSize(0),currentReadBlockSizeCached(0), + lastBlockToReadSize(0), additionalInfo(additionalInfo),overwriteOld(overwriteOld) + { + //Calculate the maximum number of indices needed for this blocksize + uint32_t maxNrOfIndices = floor(static_cast(size)/static_cast(bytesPerBlock)); + + //Calculate the Size needeed for the index itself + size_t serializedSize = 0; + if(additionalInfo!=NULL) { + serializedSize += additionalInfo->getSerializedSize(); + } + + //Size of current iterator type + Index tempIndex; + serializedSize += tempIndex.getSerializedSize(); + + //Add Size of Array + serializedSize += sizeof(uint32_t); //size of array + serializedSize += (tempIndex.getSerializedSize() * maxNrOfIndices); //size of elements + serializedSize += sizeof(uint16_t); //size of crc + + //Calculate new size after index + if(serializedSize > totalSize){ + error << "IndexedRingMemory: Store is too small for index" << std::endl; + } + uint32_t useableSize = totalSize - serializedSize; + + //Update the totalSize for calculations + totalSize = useableSize; + + //True StartAddress + uint32_t trueStartAddress = indexAddress + serializedSize; + + //Calculate True number of Blocks and reset size of true Number of Blocks + uint32_t trueNumberOfBlocks = floor(static_cast(totalSize) / static_cast(bytesPerBlock)); + + //allocate memory now + this->entries = new Index[trueNumberOfBlocks]; + this->size = trueNumberOfBlocks; + this->maxSize_ = trueNumberOfBlocks; + this->allocated = true; + + //Check trueNumberOfBlocks + if(trueNumberOfBlocks<1) { + error << "IndexedRingMemory: Invalid Number of Blocks: " << trueNumberOfBlocks; + } + + //Fill address into index + uint32_t address = trueStartAddress; + for (typename IndexedRingMemoryArray::Iterator it = this->begin();it!=this->end();++it) { + it->setBlockStartAddress(address); + it->setSize(0); + it->setStoredPackets(0); + address += bytesPerBlock; + } + + //Initialize iterators + currentWriteBlock = this->begin(); + currentReadBlock = this->begin(); + lastBlockToRead = this->begin(); + + //Check last blockSize + uint32_t lastBlockSize = (trueStartAddress + useableSize) - (this->back()->getBlockStartAddress()); + if((lastBlockSizesize > 1)){ + //remove the last Block so the second last block has more size + this->size -= 1; + debug << "IndexedRingMemory: Last Block is smaller than bytesPerBlock, removed last block" << std::endl; + } + } + + /** + * Resets the whole index, the iterators and executes the given reset function on every index type + * @param typeResetFnc static reset function which accepts a pointer to the index Type + */ + void reset(void (*typeResetFnc)(T*)){ + currentReadBlock = this->begin(); + currentWriteBlock = this->begin(); + lastBlockToRead = this->begin(); + currentReadSize = 0; + currentReadBlockSizeCached = 0; + lastBlockToReadSize = 0; + for(typename IndexedRingMemoryArray::Iterator it = this->begin();it!=this->end();++it){ + it->setSize(0); + it->setStoredPackets(0); + (*typeResetFnc)(it->modifyIndexType()); + } + } + + void resetBlock(typename IndexedRingMemoryArray::Iterator it,void (*typeResetFnc)(T*)){ + it->setSize(0); + it->setStoredPackets(0); + (*typeResetFnc)(it->modifyIndexType()); + } + + /** + * Reading + * @param it + */ + void setCurrentReadBlock(typename IndexedRingMemoryArray::Iterator it){ + currentReadBlock = it; + currentReadBlockSizeCached = it->getSize(); + } + + void resetRead(){ + currentReadBlock = this->begin(); + currentReadSize = 0; + currentReadBlockSizeCached = this->begin()->getSize(); + lastBlockToRead = currentWriteBlock; + lastBlockToReadSize = currentWriteBlock->getSize(); + } + + /** + * Sets the last block to read to this iterator. + * Can be used to dump until block x + * @param it The iterator for the last read block + */ + void setLastBlockToRead(typename IndexedRingMemoryArray::Iterator it){ + lastBlockToRead = it; + lastBlockToReadSize = it->getSize(); + } + + /** + * Set the read pointer to the first written Block, which is the first non empty block in front of the write block + * Can be the currentWriteBlock as well + */ + void readOldest(){ + resetRead(); + currentReadBlock = getNextNonEmptyBlock(); + currentReadBlockSizeCached = currentReadBlock->getSize(); + + } + + /** + * Sets the current read iterator to the next Block and resets the current read size + * The current size of the block will be cached to avoid race condition between write and read + * If the end of the ring is reached the read pointer will be set to the begin + */ + void readNext(){ + currentReadSize = 0; + if((this->size != 0) && (currentReadBlock.value ==this->back())){ + currentReadBlock = this->begin(); + }else{ + currentReadBlock++; + } + + currentReadBlockSizeCached = currentReadBlock->getSize(); + } + + /** + * Returns the address which is currently read from + * @return Address to read from + */ + uint32_t getCurrentReadAddress() const { + return getAddressOfCurrentReadBlock() + currentReadSize; + } + + /** + * Adds readSize to the current size and checks if the read has no more data + * left and advances the read block. + * @param readSize The size that was read + * @return Returns true if the read can go on + */ + bool addReadSize(uint32_t readSize) { + if(currentReadBlock == lastBlockToRead) { + //The current read block is the last to read + if((currentReadSize+readSize) return true + currentReadSize += readSize; + return true; + } + else { + //Reached end of read -> return false + currentReadSize = lastBlockToReadSize; + return false; + } + } + else { + //We are not in the last Block + if((currentReadSize + readSize)::Iterator it(currentReadBlock); + //Search if any block between this and the last block is not empty + for(;it!=lastBlockToRead;++it){ + if(it == this->end()){ + //This is the end, next block is the begin + it = this->begin(); + if(it == lastBlockToRead){ + //Break if the begin is the lastBlockToRead + break; + } + } + if(it->getSize()!=0){ + //This is a non empty block. Go on reading with this block + currentReadBlock = it; + currentReadBlockSizeCached = it->getSize(); + return true; + } + } + //reached lastBlockToRead and every block was empty, check if the last block is also empty + if(lastBlockToReadSize!=0){ + //go on with last Block + currentReadBlock = lastBlockToRead; + currentReadBlockSizeCached = lastBlockToReadSize; + return true; + } + //There is no non empty block left + return false; + } + //Size is larger than 0 + return true; + } + } + } + uint32_t getRemainigSizeOfCurrentReadBlock() const{ + if(currentReadBlock == lastBlockToRead){ + return (lastBlockToReadSize - currentReadSize); + }else{ + return (currentReadBlockSizeCached - currentReadSize); + } + } + + uint32_t getAddressOfCurrentReadBlock() const { + return currentReadBlock->getBlockStartAddress(); + } + + /** + * Gets the next non empty Block after the current write block, + * @return Returns the iterator to the block. If there is non, the current write block is returned + */ + typename IndexedRingMemoryArray::Iterator getNextNonEmptyBlock() const { + for(typename IndexedRingMemoryArray::Iterator it = getNextWrite();it!=currentWriteBlock;++it){ + if(it == this->end()){ + it = this->begin(); + if(it == currentWriteBlock){ + break; + } + } + if(it->getSize()!=0){ + return it; + } + } + return currentWriteBlock; + } + + /** + * Returns a copy of the oldest Index type + * @return Type of Index + */ + T* getOldest(){ + return (getNextNonEmptyBlock()->modifyIndexType()); + } + + + /* + * Writing + */ + uint32_t getAddressOfCurrentWriteBlock() const{ + return currentWriteBlock->getBlockStartAddress(); + } + + uint32_t getSizeOfCurrentWriteBlock() const{ + return currentWriteBlock->getSize(); + } + + uint32_t getCurrentWriteAddress() const{ + return getAddressOfCurrentWriteBlock() + getSizeOfCurrentWriteBlock(); + } + + void clearCurrentWriteBlock(){ + currentWriteBlock->setSize(0); + currentWriteBlock->setStoredPackets(0); + } + + void addCurrentWriteBlock(uint32_t size, uint32_t storedPackets){ + currentWriteBlock->addSize(size); + currentWriteBlock->addStoredPackets(storedPackets); + } + + T* modifyCurrentWriteBlockIndexType(){ + return currentWriteBlock->modifyIndexType(); + } + + void updatePreviousWriteSize(uint32_t size, uint32_t storedPackets){ + typename IndexedRingMemoryArray::Iterator it = getPreviousBlock(currentWriteBlock); + it->addSize(size); + it->addStoredPackets(storedPackets); + } + + /** + * Checks if the block has enough space for sizeToWrite + * @param sizeToWrite The data to be written in the Block + * @return Returns true if size to write is smaller the remaining size of the block + */ + bool hasCurrentWriteBlockEnoughSpace(uint32_t sizeToWrite){ + typename IndexedRingMemoryArray::Iterator next = getNextWrite(); + uint32_t addressOfNextBlock = next->getBlockStartAddress(); + uint32_t availableSize = + ( ( addressOfNextBlock + totalSize ) - + (getAddressOfCurrentWriteBlock() + getSizeOfCurrentWriteBlock())) + % totalSize; + return (sizeToWrite < availableSize); + } + + /** + * Checks if the store is full if overwrite old is false + * @return Returns true if it is writeable and false if not + */ + bool isNextBlockWritable(){ + //First check if this is the end of the list + typename IndexedRingMemoryArray::Iterator next; + next = getNextWrite(); + if((next->getSize()!=0) && (!overwriteOld)){ + return false; + } + return true; + } + + /** + * Updates current write Block Index Type + * @param infoOfNewBlock + */ + void updateCurrentBlock(T* infoOfNewBlock){ + currentWriteBlock->setIndexType(infoOfNewBlock); + } + + + /** + * Succeed to next block, returns FAILED if overwrite is false and the store is full + * @return + */ + ReturnValue_t writeNext(){ + //Check Next Block + if(!isNextBlockWritable()){ + //The Index is full and does not overwrite old + return HasReturnvaluesIF::RETURN_FAILED; + } + //Next block can be written, update Metadata + currentWriteBlock = getNextWrite(); + currentWriteBlock->setSize(0); + currentWriteBlock->setStoredPackets(0); + return HasReturnvaluesIF::RETURN_OK; + } + + /** + * Serializes the Index and calculates the CRC. + * Parameters according to HasSerializeIF + * @param buffer + * @param size + * @param maxSize + * @param streamEndianness + * @return + */ + ReturnValue_t serialize(uint8_t** buffer, size_t* size, + size_t maxSize, Endianness streamEndianness) const{ + uint8_t* crcBuffer = *buffer; + uint32_t oldSize = *size; + if(additionalInfo!=NULL){ + additionalInfo->serialize(buffer,size,maxSize,streamEndianness); + } + ReturnValue_t result = currentWriteBlock->serialize(buffer,size,maxSize,streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK){ + return result; + } + result = SerializeAdapter::serialize(&this->size,buffer,size,maxSize,streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK){ + return result; + } + + uint32_t i = 0; + while ((result == HasReturnvaluesIF::RETURN_OK) && (i < this->size)) { + result = SerializeAdapter::serialize(&this->entries[i], buffer, size, + maxSize, streamEndianness); + ++i; + } + if(result != HasReturnvaluesIF::RETURN_OK){ + return result; + } + uint16_t crc = Calculate_CRC(crcBuffer,(*size-oldSize)); + result = SerializeAdapter::serialize(&crc,buffer,size,maxSize,streamEndianness); + return result; + } + + + /** + * Get the serialized Size of the index + * @return The serialized size of the index + */ + size_t getSerializedSize() const { + + size_t size = 0; + if(additionalInfo!=NULL){ + size += additionalInfo->getSerializedSize(); + } + size += currentWriteBlock->getSerializedSize(); + size += SerializeAdapter::getSerializedSize(&this->size); + size += (this->entries[0].getSerializedSize()) * this->size; + uint16_t crc = 0; + size += SerializeAdapter::getSerializedSize(&crc); + return size; + } + /** + * DeSerialize the Indexed Ring from a buffer, deSerializes the current write iterator + * CRC Has to be checked before! + * @param buffer + * @param size + * @param streamEndianness + * @return + */ + + ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + Endianness streamEndianness){ + + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + if(additionalInfo!=NULL){ + result = additionalInfo->deSerialize(buffer,size,streamEndianness); + } + if(result != HasReturnvaluesIF::RETURN_OK){ + return result; + } + + Index tempIndex; + result = tempIndex.deSerialize(buffer,size,streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK){ + return result; + } + uint32_t tempSize = 0; + result = SerializeAdapter::deSerialize(&tempSize,buffer,size,streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK){ + return result; + } + if(this->size != tempSize){ + return HasReturnvaluesIF::RETURN_FAILED; + } + uint32_t i = 0; + while ((result == HasReturnvaluesIF::RETURN_OK) && (i < this->size)) { + result = SerializeAdapter::deSerialize( + &this->entries[i], buffer, size, + streamEndianness); + ++i; + } + if(result != HasReturnvaluesIF::RETURN_OK){ + return result; + } + typename IndexedRingMemoryArray::Iterator cmp(&tempIndex); + for(typename IndexedRingMemoryArray::Iterator it= this->begin();it!=this->end();++it){ + if(*(cmp.value) == *(it.value)){ + currentWriteBlock = it; + return HasReturnvaluesIF::RETURN_OK; + } + } + //Reached if current write block iterator is not found + return HasReturnvaluesIF::RETURN_FAILED; + } + + uint32_t getIndexAddress() const { + return indexAddress; + } + + + /* + * Statistics + */ + uint32_t getStoredPackets() const { + uint32_t size = 0; + for(typename IndexedRingMemoryArray::Iterator it= this->begin();it!=this->end();++it){ + size += it->getStoredPackets(); + } + return size; + } + + uint32_t getTotalSize() const { + return totalSize; + } + + uint32_t getCurrentSize() const{ + uint32_t size = 0; + for(typename IndexedRingMemoryArray::Iterator it= this->begin();it!=this->end();++it){ + size += it->getSize(); + } + return size; + } + + bool isEmpty() const{ + return getCurrentSize()==0; + } + + double getPercentageFilled() const{ + uint32_t filledSize = 0; + for(typename IndexedRingMemoryArray::Iterator it= this->begin();it!=this->end();++it){ + filledSize += it->getSize(); + } + + return (double)filledSize/(double)this->totalSize; + } + + typename IndexedRingMemoryArray::Iterator getCurrentWriteBlock() const{ + return currentWriteBlock; + } + /** + * Get the next block of the currentWriteBlock. + * Returns the first one if currentWriteBlock is the last one + * @return Iterator pointing to the next block after currentWriteBlock + */ + typename IndexedRingMemoryArray::Iterator getNextWrite() const{ + typename IndexedRingMemoryArray::Iterator next(currentWriteBlock); + if((this->size != 0) && (currentWriteBlock.value == this->back())){ + next = this->begin(); + }else{ + ++next; + } + return next; + } + /** + * Get the block in front of the Iterator + * Returns the last block if it is the first block + * @param it iterator which you want the previous block from + * @return pointing to the block before it + */ + typename IndexedRingMemoryArray::Iterator getPreviousBlock(typename IndexedRingMemoryArray::Iterator it) { + if(this->begin() == it){ + typename IndexedRingMemoryArray::Iterator next((this->back())); + return next; + } + typename IndexedRingMemoryArray::Iterator next(it); + --next; + return next; + } +private: + //The total size used by the blocks (without index) + uint32_t totalSize; + + //The address of the index + const uint32_t indexAddress; + + //The iterators for writing and reading + typename IndexedRingMemoryArray::Iterator currentWriteBlock; + typename IndexedRingMemoryArray::Iterator currentReadBlock; + + //How much of the current read block is read already + uint32_t currentReadSize; + + //Cached Size of current read block + uint32_t currentReadBlockSizeCached; + + //Last block of current write (should be write block) + typename IndexedRingMemoryArray::Iterator lastBlockToRead; + //current size of last Block to read + uint32_t lastBlockToReadSize; + + //Additional Info to be serialized with the index + SerializeIF* additionalInfo; + + //Does it overwrite old blocks? + const bool overwriteOld; + +}; + +#endif /* FRAMEWORK_CONTAINER_INDEXEDRINGMEMORY_H_ */ diff --git a/container/PlacementFactory.h b/container/PlacementFactory.h index daf4ee20..4a1b7df2 100644 --- a/container/PlacementFactory.h +++ b/container/PlacementFactory.h @@ -1,35 +1,35 @@ -#ifndef FRAMEWORK_CONTAINER_PLACEMENTFACTORY_H_ -#define FRAMEWORK_CONTAINER_PLACEMENTFACTORY_H_ - -#include -#include - -class PlacementFactory { -public: - PlacementFactory(StorageManagerIF* backend) : - dataBackend(backend) { - } - template - T* generate(Args&&... args) { - store_address_t tempId; - uint8_t* pData = NULL; - ReturnValue_t result = dataBackend->getFreeElement(&tempId, sizeof(T), - &pData); - if (result != HasReturnvaluesIF::RETURN_OK) { - return NULL; - } - T* temp = new (pData) T(std::forward(args)...); - return temp; - } - template - ReturnValue_t destroy(T* thisElement) { - //Need to call destructor first, in case something was allocated by the object (shouldn't do that, however). - thisElement->~T(); - uint8_t* pointer = (uint8_t*) (thisElement); - return dataBackend->deleteData(pointer, sizeof(T)); - } -private: - StorageManagerIF* dataBackend; -}; - -#endif /* FRAMEWORK_CONTAINER_PLACEMENTFACTORY_H_ */ +#ifndef FRAMEWORK_CONTAINER_PLACEMENTFACTORY_H_ +#define FRAMEWORK_CONTAINER_PLACEMENTFACTORY_H_ + +#include "../storagemanager/StorageManagerIF.h" +#include + +class PlacementFactory { +public: + PlacementFactory(StorageManagerIF* backend) : + dataBackend(backend) { + } + template + T* generate(Args&&... args) { + store_address_t tempId; + uint8_t* pData = NULL; + ReturnValue_t result = dataBackend->getFreeElement(&tempId, sizeof(T), + &pData); + if (result != HasReturnvaluesIF::RETURN_OK) { + return NULL; + } + T* temp = new (pData) T(std::forward(args)...); + return temp; + } + template + ReturnValue_t destroy(T* thisElement) { + //Need to call destructor first, in case something was allocated by the object (shouldn't do that, however). + thisElement->~T(); + uint8_t* pointer = (uint8_t*) (thisElement); + return dataBackend->deleteData(pointer, sizeof(T)); + } +private: + StorageManagerIF* dataBackend; +}; + +#endif /* FRAMEWORK_CONTAINER_PLACEMENTFACTORY_H_ */ diff --git a/container/RingBufferBase.h b/container/RingBufferBase.h index f42a4288..b6ac20c1 100644 --- a/container/RingBufferBase.h +++ b/container/RingBufferBase.h @@ -1,113 +1,113 @@ -#ifndef FRAMEWORK_CONTAINER_RINGBUFFERBASE_H_ -#define FRAMEWORK_CONTAINER_RINGBUFFERBASE_H_ - -#include -#include - -template -class RingBufferBase { -public: - RingBufferBase(size_t startAddress, const size_t size, bool overwriteOld) : - start(startAddress), write(startAddress), size(size), - overwriteOld(overwriteOld) { - for (uint8_t count = 0; count < N_READ_PTRS; count++) { - read[count] = startAddress; - } - } - - virtual ~RingBufferBase() {} - - bool isFull(uint8_t n = 0) { - return (availableWriteSpace(n) == 0); - } - bool isEmpty(uint8_t n = 0) { - return (availableReadData(n) == 0); - } - - size_t availableReadData(uint8_t n = 0) const { - return ((write + size) - read[n]) % size; - } - size_t availableWriteSpace(uint8_t n = 0) const { - //One less to avoid ambiguous full/empty problem. - return (((read[n] + size) - write - 1) % size); - } - - bool overwritesOld() const { - return overwriteOld; - } - - size_t maxSize() const { - return size - 1; - } - - void clear() { - write = start; - for (uint8_t count = 0; count < N_READ_PTRS; count++) { - read[count] = start; - } - } - - size_t writeTillWrap() { - return (start + size) - write; - } - - size_t readTillWrap(uint8_t n = 0) { - return (start + size) - read[n]; - } - - size_t getStart() const { - return start; - } - -protected: - const size_t start; - size_t write; - size_t read[N_READ_PTRS]; - const size_t size; - const bool overwriteOld; - void incrementWrite(uint32_t amount) { - write = ((write + amount - start) % size) + start; - } - void incrementRead(uint32_t amount, uint8_t n = 0) { - read[n] = ((read[n] + amount - start) % size) + start; - } - - ReturnValue_t readData(uint32_t amount, uint8_t n = 0) { - if (availableReadData(n) >= amount) { - incrementRead(amount, n); - return HasReturnvaluesIF::RETURN_OK; - } else { - return HasReturnvaluesIF::RETURN_FAILED; - } - } - - ReturnValue_t writeData(uint32_t amount) { - if (availableWriteSpace() >= amount or overwriteOld) { - incrementWrite(amount); - return HasReturnvaluesIF::RETURN_OK; - } else { - return HasReturnvaluesIF::RETURN_FAILED; - } - } - - - size_t getRead(uint8_t n = 0) const { - return read[n]; - } - - void setRead(uint32_t read, uint8_t n = 0) { - if (read >= start && read < (start+size)) { - this->read[n] = read; - } - } - - uint32_t getWrite() const { - return write; - } - - void setWrite(uint32_t write) { - this->write = write; - } -}; - -#endif /* FRAMEWORK_CONTAINER_RINGBUFFERBASE_H_ */ +#ifndef FRAMEWORK_CONTAINER_RINGBUFFERBASE_H_ +#define FRAMEWORK_CONTAINER_RINGBUFFERBASE_H_ + +#include "../returnvalues/HasReturnvaluesIF.h" +#include + +template +class RingBufferBase { +public: + RingBufferBase(size_t startAddress, const size_t size, bool overwriteOld) : + start(startAddress), write(startAddress), size(size), + overwriteOld(overwriteOld) { + for (uint8_t count = 0; count < N_READ_PTRS; count++) { + read[count] = startAddress; + } + } + + virtual ~RingBufferBase() {} + + bool isFull(uint8_t n = 0) { + return (availableWriteSpace(n) == 0); + } + bool isEmpty(uint8_t n = 0) { + return (availableReadData(n) == 0); + } + + size_t availableReadData(uint8_t n = 0) const { + return ((write + size) - read[n]) % size; + } + size_t availableWriteSpace(uint8_t n = 0) const { + //One less to avoid ambiguous full/empty problem. + return (((read[n] + size) - write - 1) % size); + } + + bool overwritesOld() const { + return overwriteOld; + } + + size_t maxSize() const { + return size - 1; + } + + void clear() { + write = start; + for (uint8_t count = 0; count < N_READ_PTRS; count++) { + read[count] = start; + } + } + + size_t writeTillWrap() { + return (start + size) - write; + } + + size_t readTillWrap(uint8_t n = 0) { + return (start + size) - read[n]; + } + + size_t getStart() const { + return start; + } + +protected: + const size_t start; + size_t write; + size_t read[N_READ_PTRS]; + const size_t size; + const bool overwriteOld; + void incrementWrite(uint32_t amount) { + write = ((write + amount - start) % size) + start; + } + void incrementRead(uint32_t amount, uint8_t n = 0) { + read[n] = ((read[n] + amount - start) % size) + start; + } + + ReturnValue_t readData(uint32_t amount, uint8_t n = 0) { + if (availableReadData(n) >= amount) { + incrementRead(amount, n); + return HasReturnvaluesIF::RETURN_OK; + } else { + return HasReturnvaluesIF::RETURN_FAILED; + } + } + + ReturnValue_t writeData(uint32_t amount) { + if (availableWriteSpace() >= amount or overwriteOld) { + incrementWrite(amount); + return HasReturnvaluesIF::RETURN_OK; + } else { + return HasReturnvaluesIF::RETURN_FAILED; + } + } + + + size_t getRead(uint8_t n = 0) const { + return read[n]; + } + + void setRead(uint32_t read, uint8_t n = 0) { + if (read >= start && read < (start+size)) { + this->read[n] = read; + } + } + + uint32_t getWrite() const { + return write; + } + + void setWrite(uint32_t write) { + this->write = write; + } +}; + +#endif /* FRAMEWORK_CONTAINER_RINGBUFFERBASE_H_ */ diff --git a/container/SharedRingBuffer.cpp b/container/SharedRingBuffer.cpp index 001a21ed..c41e8d30 100644 --- a/container/SharedRingBuffer.cpp +++ b/container/SharedRingBuffer.cpp @@ -1,30 +1,30 @@ -#include -#include -#include - -SharedRingBuffer::SharedRingBuffer(object_id_t objectId, const size_t size, - bool overwriteOld, size_t maxExcessBytes): - SystemObject(objectId), SimpleRingBuffer(size, overwriteOld, - maxExcessBytes) { - mutex = MutexFactory::instance()->createMutex(); -} - -SharedRingBuffer::SharedRingBuffer(object_id_t objectId, uint8_t *buffer, - const size_t size, bool overwriteOld, size_t maxExcessBytes): - SystemObject(objectId), SimpleRingBuffer(buffer, size, overwriteOld, - maxExcessBytes) { - mutex = MutexFactory::instance()->createMutex(); -} - -ReturnValue_t SharedRingBuffer::lockRingBufferMutex( - MutexIF::TimeoutType timeoutType, dur_millis_t timeout) { - return mutex->lockMutex(timeoutType, timeout); -} - -ReturnValue_t SharedRingBuffer::unlockRingBufferMutex() { - return mutex->unlockMutex(); -} - -MutexIF* SharedRingBuffer::getMutexHandle() const { - return mutex; -} +#include "../container/SharedRingBuffer.h" +#include "../ipc/MutexFactory.h" +#include "../ipc/MutexHelper.h" + +SharedRingBuffer::SharedRingBuffer(object_id_t objectId, const size_t size, + bool overwriteOld, size_t maxExcessBytes): + SystemObject(objectId), SimpleRingBuffer(size, overwriteOld, + maxExcessBytes) { + mutex = MutexFactory::instance()->createMutex(); +} + +SharedRingBuffer::SharedRingBuffer(object_id_t objectId, uint8_t *buffer, + const size_t size, bool overwriteOld, size_t maxExcessBytes): + SystemObject(objectId), SimpleRingBuffer(buffer, size, overwriteOld, + maxExcessBytes) { + mutex = MutexFactory::instance()->createMutex(); +} + +ReturnValue_t SharedRingBuffer::lockRingBufferMutex( + MutexIF::TimeoutType timeoutType, dur_millis_t timeout) { + return mutex->lockMutex(timeoutType, timeout); +} + +ReturnValue_t SharedRingBuffer::unlockRingBufferMutex() { + return mutex->unlockMutex(); +} + +MutexIF* SharedRingBuffer::getMutexHandle() const { + return mutex; +} diff --git a/container/SharedRingBuffer.h b/container/SharedRingBuffer.h index 0b5be052..c6d958cc 100644 --- a/container/SharedRingBuffer.h +++ b/container/SharedRingBuffer.h @@ -1,68 +1,68 @@ -#ifndef FRAMEWORK_CONTAINER_SHAREDRINGBUFFER_H_ -#define FRAMEWORK_CONTAINER_SHAREDRINGBUFFER_H_ - -#include -#include -#include -#include - -/** - * @brief Ring buffer which can be shared among multiple objects - * @details - * This class offers a mutex to perform thread-safe operation on the ring - * buffer. It is still up to the developer to actually perform the lock - * and unlock operations. - */ -class SharedRingBuffer: public SystemObject, - public SimpleRingBuffer { -public: - /** - * This constructor allocates a new internal buffer with the supplied size. - * @param size - * @param overwriteOld - * If the ring buffer is overflowing at a write operartion, the oldest data - * will be overwritten. - */ - SharedRingBuffer(object_id_t objectId, const size_t size, - bool overwriteOld, size_t maxExcessBytes); - - /** - * This constructor takes an external buffer with the specified size. - * @param buffer - * @param size - * @param overwriteOld - * If the ring buffer is overflowing at a write operartion, the oldest data - * will be overwritten. - */ - SharedRingBuffer(object_id_t objectId, uint8_t* buffer, const size_t size, - bool overwriteOld, size_t maxExcessBytes); - - /** - * Unless a read-only constant value is read, all operations on the - * shared ring buffer should be protected by calling this function. - * @param timeoutType - * @param timeout - * @return - */ - virtual ReturnValue_t lockRingBufferMutex(MutexIF::TimeoutType timeoutType, - dur_millis_t timeout); - /** - * Any locked mutex also has to be unlocked, otherwise, access to the - * shared ring buffer will be blocked. - * @return - */ - virtual ReturnValue_t unlockRingBufferMutex(); - - /** - * The mutex handle can be accessed directly, for example to perform - * the lock with the #MutexHelper for a RAII compliant lock operation. - * @return - */ - MutexIF* getMutexHandle() const; -private: - MutexIF* mutex = nullptr; -}; - - - -#endif /* FRAMEWORK_CONTAINER_SHAREDRINGBUFFER_H_ */ +#ifndef FRAMEWORK_CONTAINER_SHAREDRINGBUFFER_H_ +#define FRAMEWORK_CONTAINER_SHAREDRINGBUFFER_H_ + +#include "../container/SimpleRingBuffer.h" +#include "../ipc/MutexIF.h" +#include "../objectmanager/SystemObject.h" +#include "../timemanager/Clock.h" + +/** + * @brief Ring buffer which can be shared among multiple objects + * @details + * This class offers a mutex to perform thread-safe operation on the ring + * buffer. It is still up to the developer to actually perform the lock + * and unlock operations. + */ +class SharedRingBuffer: public SystemObject, + public SimpleRingBuffer { +public: + /** + * This constructor allocates a new internal buffer with the supplied size. + * @param size + * @param overwriteOld + * If the ring buffer is overflowing at a write operartion, the oldest data + * will be overwritten. + */ + SharedRingBuffer(object_id_t objectId, const size_t size, + bool overwriteOld, size_t maxExcessBytes); + + /** + * This constructor takes an external buffer with the specified size. + * @param buffer + * @param size + * @param overwriteOld + * If the ring buffer is overflowing at a write operartion, the oldest data + * will be overwritten. + */ + SharedRingBuffer(object_id_t objectId, uint8_t* buffer, const size_t size, + bool overwriteOld, size_t maxExcessBytes); + + /** + * Unless a read-only constant value is read, all operations on the + * shared ring buffer should be protected by calling this function. + * @param timeoutType + * @param timeout + * @return + */ + virtual ReturnValue_t lockRingBufferMutex(MutexIF::TimeoutType timeoutType, + dur_millis_t timeout); + /** + * Any locked mutex also has to be unlocked, otherwise, access to the + * shared ring buffer will be blocked. + * @return + */ + virtual ReturnValue_t unlockRingBufferMutex(); + + /** + * The mutex handle can be accessed directly, for example to perform + * the lock with the #MutexHelper for a RAII compliant lock operation. + * @return + */ + MutexIF* getMutexHandle() const; +private: + MutexIF* mutex = nullptr; +}; + + + +#endif /* FRAMEWORK_CONTAINER_SHAREDRINGBUFFER_H_ */ diff --git a/container/SimpleRingBuffer.cpp b/container/SimpleRingBuffer.cpp index 36880813..8d817bb0 100644 --- a/container/SimpleRingBuffer.cpp +++ b/container/SimpleRingBuffer.cpp @@ -1,127 +1,127 @@ -#include -#include - -SimpleRingBuffer::SimpleRingBuffer(const size_t size, bool overwriteOld, - size_t maxExcessBytes) : - RingBufferBase<>(0, size, overwriteOld), - maxExcessBytes(maxExcessBytes) { - if(maxExcessBytes > size) { - this->maxExcessBytes = size; - } - else { - this->maxExcessBytes = maxExcessBytes; - } - buffer = new uint8_t[size + maxExcessBytes]; -} - -SimpleRingBuffer::SimpleRingBuffer(uint8_t *buffer, const size_t size, - bool overwriteOld, size_t maxExcessBytes): - RingBufferBase<>(0, size, overwriteOld), buffer(buffer) { - if(maxExcessBytes > size) { - this->maxExcessBytes = size; - } - else { - this->maxExcessBytes = maxExcessBytes; - } -} - - -SimpleRingBuffer::~SimpleRingBuffer() { - delete[] buffer; -} - - -ReturnValue_t SimpleRingBuffer::getFreeElement(uint8_t **writePointer, - size_t amount) { - if (availableWriteSpace() >= amount or overwriteOld) { - size_t amountTillWrap = writeTillWrap(); - if (amountTillWrap < amount) { - if((amount - amountTillWrap + excessBytes) > maxExcessBytes) { - return HasReturnvaluesIF::RETURN_FAILED; - } - excessBytes = amount - amountTillWrap; - } - *writePointer = &buffer[write]; - incrementWrite(amount); - return HasReturnvaluesIF::RETURN_OK; - } - else { - return HasReturnvaluesIF::RETURN_FAILED; - } -} - -ReturnValue_t SimpleRingBuffer::writeData(const uint8_t* data, - size_t amount) { - if (availableWriteSpace() >= amount or overwriteOld) { - size_t amountTillWrap = writeTillWrap(); - if (amountTillWrap >= amount) { - // remaining size in buffer is sufficient to fit full amount. - memcpy(&buffer[write], data, amount); - } - else { - memcpy(&buffer[write], data, amountTillWrap); - memcpy(buffer, data + amountTillWrap, amount - amountTillWrap); - } - incrementWrite(amount); - return HasReturnvaluesIF::RETURN_OK; - } else { - return HasReturnvaluesIF::RETURN_FAILED; - } -} - -ReturnValue_t SimpleRingBuffer::readData(uint8_t* data, size_t amount, - bool incrementReadPtr, bool readRemaining, size_t* trueAmount) { - size_t availableData = availableReadData(READ_PTR); - size_t amountTillWrap = readTillWrap(READ_PTR); - if (availableData < amount) { - if (readRemaining) { - // more data available than amount specified. - amount = availableData; - } else { - return HasReturnvaluesIF::RETURN_FAILED; - } - } - if (trueAmount != nullptr) { - *trueAmount = amount; - } - if (amountTillWrap >= amount) { - memcpy(data, &buffer[read[READ_PTR]], amount); - } else { - memcpy(data, &buffer[read[READ_PTR]], amountTillWrap); - memcpy(data + amountTillWrap, buffer, amount - amountTillWrap); - } - - if(incrementReadPtr) { - deleteData(amount, readRemaining); - } - return HasReturnvaluesIF::RETURN_OK; -} - -size_t SimpleRingBuffer::getExcessBytes() const { - return excessBytes; -} - -void SimpleRingBuffer::moveExcessBytesToStart() { - if(excessBytes > 0) { - std::memcpy(buffer, &buffer[size], excessBytes); - excessBytes = 0; - } -} - -ReturnValue_t SimpleRingBuffer::deleteData(size_t amount, - bool deleteRemaining, size_t* trueAmount) { - size_t availableData = availableReadData(READ_PTR); - if (availableData < amount) { - if (deleteRemaining) { - amount = availableData; - } else { - return HasReturnvaluesIF::RETURN_FAILED; - } - } - if (trueAmount != nullptr) { - *trueAmount = amount; - } - incrementRead(amount, READ_PTR); - return HasReturnvaluesIF::RETURN_OK; -} - +#include "../container/SimpleRingBuffer.h" +#include + +SimpleRingBuffer::SimpleRingBuffer(const size_t size, bool overwriteOld, + size_t maxExcessBytes) : + RingBufferBase<>(0, size, overwriteOld), + maxExcessBytes(maxExcessBytes) { + if(maxExcessBytes > size) { + this->maxExcessBytes = size; + } + else { + this->maxExcessBytes = maxExcessBytes; + } + buffer = new uint8_t[size + maxExcessBytes]; +} + +SimpleRingBuffer::SimpleRingBuffer(uint8_t *buffer, const size_t size, + bool overwriteOld, size_t maxExcessBytes): + RingBufferBase<>(0, size, overwriteOld), buffer(buffer) { + if(maxExcessBytes > size) { + this->maxExcessBytes = size; + } + else { + this->maxExcessBytes = maxExcessBytes; + } +} + + +SimpleRingBuffer::~SimpleRingBuffer() { + delete[] buffer; +} + + +ReturnValue_t SimpleRingBuffer::getFreeElement(uint8_t **writePointer, + size_t amount) { + if (availableWriteSpace() >= amount or overwriteOld) { + size_t amountTillWrap = writeTillWrap(); + if (amountTillWrap < amount) { + if((amount - amountTillWrap + excessBytes) > maxExcessBytes) { + return HasReturnvaluesIF::RETURN_FAILED; + } + excessBytes = amount - amountTillWrap; + } + *writePointer = &buffer[write]; + incrementWrite(amount); + return HasReturnvaluesIF::RETURN_OK; + } + else { + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +ReturnValue_t SimpleRingBuffer::writeData(const uint8_t* data, + size_t amount) { + if (availableWriteSpace() >= amount or overwriteOld) { + size_t amountTillWrap = writeTillWrap(); + if (amountTillWrap >= amount) { + // remaining size in buffer is sufficient to fit full amount. + memcpy(&buffer[write], data, amount); + } + else { + memcpy(&buffer[write], data, amountTillWrap); + memcpy(buffer, data + amountTillWrap, amount - amountTillWrap); + } + incrementWrite(amount); + return HasReturnvaluesIF::RETURN_OK; + } else { + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +ReturnValue_t SimpleRingBuffer::readData(uint8_t* data, size_t amount, + bool incrementReadPtr, bool readRemaining, size_t* trueAmount) { + size_t availableData = availableReadData(READ_PTR); + size_t amountTillWrap = readTillWrap(READ_PTR); + if (availableData < amount) { + if (readRemaining) { + // more data available than amount specified. + amount = availableData; + } else { + return HasReturnvaluesIF::RETURN_FAILED; + } + } + if (trueAmount != nullptr) { + *trueAmount = amount; + } + if (amountTillWrap >= amount) { + memcpy(data, &buffer[read[READ_PTR]], amount); + } else { + memcpy(data, &buffer[read[READ_PTR]], amountTillWrap); + memcpy(data + amountTillWrap, buffer, amount - amountTillWrap); + } + + if(incrementReadPtr) { + deleteData(amount, readRemaining); + } + return HasReturnvaluesIF::RETURN_OK; +} + +size_t SimpleRingBuffer::getExcessBytes() const { + return excessBytes; +} + +void SimpleRingBuffer::moveExcessBytesToStart() { + if(excessBytes > 0) { + std::memcpy(buffer, &buffer[size], excessBytes); + excessBytes = 0; + } +} + +ReturnValue_t SimpleRingBuffer::deleteData(size_t amount, + bool deleteRemaining, size_t* trueAmount) { + size_t availableData = availableReadData(READ_PTR); + if (availableData < amount) { + if (deleteRemaining) { + amount = availableData; + } else { + return HasReturnvaluesIF::RETURN_FAILED; + } + } + if (trueAmount != nullptr) { + *trueAmount = amount; + } + incrementRead(amount, READ_PTR); + return HasReturnvaluesIF::RETURN_OK; +} + diff --git a/container/SimpleRingBuffer.h b/container/SimpleRingBuffer.h index 0784e415..a2cb96ab 100644 --- a/container/SimpleRingBuffer.h +++ b/container/SimpleRingBuffer.h @@ -1,119 +1,119 @@ -#ifndef FRAMEWORK_CONTAINER_SIMPLERINGBUFFER_H_ -#define FRAMEWORK_CONTAINER_SIMPLERINGBUFFER_H_ - -#include -#include - -/** - * @brief Circular buffer implementation, useful for buffering - * into data streams. - * @details - * Note that the deleteData() has to be called to increment the read pointer. - * This class allocated dynamically, so - * @ingroup containers - */ -class SimpleRingBuffer: public RingBufferBase<> { -public: - /** - * This constructor allocates a new internal buffer with the supplied size. - * - * @param size - * @param overwriteOld If the ring buffer is overflowing at a write - * operation, the oldest data will be overwritten. - * @param maxExcessBytes These additional bytes will be allocated in addtion - * to the specified size to accomodate contiguous write operations - * with getFreeElement. - * - */ - SimpleRingBuffer(const size_t size, bool overwriteOld, - size_t maxExcessBytes = 0); - /** - * This constructor takes an external buffer with the specified size. - * @param buffer - * @param size - * @param overwriteOld - * If the ring buffer is overflowing at a write operartion, the oldest data - * will be overwritten. - * @param maxExcessBytes - * If the buffer can accomodate additional bytes for contigous write - * operations with getFreeElement, this is the maximum allowed additional - * size - */ - SimpleRingBuffer(uint8_t* buffer, const size_t size, bool overwriteOld, - size_t maxExcessBytes = 0); - - virtual ~SimpleRingBuffer(); - - /** - * Write to circular buffer and increment write pointer by amount. - * @param data - * @param amount - * @return -@c RETURN_OK if write operation was successfull - * -@c RETURN_FAILED if - */ - ReturnValue_t writeData(const uint8_t* data, size_t amount); - - /** - * Returns a pointer to a free element. If the remaining buffer is - * not large enough, the data will be written past the actual size - * and the amount of excess bytes will be cached. - * @param writePointer Pointer to a pointer which can be used to write - * contiguous blocks into the ring buffer - * @param amount - * @return - */ - ReturnValue_t getFreeElement(uint8_t** writePointer, size_t amount); - - virtual size_t getExcessBytes() const; - /** - * Helper functions which moves any excess bytes to the start - * of the ring buffer. - * @return - */ - virtual void moveExcessBytesToStart(); - - /** - * Read from circular buffer at read pointer. - * @param data - * @param amount - * @param incrementReadPtr - * If this is set to true, the read pointer will be incremented. - * If readRemaining is set to true, the read pointer will be incremented - * accordingly. - * @param readRemaining - * If this is set to true, the data will be read even if the amount - * specified exceeds the read data available. - * @param trueAmount [out] - * If readRemaining was set to true, the true amount read will be assigned - * to the passed value. - * @return - * - @c RETURN_OK if data was read successfully - * - @c RETURN_FAILED if not enough data was available and readRemaining - * was set to false. - */ - ReturnValue_t readData(uint8_t* data, size_t amount, - bool incrementReadPtr = false, bool readRemaining = false, - size_t* trueAmount = nullptr); - - /** - * Delete data by incrementing read pointer. - * @param amount - * @param deleteRemaining - * 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 - * @param trueAmount [out] - * If deleteRemaining was set to true, the amount deleted will be assigned - * to the passed value. - * @return - */ - ReturnValue_t deleteData(size_t amount, bool deleteRemaining = false, - size_t* trueAmount = nullptr); -private: - static const uint8_t READ_PTR = 0; - uint8_t* buffer = nullptr; - size_t maxExcessBytes; - size_t excessBytes = 0; -}; - -#endif /* FRAMEWORK_CONTAINER_SIMPLERINGBUFFER_H_ */ - +#ifndef FRAMEWORK_CONTAINER_SIMPLERINGBUFFER_H_ +#define FRAMEWORK_CONTAINER_SIMPLERINGBUFFER_H_ + +#include "../container/RingBufferBase.h" +#include + +/** + * @brief Circular buffer implementation, useful for buffering + * into data streams. + * @details + * Note that the deleteData() has to be called to increment the read pointer. + * This class allocated dynamically, so + * @ingroup containers + */ +class SimpleRingBuffer: public RingBufferBase<> { +public: + /** + * This constructor allocates a new internal buffer with the supplied size. + * + * @param size + * @param overwriteOld If the ring buffer is overflowing at a write + * operation, the oldest data will be overwritten. + * @param maxExcessBytes These additional bytes will be allocated in addtion + * to the specified size to accomodate contiguous write operations + * with getFreeElement. + * + */ + SimpleRingBuffer(const size_t size, bool overwriteOld, + size_t maxExcessBytes = 0); + /** + * This constructor takes an external buffer with the specified size. + * @param buffer + * @param size + * @param overwriteOld + * If the ring buffer is overflowing at a write operartion, the oldest data + * will be overwritten. + * @param maxExcessBytes + * If the buffer can accomodate additional bytes for contigous write + * operations with getFreeElement, this is the maximum allowed additional + * size + */ + SimpleRingBuffer(uint8_t* buffer, const size_t size, bool overwriteOld, + size_t maxExcessBytes = 0); + + virtual ~SimpleRingBuffer(); + + /** + * Write to circular buffer and increment write pointer by amount. + * @param data + * @param amount + * @return -@c RETURN_OK if write operation was successfull + * -@c RETURN_FAILED if + */ + ReturnValue_t writeData(const uint8_t* data, size_t amount); + + /** + * Returns a pointer to a free element. If the remaining buffer is + * not large enough, the data will be written past the actual size + * and the amount of excess bytes will be cached. + * @param writePointer Pointer to a pointer which can be used to write + * contiguous blocks into the ring buffer + * @param amount + * @return + */ + ReturnValue_t getFreeElement(uint8_t** writePointer, size_t amount); + + virtual size_t getExcessBytes() const; + /** + * Helper functions which moves any excess bytes to the start + * of the ring buffer. + * @return + */ + virtual void moveExcessBytesToStart(); + + /** + * Read from circular buffer at read pointer. + * @param data + * @param amount + * @param incrementReadPtr + * If this is set to true, the read pointer will be incremented. + * If readRemaining is set to true, the read pointer will be incremented + * accordingly. + * @param readRemaining + * If this is set to true, the data will be read even if the amount + * specified exceeds the read data available. + * @param trueAmount [out] + * If readRemaining was set to true, the true amount read will be assigned + * to the passed value. + * @return + * - @c RETURN_OK if data was read successfully + * - @c RETURN_FAILED if not enough data was available and readRemaining + * was set to false. + */ + ReturnValue_t readData(uint8_t* data, size_t amount, + bool incrementReadPtr = false, bool readRemaining = false, + size_t* trueAmount = nullptr); + + /** + * Delete data by incrementing read pointer. + * @param amount + * @param deleteRemaining + * 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 + * @param trueAmount [out] + * If deleteRemaining was set to true, the amount deleted will be assigned + * to the passed value. + * @return + */ + ReturnValue_t deleteData(size_t amount, bool deleteRemaining = false, + size_t* trueAmount = nullptr); +private: + static const uint8_t READ_PTR = 0; + uint8_t* buffer = nullptr; + size_t maxExcessBytes; + size_t excessBytes = 0; +}; + +#endif /* FRAMEWORK_CONTAINER_SIMPLERINGBUFFER_H_ */ + diff --git a/controller/ControllerBase.cpp b/controller/ControllerBase.cpp index 674d0fc8..4ce854dc 100644 --- a/controller/ControllerBase.cpp +++ b/controller/ControllerBase.cpp @@ -1,137 +1,137 @@ -#include -#include -#include -#include -#include - -ControllerBase::ControllerBase(uint32_t setObjectId, uint32_t parentId, - size_t commandQueueDepth) : - SystemObject(setObjectId), parentId(parentId), mode(MODE_OFF), submode( - SUBMODE_NONE), commandQueue(NULL), modeHelper( - this), healthHelper(this, setObjectId),hkSwitcher(this),executingTask(NULL) { - commandQueue = QueueFactory::instance()->createMessageQueue(commandQueueDepth); - -} - -ControllerBase::~ControllerBase() { - QueueFactory::instance()->deleteMessageQueue(commandQueue); -} - -ReturnValue_t ControllerBase::initialize() { - ReturnValue_t result = SystemObject::initialize(); - if (result != RETURN_OK) { - return result; - } - - MessageQueueId_t parentQueue = 0; - if (parentId != 0) { - SubsystemBase *parent = objectManager->get(parentId); - if (parent == NULL) { - return RETURN_FAILED; - } - parentQueue = parent->getCommandQueue(); - - parent->registerChild(getObjectId()); - } - - result = healthHelper.initialize(parentQueue); - if (result != RETURN_OK) { - return result; - } - - result = modeHelper.initialize(parentQueue); - if (result != RETURN_OK) { - return result; - } - - result = hkSwitcher.initialize(); - if (result != RETURN_OK) { - return result; - } - return RETURN_OK; -} - -MessageQueueId_t ControllerBase::getCommandQueue() const { - return commandQueue->getId(); -} - -void ControllerBase::handleQueue() { - CommandMessage command; - ReturnValue_t result; - for (result = commandQueue->receiveMessage(&command); result == RETURN_OK; - result = commandQueue->receiveMessage(&command)) { - - result = modeHelper.handleModeCommand(&command); - if (result == RETURN_OK) { - continue; - } - - result = healthHelper.handleHealthCommand(&command); - if (result == RETURN_OK) { - continue; - } - result = handleCommandMessage(&command); - if (result == RETURN_OK) { - continue; - } - command.setToUnknownCommand(); - commandQueue->reply(&command); - } - -} - -void ControllerBase::startTransition(Mode_t mode, Submode_t submode) { - changeHK(this->mode, this->submode, false); - triggerEvent(CHANGING_MODE, mode, submode); - this->mode = mode; - this->submode = submode; - modeHelper.modeChanged(mode, submode); - modeChanged(mode, submode); - announceMode(false); - changeHK(this->mode, this->submode, true); -} - -void ControllerBase::getMode(Mode_t* mode, Submode_t* submode) { - *mode = this->mode; - *submode = this->submode; -} - -void ControllerBase::setToExternalControl() { - healthHelper.setHealth(EXTERNAL_CONTROL); -} - -void ControllerBase::announceMode(bool recursive) { - triggerEvent(MODE_INFO, mode, submode); -} - -ReturnValue_t ControllerBase::performOperation(uint8_t opCode) { - handleQueue(); - hkSwitcher.performOperation(); - performControlOperation(); - return RETURN_OK; -} - -void ControllerBase::modeChanged(Mode_t mode, Submode_t submode) { - return; -} - -ReturnValue_t ControllerBase::setHealth(HealthState health) { - switch (health) { - case HEALTHY: - case EXTERNAL_CONTROL: - healthHelper.setHealth(health); - return RETURN_OK; - default: - return INVALID_HEALTH_STATE; - } -} - -HasHealthIF::HealthState ControllerBase::getHealth() { - return healthHelper.getHealth(); -} -void ControllerBase::setTaskIF(PeriodicTaskIF* task_){ - executingTask = task_; -} - -void ControllerBase::changeHK(Mode_t mode, Submode_t submode, bool enable) { -} +#include "../subsystem/SubsystemBase.h" +#include "../controller/ControllerBase.h" +#include "../subsystem/SubsystemBase.h" +#include "../ipc/QueueFactory.h" +#include "../action/HasActionsIF.h" + +ControllerBase::ControllerBase(uint32_t setObjectId, uint32_t parentId, + size_t commandQueueDepth) : + SystemObject(setObjectId), parentId(parentId), mode(MODE_OFF), submode( + SUBMODE_NONE), commandQueue(NULL), modeHelper( + this), healthHelper(this, setObjectId),hkSwitcher(this),executingTask(NULL) { + commandQueue = QueueFactory::instance()->createMessageQueue(commandQueueDepth); + +} + +ControllerBase::~ControllerBase() { + QueueFactory::instance()->deleteMessageQueue(commandQueue); +} + +ReturnValue_t ControllerBase::initialize() { + ReturnValue_t result = SystemObject::initialize(); + if (result != RETURN_OK) { + return result; + } + + MessageQueueId_t parentQueue = 0; + if (parentId != 0) { + SubsystemBase *parent = objectManager->get(parentId); + if (parent == NULL) { + return RETURN_FAILED; + } + parentQueue = parent->getCommandQueue(); + + parent->registerChild(getObjectId()); + } + + result = healthHelper.initialize(parentQueue); + if (result != RETURN_OK) { + return result; + } + + result = modeHelper.initialize(parentQueue); + if (result != RETURN_OK) { + return result; + } + + result = hkSwitcher.initialize(); + if (result != RETURN_OK) { + return result; + } + return RETURN_OK; +} + +MessageQueueId_t ControllerBase::getCommandQueue() const { + return commandQueue->getId(); +} + +void ControllerBase::handleQueue() { + CommandMessage command; + ReturnValue_t result; + for (result = commandQueue->receiveMessage(&command); result == RETURN_OK; + result = commandQueue->receiveMessage(&command)) { + + result = modeHelper.handleModeCommand(&command); + if (result == RETURN_OK) { + continue; + } + + result = healthHelper.handleHealthCommand(&command); + if (result == RETURN_OK) { + continue; + } + result = handleCommandMessage(&command); + if (result == RETURN_OK) { + continue; + } + command.setToUnknownCommand(); + commandQueue->reply(&command); + } + +} + +void ControllerBase::startTransition(Mode_t mode, Submode_t submode) { + changeHK(this->mode, this->submode, false); + triggerEvent(CHANGING_MODE, mode, submode); + this->mode = mode; + this->submode = submode; + modeHelper.modeChanged(mode, submode); + modeChanged(mode, submode); + announceMode(false); + changeHK(this->mode, this->submode, true); +} + +void ControllerBase::getMode(Mode_t* mode, Submode_t* submode) { + *mode = this->mode; + *submode = this->submode; +} + +void ControllerBase::setToExternalControl() { + healthHelper.setHealth(EXTERNAL_CONTROL); +} + +void ControllerBase::announceMode(bool recursive) { + triggerEvent(MODE_INFO, mode, submode); +} + +ReturnValue_t ControllerBase::performOperation(uint8_t opCode) { + handleQueue(); + hkSwitcher.performOperation(); + performControlOperation(); + return RETURN_OK; +} + +void ControllerBase::modeChanged(Mode_t mode, Submode_t submode) { + return; +} + +ReturnValue_t ControllerBase::setHealth(HealthState health) { + switch (health) { + case HEALTHY: + case EXTERNAL_CONTROL: + healthHelper.setHealth(health); + return RETURN_OK; + default: + return INVALID_HEALTH_STATE; + } +} + +HasHealthIF::HealthState ControllerBase::getHealth() { + return healthHelper.getHealth(); +} +void ControllerBase::setTaskIF(PeriodicTaskIF* task_){ + executingTask = task_; +} + +void ControllerBase::changeHK(Mode_t mode, Submode_t submode, bool enable) { +} diff --git a/controller/ControllerBase.h b/controller/ControllerBase.h index 804bc7c2..d98a6665 100644 --- a/controller/ControllerBase.h +++ b/controller/ControllerBase.h @@ -1,79 +1,79 @@ -#ifndef CONTROLLERBASE_H_ -#define CONTROLLERBASE_H_ - -#include -#include -#include -#include -#include -#include -#include - - -class ControllerBase: public HasModesIF, - public HasHealthIF, - public ExecutableObjectIF, - public SystemObject, - public HasReturnvaluesIF { -public: - - static const Mode_t MODE_NORMAL = 2; - - ControllerBase(uint32_t setObjectId, uint32_t parentId, - size_t commandQueueDepth = 3); - virtual ~ControllerBase(); - - ReturnValue_t initialize(); - - virtual MessageQueueId_t getCommandQueue() const; - - virtual ReturnValue_t performOperation(uint8_t opCode); - - virtual ReturnValue_t setHealth(HealthState health); - - virtual HasHealthIF::HealthState getHealth(); - - /** - * Implementation of ExecutableObjectIF function - * - * Used to setup the reference of the task, that executes this component - * @param task_ Pointer to the taskIF of this task - */ - virtual void setTaskIF(PeriodicTaskIF* task_); - - -protected: - const uint32_t parentId; - - Mode_t mode; - - Submode_t submode; - - MessageQueueIF* commandQueue; - - ModeHelper modeHelper; - - HealthHelper healthHelper; - - HkSwitchHelper hkSwitcher; - - /** - * Pointer to the task which executes this component, is invalid before setTaskIF was called. - */ - PeriodicTaskIF* executingTask; - - void handleQueue(); - - virtual ReturnValue_t handleCommandMessage(CommandMessage *message) = 0; - virtual void performControlOperation() = 0; - virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, - uint32_t *msToReachTheMode) = 0; - virtual void modeChanged(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 setToExternalControl(); - virtual void announceMode(bool recursive); - virtual void changeHK(Mode_t mode, Submode_t submode, bool enable); -}; - -#endif /* CONTROLLERBASE_H_ */ +#ifndef CONTROLLERBASE_H_ +#define CONTROLLERBASE_H_ + +#include "../health/HasHealthIF.h" +#include "../health/HealthHelper.h" +#include "../modes/HasModesIF.h" +#include "../modes/ModeHelper.h" +#include "../objectmanager/SystemObject.h" +#include "../tasks/ExecutableObjectIF.h" +#include "../datapool/HkSwitchHelper.h" + + +class ControllerBase: public HasModesIF, + public HasHealthIF, + public ExecutableObjectIF, + public SystemObject, + public HasReturnvaluesIF { +public: + + static const Mode_t MODE_NORMAL = 2; + + ControllerBase(uint32_t setObjectId, uint32_t parentId, + size_t commandQueueDepth = 3); + virtual ~ControllerBase(); + + ReturnValue_t initialize(); + + virtual MessageQueueId_t getCommandQueue() const; + + virtual ReturnValue_t performOperation(uint8_t opCode); + + virtual ReturnValue_t setHealth(HealthState health); + + virtual HasHealthIF::HealthState getHealth(); + + /** + * Implementation of ExecutableObjectIF function + * + * Used to setup the reference of the task, that executes this component + * @param task_ Pointer to the taskIF of this task + */ + virtual void setTaskIF(PeriodicTaskIF* task_); + + +protected: + const uint32_t parentId; + + Mode_t mode; + + Submode_t submode; + + MessageQueueIF* commandQueue; + + ModeHelper modeHelper; + + HealthHelper healthHelper; + + HkSwitchHelper hkSwitcher; + + /** + * Pointer to the task which executes this component, is invalid before setTaskIF was called. + */ + PeriodicTaskIF* executingTask; + + void handleQueue(); + + virtual ReturnValue_t handleCommandMessage(CommandMessage *message) = 0; + virtual void performControlOperation() = 0; + virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, + uint32_t *msToReachTheMode) = 0; + virtual void modeChanged(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 setToExternalControl(); + virtual void announceMode(bool recursive); + virtual void changeHK(Mode_t mode, Submode_t submode, bool enable); +}; + +#endif /* CONTROLLERBASE_H_ */ diff --git a/coordinates/CoordinateTransformations.cpp b/coordinates/CoordinateTransformations.cpp index b57519a3..df9b3cac 100644 --- a/coordinates/CoordinateTransformations.cpp +++ b/coordinates/CoordinateTransformations.cpp @@ -1,227 +1,227 @@ -#include -#include -#include -#include -#include -#include - - -void CoordinateTransformations::positionEcfToEci(const double* ecfPosition, - double* eciPosition, timeval *timeUTC) { - ecfToEci(ecfPosition, eciPosition, NULL, timeUTC); - -} - -void CoordinateTransformations::velocityEcfToEci(const double* ecfVelocity, - const double* ecfPosition, double* eciVelocity, timeval *timeUTC) { - ecfToEci(ecfVelocity, eciVelocity, ecfPosition, timeUTC); -} - -void CoordinateTransformations::positionEciToEcf(const double* eciCoordinates, double* ecfCoordinates,timeval *timeUTC){ - eciToEcf(eciCoordinates,ecfCoordinates,NULL,timeUTC); -}; - -void CoordinateTransformations::velocityEciToEcf(const double* eciVelocity,const double* eciPosition, double* ecfVelocity,timeval* timeUTC){ - eciToEcf(eciVelocity,ecfVelocity,eciPosition,timeUTC); -} - -double CoordinateTransformations::getEarthRotationAngle(timeval timeUTC) { - - double jD2000UTC; - Clock::convertTimevalToJD2000(timeUTC, &jD2000UTC); - - double TTt2000 = getJuleanCenturiesTT(timeUTC); - - double theta = 2 * Math::PI - * (0.779057273264 + 1.00273781191135448 * jD2000UTC); - - //Correct theta according to IAU 2000 precession-nutation model - theta = theta + 7.03270725817493E-008 + 0.0223603701 * TTt2000 - + 6.77128219501896E-006 * TTt2000 * TTt2000 - + 4.5300990362875E-010 * TTt2000 * TTt2000 * TTt2000 - + 9.12419347848147E-011 * TTt2000 * TTt2000 * TTt2000 * TTt2000; - return theta; -} - -void CoordinateTransformations::getEarthRotationMatrix(timeval timeUTC, - double matrix[][3]) { - double theta = getEarthRotationAngle(timeUTC); - - matrix[0][0] = cos(theta); - matrix[0][1] = sin(theta); - matrix[0][2] = 0; - matrix[1][0] = -sin(theta); - matrix[1][1] = cos(theta); - matrix[1][2] = 0; - matrix[2][0] = 0; - matrix[2][1] = 0; - matrix[2][2] = 1; -} - -void CoordinateTransformations::ecfToEci(const double* ecfCoordinates, - double* eciCoordinates, - const double* ecfPositionIfCoordinatesAreVelocity, timeval *timeUTCin) { - - timeval timeUTC; - if (timeUTCin != NULL) { - timeUTC = *timeUTCin; - } else { - Clock::getClock_timeval(&timeUTC); - } - - double Tfi[3][3]; - double Tif[3][3]; - getTransMatrixECITOECF(timeUTC,Tfi); - - MatrixOperations::transpose(Tfi[0], Tif[0], 3); - - MatrixOperations::multiply(Tif[0], ecfCoordinates, eciCoordinates, - 3, 3, 1); - - - - - if (ecfPositionIfCoordinatesAreVelocity != NULL) { - - double Tdotfi[3][3]; - double Tdotif[3][3]; - double Trot[3][3] = { { 0, Earth::OMEGA, 0 }, - { 0 - Earth::OMEGA, 0, 0 }, { 0, 0, 0 } }; - - MatrixOperations::multiply(Trot[0], Tfi[0], Tdotfi[0], 3, 3, - 3); - - MatrixOperations::transpose(Tdotfi[0], Tdotif[0], 3); - - double velocityCorrection[3]; - - MatrixOperations::multiply(Tdotif[0], - ecfPositionIfCoordinatesAreVelocity, velocityCorrection, 3, 3, - 1); - - VectorOperations::add(velocityCorrection, eciCoordinates, - eciCoordinates, 3); - } -} - -double CoordinateTransformations::getJuleanCenturiesTT(timeval timeUTC) { - timeval timeTT; - Clock::convertUTCToTT(timeUTC, &timeTT); - double jD2000TT; - Clock::convertTimevalToJD2000(timeTT, &jD2000TT); - - return jD2000TT / 36525.; -} - -void CoordinateTransformations::eciToEcf(const double* eciCoordinates, - double* ecfCoordinates, - const double* eciPositionIfCoordinatesAreVelocity,timeval *timeUTCin){ - timeval timeUTC; - if (timeUTCin != NULL) { - timeUTC = *timeUTCin; - }else{ - Clock::getClock_timeval(&timeUTC); - } - - double Tfi[3][3]; - - getTransMatrixECITOECF(timeUTC,Tfi); - - MatrixOperations::multiply(Tfi[0],eciCoordinates,ecfCoordinates,3,3,1); - - if (eciPositionIfCoordinatesAreVelocity != NULL) { - - double Tdotfi[3][3]; - double Trot[3][3] = { { 0, Earth::OMEGA, 0 }, - { 0 - Earth::OMEGA, 0, 0 }, { 0, 0, 0 } }; - - MatrixOperations::multiply(Trot[0], Tfi[0], Tdotfi[0], 3, 3, - 3); - - double velocityCorrection[3]; - - MatrixOperations::multiply(Tdotfi[0], - eciPositionIfCoordinatesAreVelocity, velocityCorrection, 3, 3, - 1); - - VectorOperations::add(ecfCoordinates, velocityCorrection, - ecfCoordinates, 3); - } -}; - -void CoordinateTransformations::getTransMatrixECITOECF(timeval timeUTC,double Tfi[3][3]){ - double TTt2000 = getJuleanCenturiesTT(timeUTC); - - ////////////////////////////////////////////////////////// - // Calculate Precession Matrix - - double zeta = 0.0111808609 * TTt2000 - + 1.46355554053347E-006 * TTt2000 * TTt2000 - + 8.72567663260943E-008 * TTt2000 * TTt2000 * TTt2000; - double theta_p = 0.0097171735 * TTt2000 - - 2.06845757045384E-006 * TTt2000 * TTt2000 - - 2.02812107218552E-007 * TTt2000 * TTt2000 * TTt2000; - double z = zeta + 3.8436028638364E-006 * TTt2000 * TTt2000 - + 0.000000001 * TTt2000 * TTt2000 * TTt2000; - - double mPrecession[3][3]; - - mPrecession[0][0] = -sin(z) * sin(zeta) + cos(z) * cos(theta_p) * cos(zeta); - mPrecession[1][0] = cos(z) * sin(zeta) + sin(z) * cos(theta_p) * cos(zeta); - mPrecession[2][0] = sin(theta_p) * cos(zeta); - - mPrecession[0][1] = -sin(z) * cos(zeta) - cos(z) * cos(theta_p) * sin(zeta); - mPrecession[1][1] = cos(z) * cos(zeta) - sin(z) * cos(theta_p) * sin(zeta); - mPrecession[2][1] = -sin(theta_p) * sin(zeta); - - mPrecession[0][2] = -cos(z) * sin(theta_p); - mPrecession[1][2] = -sin(z) * sin(theta_p); - mPrecession[2][2] = cos(theta_p); - - ////////////////////////////////////////////////////////// - // Calculate Nutation Matrix - - double omega_moon = 2.1824386244 - 33.7570459338 * TTt2000 - + 3.61428599267159E-005 * TTt2000 * TTt2000 - + 3.87850944887629E-008 * TTt2000 * TTt2000 * TTt2000; - - double deltaPsi = -0.000083388 * sin(omega_moon); - double deltaEpsilon = 4.46174030725106E-005 * cos(omega_moon); - - double epsilon = 0.4090928042 - 0.0002269655 * TTt2000 - - 2.86040071854626E-009 * TTt2000 * TTt2000 - + 8.78967203851589E-009 * TTt2000 * TTt2000 * TTt2000; - - - double mNutation[3][3]; - - mNutation[0][0] = cos(deltaPsi); - mNutation[1][0] = cos(epsilon + deltaEpsilon) * sin(deltaPsi); - mNutation[2][0] = sin(epsilon + deltaEpsilon) * sin(deltaPsi); - - mNutation[0][1] = -cos(epsilon) * sin(deltaPsi); - mNutation[1][1] = cos(epsilon) * cos(epsilon + deltaEpsilon) * cos(deltaPsi) - + sin(epsilon) * sin(epsilon + deltaEpsilon); - mNutation[2][1] = cos(epsilon) * sin(epsilon + deltaEpsilon) * cos(deltaPsi) - - sin(epsilon) * cos(epsilon + deltaEpsilon); - - mNutation[0][2] = -sin(epsilon) * sin(deltaPsi); - mNutation[1][2] = sin(epsilon) * cos(epsilon + deltaEpsilon) * cos(deltaPsi) - - cos(epsilon) * sin(epsilon + deltaEpsilon); - mNutation[2][2] = sin(epsilon) * sin(epsilon + deltaEpsilon) * cos(deltaPsi) - + cos(epsilon) * cos(epsilon + deltaEpsilon); - - ////////////////////////////////////////////////////////// - // Calculate Earth rotation matrix - //calculate theta - - double mTheta[3][3]; - double Ttemp[3][3]; - getEarthRotationMatrix(timeUTC, mTheta); - - //polar motion is neglected - MatrixOperations::multiply(mNutation[0], mPrecession[0], Ttemp[0], - 3, 3, 3); - - MatrixOperations::multiply(mTheta[0], Ttemp[0], Tfi[0], 3, 3, 3); -}; +#include "../coordinates/CoordinateTransformations.h" +#include "../globalfunctions/constants.h" +#include "../globalfunctions/math/MatrixOperations.h" +#include "../globalfunctions/math/VectorOperations.h" +#include +#include + + +void CoordinateTransformations::positionEcfToEci(const double* ecfPosition, + double* eciPosition, timeval *timeUTC) { + ecfToEci(ecfPosition, eciPosition, NULL, timeUTC); + +} + +void CoordinateTransformations::velocityEcfToEci(const double* ecfVelocity, + const double* ecfPosition, double* eciVelocity, timeval *timeUTC) { + ecfToEci(ecfVelocity, eciVelocity, ecfPosition, timeUTC); +} + +void CoordinateTransformations::positionEciToEcf(const double* eciCoordinates, double* ecfCoordinates,timeval *timeUTC){ + eciToEcf(eciCoordinates,ecfCoordinates,NULL,timeUTC); +}; + +void CoordinateTransformations::velocityEciToEcf(const double* eciVelocity,const double* eciPosition, double* ecfVelocity,timeval* timeUTC){ + eciToEcf(eciVelocity,ecfVelocity,eciPosition,timeUTC); +} + +double CoordinateTransformations::getEarthRotationAngle(timeval timeUTC) { + + double jD2000UTC; + Clock::convertTimevalToJD2000(timeUTC, &jD2000UTC); + + double TTt2000 = getJuleanCenturiesTT(timeUTC); + + double theta = 2 * Math::PI + * (0.779057273264 + 1.00273781191135448 * jD2000UTC); + + //Correct theta according to IAU 2000 precession-nutation model + theta = theta + 7.03270725817493E-008 + 0.0223603701 * TTt2000 + + 6.77128219501896E-006 * TTt2000 * TTt2000 + + 4.5300990362875E-010 * TTt2000 * TTt2000 * TTt2000 + + 9.12419347848147E-011 * TTt2000 * TTt2000 * TTt2000 * TTt2000; + return theta; +} + +void CoordinateTransformations::getEarthRotationMatrix(timeval timeUTC, + double matrix[][3]) { + double theta = getEarthRotationAngle(timeUTC); + + matrix[0][0] = cos(theta); + matrix[0][1] = sin(theta); + matrix[0][2] = 0; + matrix[1][0] = -sin(theta); + matrix[1][1] = cos(theta); + matrix[1][2] = 0; + matrix[2][0] = 0; + matrix[2][1] = 0; + matrix[2][2] = 1; +} + +void CoordinateTransformations::ecfToEci(const double* ecfCoordinates, + double* eciCoordinates, + const double* ecfPositionIfCoordinatesAreVelocity, timeval *timeUTCin) { + + timeval timeUTC; + if (timeUTCin != NULL) { + timeUTC = *timeUTCin; + } else { + Clock::getClock_timeval(&timeUTC); + } + + double Tfi[3][3]; + double Tif[3][3]; + getTransMatrixECITOECF(timeUTC,Tfi); + + MatrixOperations::transpose(Tfi[0], Tif[0], 3); + + MatrixOperations::multiply(Tif[0], ecfCoordinates, eciCoordinates, + 3, 3, 1); + + + + + if (ecfPositionIfCoordinatesAreVelocity != NULL) { + + double Tdotfi[3][3]; + double Tdotif[3][3]; + double Trot[3][3] = { { 0, Earth::OMEGA, 0 }, + { 0 - Earth::OMEGA, 0, 0 }, { 0, 0, 0 } }; + + MatrixOperations::multiply(Trot[0], Tfi[0], Tdotfi[0], 3, 3, + 3); + + MatrixOperations::transpose(Tdotfi[0], Tdotif[0], 3); + + double velocityCorrection[3]; + + MatrixOperations::multiply(Tdotif[0], + ecfPositionIfCoordinatesAreVelocity, velocityCorrection, 3, 3, + 1); + + VectorOperations::add(velocityCorrection, eciCoordinates, + eciCoordinates, 3); + } +} + +double CoordinateTransformations::getJuleanCenturiesTT(timeval timeUTC) { + timeval timeTT; + Clock::convertUTCToTT(timeUTC, &timeTT); + double jD2000TT; + Clock::convertTimevalToJD2000(timeTT, &jD2000TT); + + return jD2000TT / 36525.; +} + +void CoordinateTransformations::eciToEcf(const double* eciCoordinates, + double* ecfCoordinates, + const double* eciPositionIfCoordinatesAreVelocity,timeval *timeUTCin){ + timeval timeUTC; + if (timeUTCin != NULL) { + timeUTC = *timeUTCin; + }else{ + Clock::getClock_timeval(&timeUTC); + } + + double Tfi[3][3]; + + getTransMatrixECITOECF(timeUTC,Tfi); + + MatrixOperations::multiply(Tfi[0],eciCoordinates,ecfCoordinates,3,3,1); + + if (eciPositionIfCoordinatesAreVelocity != NULL) { + + double Tdotfi[3][3]; + double Trot[3][3] = { { 0, Earth::OMEGA, 0 }, + { 0 - Earth::OMEGA, 0, 0 }, { 0, 0, 0 } }; + + MatrixOperations::multiply(Trot[0], Tfi[0], Tdotfi[0], 3, 3, + 3); + + double velocityCorrection[3]; + + MatrixOperations::multiply(Tdotfi[0], + eciPositionIfCoordinatesAreVelocity, velocityCorrection, 3, 3, + 1); + + VectorOperations::add(ecfCoordinates, velocityCorrection, + ecfCoordinates, 3); + } +}; + +void CoordinateTransformations::getTransMatrixECITOECF(timeval timeUTC,double Tfi[3][3]){ + double TTt2000 = getJuleanCenturiesTT(timeUTC); + + ////////////////////////////////////////////////////////// + // Calculate Precession Matrix + + double zeta = 0.0111808609 * TTt2000 + + 1.46355554053347E-006 * TTt2000 * TTt2000 + + 8.72567663260943E-008 * TTt2000 * TTt2000 * TTt2000; + double theta_p = 0.0097171735 * TTt2000 + - 2.06845757045384E-006 * TTt2000 * TTt2000 + - 2.02812107218552E-007 * TTt2000 * TTt2000 * TTt2000; + double z = zeta + 3.8436028638364E-006 * TTt2000 * TTt2000 + + 0.000000001 * TTt2000 * TTt2000 * TTt2000; + + double mPrecession[3][3]; + + mPrecession[0][0] = -sin(z) * sin(zeta) + cos(z) * cos(theta_p) * cos(zeta); + mPrecession[1][0] = cos(z) * sin(zeta) + sin(z) * cos(theta_p) * cos(zeta); + mPrecession[2][0] = sin(theta_p) * cos(zeta); + + mPrecession[0][1] = -sin(z) * cos(zeta) - cos(z) * cos(theta_p) * sin(zeta); + mPrecession[1][1] = cos(z) * cos(zeta) - sin(z) * cos(theta_p) * sin(zeta); + mPrecession[2][1] = -sin(theta_p) * sin(zeta); + + mPrecession[0][2] = -cos(z) * sin(theta_p); + mPrecession[1][2] = -sin(z) * sin(theta_p); + mPrecession[2][2] = cos(theta_p); + + ////////////////////////////////////////////////////////// + // Calculate Nutation Matrix + + double omega_moon = 2.1824386244 - 33.7570459338 * TTt2000 + + 3.61428599267159E-005 * TTt2000 * TTt2000 + + 3.87850944887629E-008 * TTt2000 * TTt2000 * TTt2000; + + double deltaPsi = -0.000083388 * sin(omega_moon); + double deltaEpsilon = 4.46174030725106E-005 * cos(omega_moon); + + double epsilon = 0.4090928042 - 0.0002269655 * TTt2000 + - 2.86040071854626E-009 * TTt2000 * TTt2000 + + 8.78967203851589E-009 * TTt2000 * TTt2000 * TTt2000; + + + double mNutation[3][3]; + + mNutation[0][0] = cos(deltaPsi); + mNutation[1][0] = cos(epsilon + deltaEpsilon) * sin(deltaPsi); + mNutation[2][0] = sin(epsilon + deltaEpsilon) * sin(deltaPsi); + + mNutation[0][1] = -cos(epsilon) * sin(deltaPsi); + mNutation[1][1] = cos(epsilon) * cos(epsilon + deltaEpsilon) * cos(deltaPsi) + + sin(epsilon) * sin(epsilon + deltaEpsilon); + mNutation[2][1] = cos(epsilon) * sin(epsilon + deltaEpsilon) * cos(deltaPsi) + - sin(epsilon) * cos(epsilon + deltaEpsilon); + + mNutation[0][2] = -sin(epsilon) * sin(deltaPsi); + mNutation[1][2] = sin(epsilon) * cos(epsilon + deltaEpsilon) * cos(deltaPsi) + - cos(epsilon) * sin(epsilon + deltaEpsilon); + mNutation[2][2] = sin(epsilon) * sin(epsilon + deltaEpsilon) * cos(deltaPsi) + + cos(epsilon) * cos(epsilon + deltaEpsilon); + + ////////////////////////////////////////////////////////// + // Calculate Earth rotation matrix + //calculate theta + + double mTheta[3][3]; + double Ttemp[3][3]; + getEarthRotationMatrix(timeUTC, mTheta); + + //polar motion is neglected + MatrixOperations::multiply(mNutation[0], mPrecession[0], Ttemp[0], + 3, 3, 3); + + MatrixOperations::multiply(mTheta[0], Ttemp[0], Tfi[0], 3, 3, 3); +}; diff --git a/coordinates/CoordinateTransformations.h b/coordinates/CoordinateTransformations.h index b072271f..0bfb203d 100644 --- a/coordinates/CoordinateTransformations.h +++ b/coordinates/CoordinateTransformations.h @@ -1,34 +1,34 @@ -#ifndef COORDINATETRANSFORMATIONS_H_ -#define COORDINATETRANSFORMATIONS_H_ - -#include -#include - -class CoordinateTransformations { -public: - static void positionEcfToEci(const double* ecfCoordinates, double* eciCoordinates, timeval *timeUTC = NULL); - - static void velocityEcfToEci(const double* ecfVelocity, - const double* ecfPosition, - double* eciVelocity, timeval *timeUTC = NULL); - - static void positionEciToEcf(const double* eciCoordinates, double* ecfCoordinates,timeval *timeUTC = NULL); - static void velocityEciToEcf(const double* eciVelocity,const double* eciPosition, double* ecfVelocity,timeval* timeUTC = NULL); - - static double getEarthRotationAngle(timeval timeUTC); - - static void getEarthRotationMatrix(timeval timeUTC, double matrix[][3]); -private: - CoordinateTransformations(); - static void ecfToEci(const double* ecfCoordinates, double* eciCoordinates, - const double* ecfPositionIfCoordinatesAreVelocity, timeval *timeUTCin); - static void eciToEcf(const double* eciCoordinates, - double* ecfCoordinates, - const double* eciPositionIfCoordinatesAreVelocity,timeval *timeUTCin); - - static double getJuleanCenturiesTT(timeval timeUTC); - static void getTransMatrixECITOECF(timeval time,double Tfi[3][3]); - -}; - -#endif /* COORDINATETRANSFORMATIONS_H_ */ +#ifndef COORDINATETRANSFORMATIONS_H_ +#define COORDINATETRANSFORMATIONS_H_ + +#include "../timemanager/Clock.h" +#include + +class CoordinateTransformations { +public: + static void positionEcfToEci(const double* ecfCoordinates, double* eciCoordinates, timeval *timeUTC = NULL); + + static void velocityEcfToEci(const double* ecfVelocity, + const double* ecfPosition, + double* eciVelocity, timeval *timeUTC = NULL); + + static void positionEciToEcf(const double* eciCoordinates, double* ecfCoordinates,timeval *timeUTC = NULL); + static void velocityEciToEcf(const double* eciVelocity,const double* eciPosition, double* ecfVelocity,timeval* timeUTC = NULL); + + static double getEarthRotationAngle(timeval timeUTC); + + static void getEarthRotationMatrix(timeval timeUTC, double matrix[][3]); +private: + CoordinateTransformations(); + static void ecfToEci(const double* ecfCoordinates, double* eciCoordinates, + const double* ecfPositionIfCoordinatesAreVelocity, timeval *timeUTCin); + static void eciToEcf(const double* eciCoordinates, + double* ecfCoordinates, + const double* eciPositionIfCoordinatesAreVelocity,timeval *timeUTCin); + + static double getJuleanCenturiesTT(timeval timeUTC); + static void getTransMatrixECITOECF(timeval time,double Tfi[3][3]); + +}; + +#endif /* COORDINATETRANSFORMATIONS_H_ */ diff --git a/coordinates/Jgm3Model.h b/coordinates/Jgm3Model.h index 8f0598f8..fd74741d 100644 --- a/coordinates/Jgm3Model.h +++ b/coordinates/Jgm3Model.h @@ -1,180 +1,180 @@ -#ifndef FRAMEWORK_COORDINATES_JGM3MODEL_H_ -#define FRAMEWORK_COORDINATES_JGM3MODEL_H_ - -#include -#include -#include -#include -#include -#include - - -template -class Jgm3Model { -public: - static const uint32_t factorialLookupTable[DEGREE+3]; //This table is used instead of factorial calculation, must be increased if order or degree is higher - - Jgm3Model() { - y0[0] = 0; - y0[1] = 0; - y0[2] = 0; - y0[3] = 0; - y0[4] = 0; - y0[5] = 0; - - lastExecutionTime.tv_sec = 0; - lastExecutionTime.tv_usec = 0; - } - virtual ~Jgm3Model(){}; - - //double acsNavOrbit(double posECF[3],double velECF[3],timeval gpsTime); - - double y0[6]; //position and velocity at beginning of RK step in EC - timeval lastExecutionTime; //Time of last execution - - - void accelDegOrd(const double pos[3],const double S[ORDER+1][DEGREE+1],const double C[ORDER+1][DEGREE+1],double* accel){ - //Get radius of this position - double r = VectorOperations::norm(pos,3); - - - - //Initialize the V and W matrix - double V[DEGREE+2][ORDER+2] = {{0}}; - double W[DEGREE+2][ORDER+2] = {{0}}; - - for(uint8_t m=0;m<(ORDER+2);m++){ - for(uint8_t n=m;n<(DEGREE+2);n++){ - if((n==0) && (m==0)){ - //Montenbruck "Satellite Orbits Eq.3.31" - V[0][0] = Earth::MEAN_RADIUS / r; - W[0][0] = 0; - }else{ - if(n==m){ - //Montenbruck "Satellite Orbits Eq.3.29" - V[m][m] = (2*m-1)* (pos[0]*Earth::MEAN_RADIUS/pow(r,2)*V[m-1][m-1] - pos[1]*Earth::MEAN_RADIUS/pow(r,2)*W[m-1][m-1]); - W[m][m] = (2*m-1)* (pos[0]*Earth::MEAN_RADIUS/pow(r,2)*W[m-1][m-1] + pos[1]*Earth::MEAN_RADIUS/pow(r,2)*V[m-1][m-1]); - }else{ - //Montenbruck "Satellite Orbits Eq.3.30" - V[n][m] = ((2*n-1)/(double)(n-m))*pos[2]*Earth::MEAN_RADIUS / pow(r,2)*V[n-1][m]; - W[n][m] = ((2*n-1)/(double)(n-m))*pos[2]*Earth::MEAN_RADIUS / pow(r,2)*W[n-1][m]; - if(n!=(m+1)){ - V[n][m] = V[n][m] - (((n+m-1)/(double)(n-m)) * (pow(Earth::MEAN_RADIUS,2) / pow(r,2)) * V[n-2][m]); - W[n][m] = W[n][m] - (((n+m-1)/(double)(n-m)) * (pow(Earth::MEAN_RADIUS,2) / pow(r,2)) * W[n-2][m]); - }//End of if(n!=(m+1)) - }//End of if(n==m){ - }//End of if(n==0 and m==0) - }//End of for(uint8_t n=0;n<(DEGREE+1);n++) - }//End of for(uint8_t m=0;m<(ORDER+1);m++) - - - //overwrite accel if not properly initialized - accel[0] = 0; - accel[1] = 0; - accel[2] = 0; - - for(uint8_t m=0;m<(ORDER+1);m++){ - for(uint8_t n=m;n<(DEGREE+1);n++){ - //Use table lookup to get factorial - double partAccel[3] = {0}; - double factor = Earth::STANDARD_GRAVITATIONAL_PARAMETER/pow(Earth::MEAN_RADIUS,2); - if(m==0){ - //Montenbruck "Satellite Orbits Eq.3.33" - partAccel[0] = factor * (-C[n][0]*V[n+1][1]); - partAccel[1] = factor * (-C[n][0]*W[n+1][1]); - }else{ - double factMN = static_cast(factorialLookupTable[n-m+2]) / static_cast(factorialLookupTable[n-m]); - partAccel[0] = factor * 0.5 * ((-C[n][m]*V[n+1][m+1]-S[n][m]*W[n+1][m+1])+factMN*(C[n][m]*V[n+1][m-1]+S[n][m]*W[n+1][m-1])); - partAccel[1] = factor * 0.5 * ((-C[n][m]*W[n+1][m+1]+S[n][m]*V[n+1][m+1])+factMN*(-C[n][m]*W[n+1][m-1]+S[n][m]*V[n+1][m-1])); - } - - partAccel[2] = factor * ((n-m+1)*(-C[n][m]*V[n+1][m]-S[n][m]*W[n+1][m])); - - - accel[0] += partAccel[0]; - accel[1] += partAccel[1]; - accel[2] += partAccel[2]; - }//End of for(uint8_t n=0;n::mulScalar(y0dot,deltaT/2,yA,6); - VectorOperations::add(y0,yA,yA,6); - rungeKuttaStep(yA,yAdot,lastExecutionTime,S,C); - - //Step Three - VectorOperations::mulScalar(yAdot,deltaT/2,yB,6); - VectorOperations::add(y0,yB,yB,6); - rungeKuttaStep(yB,yBdot,lastExecutionTime,S,C); - - //Step Four - VectorOperations::mulScalar(yBdot,deltaT,yC,6); - VectorOperations::add(y0,yC,yC,6); - rungeKuttaStep(yC,yCdot,lastExecutionTime,S,C); - - //Calc new State - VectorOperations::mulScalar(yAdot,2,yAdot,6); - VectorOperations::mulScalar(yBdot,2,yBdot,6); - VectorOperations::add(y0dot,yAdot,y0dot,6); - VectorOperations::add(y0dot,yBdot,y0dot,6); - VectorOperations::add(y0dot,yCdot,y0dot,6); - VectorOperations::mulScalar(y0dot,1./6.*deltaT,y0dot,6); - VectorOperations::add(y0,y0dot,y0,6); - - CoordinateTransformations::positionEciToEcf(&y0[0],outputPos,&timeUTC); - CoordinateTransformations::velocityEciToEcf(&y0[3],&y0[0],outputVel,&timeUTC); - - lastExecutionTime = timeUTC; - - - } - - - void rungeKuttaStep(const double* yIn,double* yOut,timeval time, const double S[ORDER+1][DEGREE+1],const double C[ORDER+1][DEGREE+1]){ - double rECF[3] = {0,0,0}; - double rDotECF[3] = {0,0,0}; - double accelECF[3] = {0,0,0}; - double accelECI[3] = {0,0,0}; - - - CoordinateTransformations::positionEciToEcf(&yIn[0],rECF,&time); - CoordinateTransformations::velocityEciToEcf(&yIn[3],&yIn[0],rDotECF,&time); - accelDegOrd(rECF,S,C,accelECF); - //This is not correct, as the acceleration would have derived terms but we don't know the velocity and position at that time - //Tests showed that a wrong velocity does make the equation worse than neglecting it - CoordinateTransformations::positionEcfToEci(accelECF,accelECI,&time); - memcpy(&yOut[0],&yIn[3],sizeof(yOut[0])*3); - memcpy(&yOut[3],accelECI,sizeof(yOut[0])*3); - } -}; - - - - - - -#endif /* FRAMEWORK_COORDINATES_JGM3MODEL_H_ */ +#ifndef FRAMEWORK_COORDINATES_JGM3MODEL_H_ +#define FRAMEWORK_COORDINATES_JGM3MODEL_H_ + +#include +#include "../coordinates/CoordinateTransformations.h" +#include "../globalfunctions/math/VectorOperations.h" +#include "../globalfunctions/timevalOperations.h" +#include "../globalfunctions/constants.h" +#include + + +template +class Jgm3Model { +public: + static const uint32_t factorialLookupTable[DEGREE+3]; //This table is used instead of factorial calculation, must be increased if order or degree is higher + + Jgm3Model() { + y0[0] = 0; + y0[1] = 0; + y0[2] = 0; + y0[3] = 0; + y0[4] = 0; + y0[5] = 0; + + lastExecutionTime.tv_sec = 0; + lastExecutionTime.tv_usec = 0; + } + virtual ~Jgm3Model(){}; + + //double acsNavOrbit(double posECF[3],double velECF[3],timeval gpsTime); + + double y0[6]; //position and velocity at beginning of RK step in EC + timeval lastExecutionTime; //Time of last execution + + + void accelDegOrd(const double pos[3],const double S[ORDER+1][DEGREE+1],const double C[ORDER+1][DEGREE+1],double* accel){ + //Get radius of this position + double r = VectorOperations::norm(pos,3); + + + + //Initialize the V and W matrix + double V[DEGREE+2][ORDER+2] = {{0}}; + double W[DEGREE+2][ORDER+2] = {{0}}; + + for(uint8_t m=0;m<(ORDER+2);m++){ + for(uint8_t n=m;n<(DEGREE+2);n++){ + if((n==0) && (m==0)){ + //Montenbruck "Satellite Orbits Eq.3.31" + V[0][0] = Earth::MEAN_RADIUS / r; + W[0][0] = 0; + }else{ + if(n==m){ + //Montenbruck "Satellite Orbits Eq.3.29" + V[m][m] = (2*m-1)* (pos[0]*Earth::MEAN_RADIUS/pow(r,2)*V[m-1][m-1] - pos[1]*Earth::MEAN_RADIUS/pow(r,2)*W[m-1][m-1]); + W[m][m] = (2*m-1)* (pos[0]*Earth::MEAN_RADIUS/pow(r,2)*W[m-1][m-1] + pos[1]*Earth::MEAN_RADIUS/pow(r,2)*V[m-1][m-1]); + }else{ + //Montenbruck "Satellite Orbits Eq.3.30" + V[n][m] = ((2*n-1)/(double)(n-m))*pos[2]*Earth::MEAN_RADIUS / pow(r,2)*V[n-1][m]; + W[n][m] = ((2*n-1)/(double)(n-m))*pos[2]*Earth::MEAN_RADIUS / pow(r,2)*W[n-1][m]; + if(n!=(m+1)){ + V[n][m] = V[n][m] - (((n+m-1)/(double)(n-m)) * (pow(Earth::MEAN_RADIUS,2) / pow(r,2)) * V[n-2][m]); + W[n][m] = W[n][m] - (((n+m-1)/(double)(n-m)) * (pow(Earth::MEAN_RADIUS,2) / pow(r,2)) * W[n-2][m]); + }//End of if(n!=(m+1)) + }//End of if(n==m){ + }//End of if(n==0 and m==0) + }//End of for(uint8_t n=0;n<(DEGREE+1);n++) + }//End of for(uint8_t m=0;m<(ORDER+1);m++) + + + //overwrite accel if not properly initialized + accel[0] = 0; + accel[1] = 0; + accel[2] = 0; + + for(uint8_t m=0;m<(ORDER+1);m++){ + for(uint8_t n=m;n<(DEGREE+1);n++){ + //Use table lookup to get factorial + double partAccel[3] = {0}; + double factor = Earth::STANDARD_GRAVITATIONAL_PARAMETER/pow(Earth::MEAN_RADIUS,2); + if(m==0){ + //Montenbruck "Satellite Orbits Eq.3.33" + partAccel[0] = factor * (-C[n][0]*V[n+1][1]); + partAccel[1] = factor * (-C[n][0]*W[n+1][1]); + }else{ + double factMN = static_cast(factorialLookupTable[n-m+2]) / static_cast(factorialLookupTable[n-m]); + partAccel[0] = factor * 0.5 * ((-C[n][m]*V[n+1][m+1]-S[n][m]*W[n+1][m+1])+factMN*(C[n][m]*V[n+1][m-1]+S[n][m]*W[n+1][m-1])); + partAccel[1] = factor * 0.5 * ((-C[n][m]*W[n+1][m+1]+S[n][m]*V[n+1][m+1])+factMN*(-C[n][m]*W[n+1][m-1]+S[n][m]*V[n+1][m-1])); + } + + partAccel[2] = factor * ((n-m+1)*(-C[n][m]*V[n+1][m]-S[n][m]*W[n+1][m])); + + + accel[0] += partAccel[0]; + accel[1] += partAccel[1]; + accel[2] += partAccel[2]; + }//End of for(uint8_t n=0;n::mulScalar(y0dot,deltaT/2,yA,6); + VectorOperations::add(y0,yA,yA,6); + rungeKuttaStep(yA,yAdot,lastExecutionTime,S,C); + + //Step Three + VectorOperations::mulScalar(yAdot,deltaT/2,yB,6); + VectorOperations::add(y0,yB,yB,6); + rungeKuttaStep(yB,yBdot,lastExecutionTime,S,C); + + //Step Four + VectorOperations::mulScalar(yBdot,deltaT,yC,6); + VectorOperations::add(y0,yC,yC,6); + rungeKuttaStep(yC,yCdot,lastExecutionTime,S,C); + + //Calc new State + VectorOperations::mulScalar(yAdot,2,yAdot,6); + VectorOperations::mulScalar(yBdot,2,yBdot,6); + VectorOperations::add(y0dot,yAdot,y0dot,6); + VectorOperations::add(y0dot,yBdot,y0dot,6); + VectorOperations::add(y0dot,yCdot,y0dot,6); + VectorOperations::mulScalar(y0dot,1./6.*deltaT,y0dot,6); + VectorOperations::add(y0,y0dot,y0,6); + + CoordinateTransformations::positionEciToEcf(&y0[0],outputPos,&timeUTC); + CoordinateTransformations::velocityEciToEcf(&y0[3],&y0[0],outputVel,&timeUTC); + + lastExecutionTime = timeUTC; + + + } + + + void rungeKuttaStep(const double* yIn,double* yOut,timeval time, const double S[ORDER+1][DEGREE+1],const double C[ORDER+1][DEGREE+1]){ + double rECF[3] = {0,0,0}; + double rDotECF[3] = {0,0,0}; + double accelECF[3] = {0,0,0}; + double accelECI[3] = {0,0,0}; + + + CoordinateTransformations::positionEciToEcf(&yIn[0],rECF,&time); + CoordinateTransformations::velocityEciToEcf(&yIn[3],&yIn[0],rDotECF,&time); + accelDegOrd(rECF,S,C,accelECF); + //This is not correct, as the acceleration would have derived terms but we don't know the velocity and position at that time + //Tests showed that a wrong velocity does make the equation worse than neglecting it + CoordinateTransformations::positionEcfToEci(accelECF,accelECI,&time); + memcpy(&yOut[0],&yIn[3],sizeof(yOut[0])*3); + memcpy(&yOut[3],accelECI,sizeof(yOut[0])*3); + } +}; + + + + + + +#endif /* FRAMEWORK_COORDINATES_JGM3MODEL_H_ */ diff --git a/coordinates/Sgp4Propagator.cpp b/coordinates/Sgp4Propagator.cpp index 0eb20f08..84a52799 100644 --- a/coordinates/Sgp4Propagator.cpp +++ b/coordinates/Sgp4Propagator.cpp @@ -1,228 +1,228 @@ -#include -#include -#include -#include -#include -#include -#include -Sgp4Propagator::Sgp4Propagator() : - initialized(false), epoch({0, 0}), whichconst(wgs84) { - -} - -Sgp4Propagator::~Sgp4Propagator() { - -} - -void jday(int year, int mon, int day, int hr, int minute, double sec, - double& jd) { - jd = 367.0 * year - floor((7 * (year + floor((mon + 9) / 12.0))) * 0.25) - + floor(275 * mon / 9.0) + day + 1721013.5 - + ((sec / 60.0 + minute) / 60.0 + hr) / 24.0; // ut in days - // - 0.5*sgn(100.0*year + mon - 190002.5) + 0.5; -} - -void days2mdhms(int year, double days, int& mon, int& day, int& hr, int& minute, - double& sec) { - int i, inttemp, dayofyr; - double temp; - int lmonth[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; - - dayofyr = (int) floor(days); - /* ----------------- find month and day of month ---------------- */ - if ((year % 4) == 0) - lmonth[1] = 29; - - i = 1; - inttemp = 0; - while ((dayofyr > inttemp + lmonth[i - 1]) && (i < 12)) { - inttemp = inttemp + lmonth[i - 1]; - i++; - } - mon = i; - day = dayofyr - inttemp; - - /* ----------------- find hours minutes and seconds ------------- */ - temp = (days - dayofyr) * 24.0; - hr = (int) floor(temp); - temp = (temp - hr) * 60.0; - minute = (int) floor(temp); - sec = (temp - minute) * 60.0; -} - -ReturnValue_t Sgp4Propagator::initialize(const uint8_t* line1, - const uint8_t* line2) { - - char longstr1[130]; - char longstr2[130]; - - //need some space for decimal points - memcpy(longstr1, line1, 69); - memcpy(longstr2, line2, 69); - - const double deg2rad = Math::PI / 180.0; // 0.0174532925199433 - const double xpdotp = 1440.0 / (2.0 * Math::PI); // 229.1831180523293 - - double sec, mu, radiusearthkm, tumin, xke, j2, j3, j4, j3oj2; - int cardnumb, numb, j; - long revnum = 0, elnum = 0; - char classification, intldesg[11]; - int year = 0; - int mon, day, hr, minute, nexp, ibexp; - - getgravconst(whichconst, tumin, mu, radiusearthkm, xke, j2, j3, j4, j3oj2); - - satrec.error = 0; - - // set the implied decimal points since doing a formated read - // fixes for bad input data values (missing, ...) - for (j = 10; j <= 15; j++) - if (longstr1[j] == ' ') - longstr1[j] = '_'; - - if (longstr1[44] != ' ') - longstr1[43] = longstr1[44]; - longstr1[44] = '.'; - if (longstr1[7] == ' ') - longstr1[7] = 'U'; - if (longstr1[9] == ' ') - longstr1[9] = '.'; - for (j = 45; j <= 49; j++) - if (longstr1[j] == ' ') - longstr1[j] = '0'; - if (longstr1[51] == ' ') - longstr1[51] = '0'; - if (longstr1[53] != ' ') - longstr1[52] = longstr1[53]; - longstr1[53] = '.'; - longstr2[25] = '.'; - for (j = 26; j <= 32; j++) - if (longstr2[j] == ' ') - longstr2[j] = '0'; - if (longstr1[62] == ' ') - longstr1[62] = '0'; - if (longstr1[68] == ' ') - longstr1[68] = '0'; - - sscanf(longstr1, - "%2d %5ld %1c %10s %2d %12lf %11lf %7lf %2d %7lf %2d %2d %6ld ", - &cardnumb, &satrec.satnum, &classification, intldesg, - &satrec.epochyr, &satrec.epochdays, &satrec.ndot, &satrec.nddot, - &nexp, &satrec.bstar, &ibexp, &numb, &elnum); - - if (longstr2[52] == ' ') { - sscanf(longstr2, "%2d %5ld %9lf %9lf %8lf %9lf %9lf %10lf %6ld \n", - &cardnumb, &satrec.satnum, &satrec.inclo, &satrec.nodeo, - &satrec.ecco, &satrec.argpo, &satrec.mo, &satrec.no, &revnum); - } else { - sscanf(longstr2, "%2d %5ld %9lf %9lf %8lf %9lf %9lf %11lf %6ld \n", - &cardnumb, &satrec.satnum, &satrec.inclo, &satrec.nodeo, - &satrec.ecco, &satrec.argpo, &satrec.mo, &satrec.no, &revnum); - } - - // ---- find no, ndot, nddot ---- - satrec.no = satrec.no / xpdotp; //* rad/min - satrec.nddot = satrec.nddot * pow(10.0, nexp); - satrec.bstar = satrec.bstar * pow(10.0, ibexp); - - // ---- convert to sgp4 units ---- - satrec.a = pow(satrec.no * tumin, (-2.0 / 3.0)); - satrec.ndot = satrec.ndot / (xpdotp * 1440.0); //* ? * minperday - satrec.nddot = satrec.nddot / (xpdotp * 1440.0 * 1440); - - // ---- find standard orbital elements ---- - satrec.inclo = satrec.inclo * deg2rad; - satrec.nodeo = satrec.nodeo * deg2rad; - satrec.argpo = satrec.argpo * deg2rad; - satrec.mo = satrec.mo * deg2rad; - - satrec.alta = satrec.a * (1.0 + satrec.ecco) - 1.0; - satrec.altp = satrec.a * (1.0 - satrec.ecco) - 1.0; - - // ---------------------------------------------------------------- - // find sgp4epoch time of element set - // remember that sgp4 uses units of days from 0 jan 1950 (sgp4epoch) - // and minutes from the epoch (time) - // ---------------------------------------------------------------- - - // ---------------- temp fix for years from 1957-2056 ------------------- - // --------- correct fix will occur when year is 4-digit in tle --------- - if (satrec.epochyr < 57) { - year = satrec.epochyr + 2000; - } else { - year = satrec.epochyr + 1900; - } - - days2mdhms(year, satrec.epochdays, mon, day, hr, minute, sec); - jday(year, mon, day, hr, minute, sec, satrec.jdsatepoch); - - double unixSeconds = (satrec.jdsatepoch - 2451544.5) * 24 * 3600 - + 946684800; - - epoch.tv_sec = unixSeconds; - double subseconds = unixSeconds - epoch.tv_sec; - epoch.tv_usec = subseconds * 1000000; - - // ---------------- initialize the orbit at sgp4epoch ------------------- - uint8_t result = sgp4init(whichconst, satrec.satnum, - satrec.jdsatepoch - 2433281.5, satrec.bstar, satrec.ecco, - satrec.argpo, satrec.inclo, satrec.mo, satrec.no, satrec.nodeo, - satrec); - - if (result != 00) { - return MAKE_RETURN_CODE(result); - } else { - initialized = true; - return HasReturnvaluesIF::RETURN_OK; - } - -} - -ReturnValue_t Sgp4Propagator::propagate(double* position, double* velocity, - timeval time, uint8_t gpsUtcOffset) { - - if (!initialized) { - return TLE_NOT_INITIALIZED; - } - - //Time since epoch in minutes - timeval timeSinceEpoch = time - epoch; - double minutesSinceEpoch = timeSinceEpoch.tv_sec / 60. - + timeSinceEpoch.tv_usec / 60000000.; - - double yearsSinceEpoch = minutesSinceEpoch / 60 / 24 / 365; - - if ((yearsSinceEpoch > 1) || (yearsSinceEpoch < -1)) { - return TLE_TOO_OLD; - } - - double positionTEME[3]; - double velocityTEME[3]; - - uint8_t result = sgp4(whichconst, satrec, minutesSinceEpoch, positionTEME, - velocityTEME); - - VectorOperations::mulScalar(positionTEME, 1000, positionTEME, 3); - VectorOperations::mulScalar(velocityTEME, 1000, velocityTEME, 3); - - //Transform to ECF - double earthRotationMatrix[3][3]; - CoordinateTransformations::getEarthRotationMatrix(time, - earthRotationMatrix); - - MatrixOperations::multiply(earthRotationMatrix[0], positionTEME, - position, 3, 3, 1); - MatrixOperations::multiply(earthRotationMatrix[0], velocityTEME, - velocity, 3, 3, 1); - - double omegaEarth[3] = { 0, 0, Earth::OMEGA }; - double velocityCorrection[3]; - VectorOperations::cross(omegaEarth, position, velocityCorrection); - VectorOperations::subtract(velocity, velocityCorrection, velocity); - - if (result != 0) { - return MAKE_RETURN_CODE(result || 0xB0); - } else { - return HasReturnvaluesIF::RETURN_OK; - } -} +#include "../coordinates/CoordinateTransformations.h" +#include "../coordinates/Sgp4Propagator.h" +#include "../globalfunctions/constants.h" +#include "../globalfunctions/math/MatrixOperations.h" +#include "../globalfunctions/math/VectorOperations.h" +#include "../globalfunctions/timevalOperations.h" +#include +Sgp4Propagator::Sgp4Propagator() : + initialized(false), epoch({0, 0}), whichconst(wgs84) { + +} + +Sgp4Propagator::~Sgp4Propagator() { + +} + +void jday(int year, int mon, int day, int hr, int minute, double sec, + double& jd) { + jd = 367.0 * year - floor((7 * (year + floor((mon + 9) / 12.0))) * 0.25) + + floor(275 * mon / 9.0) + day + 1721013.5 + + ((sec / 60.0 + minute) / 60.0 + hr) / 24.0; // ut in days + // - 0.5*sgn(100.0*year + mon - 190002.5) + 0.5; +} + +void days2mdhms(int year, double days, int& mon, int& day, int& hr, int& minute, + double& sec) { + int i, inttemp, dayofyr; + double temp; + int lmonth[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + + dayofyr = (int) floor(days); + /* ----------------- find month and day of month ---------------- */ + if ((year % 4) == 0) + lmonth[1] = 29; + + i = 1; + inttemp = 0; + while ((dayofyr > inttemp + lmonth[i - 1]) && (i < 12)) { + inttemp = inttemp + lmonth[i - 1]; + i++; + } + mon = i; + day = dayofyr - inttemp; + + /* ----------------- find hours minutes and seconds ------------- */ + temp = (days - dayofyr) * 24.0; + hr = (int) floor(temp); + temp = (temp - hr) * 60.0; + minute = (int) floor(temp); + sec = (temp - minute) * 60.0; +} + +ReturnValue_t Sgp4Propagator::initialize(const uint8_t* line1, + const uint8_t* line2) { + + char longstr1[130]; + char longstr2[130]; + + //need some space for decimal points + memcpy(longstr1, line1, 69); + memcpy(longstr2, line2, 69); + + const double deg2rad = Math::PI / 180.0; // 0.0174532925199433 + const double xpdotp = 1440.0 / (2.0 * Math::PI); // 229.1831180523293 + + double sec, mu, radiusearthkm, tumin, xke, j2, j3, j4, j3oj2; + int cardnumb, numb, j; + long revnum = 0, elnum = 0; + char classification, intldesg[11]; + int year = 0; + int mon, day, hr, minute, nexp, ibexp; + + getgravconst(whichconst, tumin, mu, radiusearthkm, xke, j2, j3, j4, j3oj2); + + satrec.error = 0; + + // set the implied decimal points since doing a formated read + // fixes for bad input data values (missing, ...) + for (j = 10; j <= 15; j++) + if (longstr1[j] == ' ') + longstr1[j] = '_'; + + if (longstr1[44] != ' ') + longstr1[43] = longstr1[44]; + longstr1[44] = '.'; + if (longstr1[7] == ' ') + longstr1[7] = 'U'; + if (longstr1[9] == ' ') + longstr1[9] = '.'; + for (j = 45; j <= 49; j++) + if (longstr1[j] == ' ') + longstr1[j] = '0'; + if (longstr1[51] == ' ') + longstr1[51] = '0'; + if (longstr1[53] != ' ') + longstr1[52] = longstr1[53]; + longstr1[53] = '.'; + longstr2[25] = '.'; + for (j = 26; j <= 32; j++) + if (longstr2[j] == ' ') + longstr2[j] = '0'; + if (longstr1[62] == ' ') + longstr1[62] = '0'; + if (longstr1[68] == ' ') + longstr1[68] = '0'; + + sscanf(longstr1, + "%2d %5ld %1c %10s %2d %12lf %11lf %7lf %2d %7lf %2d %2d %6ld ", + &cardnumb, &satrec.satnum, &classification, intldesg, + &satrec.epochyr, &satrec.epochdays, &satrec.ndot, &satrec.nddot, + &nexp, &satrec.bstar, &ibexp, &numb, &elnum); + + if (longstr2[52] == ' ') { + sscanf(longstr2, "%2d %5ld %9lf %9lf %8lf %9lf %9lf %10lf %6ld \n", + &cardnumb, &satrec.satnum, &satrec.inclo, &satrec.nodeo, + &satrec.ecco, &satrec.argpo, &satrec.mo, &satrec.no, &revnum); + } else { + sscanf(longstr2, "%2d %5ld %9lf %9lf %8lf %9lf %9lf %11lf %6ld \n", + &cardnumb, &satrec.satnum, &satrec.inclo, &satrec.nodeo, + &satrec.ecco, &satrec.argpo, &satrec.mo, &satrec.no, &revnum); + } + + // ---- find no, ndot, nddot ---- + satrec.no = satrec.no / xpdotp; //* rad/min + satrec.nddot = satrec.nddot * pow(10.0, nexp); + satrec.bstar = satrec.bstar * pow(10.0, ibexp); + + // ---- convert to sgp4 units ---- + satrec.a = pow(satrec.no * tumin, (-2.0 / 3.0)); + satrec.ndot = satrec.ndot / (xpdotp * 1440.0); //* ? * minperday + satrec.nddot = satrec.nddot / (xpdotp * 1440.0 * 1440); + + // ---- find standard orbital elements ---- + satrec.inclo = satrec.inclo * deg2rad; + satrec.nodeo = satrec.nodeo * deg2rad; + satrec.argpo = satrec.argpo * deg2rad; + satrec.mo = satrec.mo * deg2rad; + + satrec.alta = satrec.a * (1.0 + satrec.ecco) - 1.0; + satrec.altp = satrec.a * (1.0 - satrec.ecco) - 1.0; + + // ---------------------------------------------------------------- + // find sgp4epoch time of element set + // remember that sgp4 uses units of days from 0 jan 1950 (sgp4epoch) + // and minutes from the epoch (time) + // ---------------------------------------------------------------- + + // ---------------- temp fix for years from 1957-2056 ------------------- + // --------- correct fix will occur when year is 4-digit in tle --------- + if (satrec.epochyr < 57) { + year = satrec.epochyr + 2000; + } else { + year = satrec.epochyr + 1900; + } + + days2mdhms(year, satrec.epochdays, mon, day, hr, minute, sec); + jday(year, mon, day, hr, minute, sec, satrec.jdsatepoch); + + double unixSeconds = (satrec.jdsatepoch - 2451544.5) * 24 * 3600 + + 946684800; + + epoch.tv_sec = unixSeconds; + double subseconds = unixSeconds - epoch.tv_sec; + epoch.tv_usec = subseconds * 1000000; + + // ---------------- initialize the orbit at sgp4epoch ------------------- + uint8_t result = sgp4init(whichconst, satrec.satnum, + satrec.jdsatepoch - 2433281.5, satrec.bstar, satrec.ecco, + satrec.argpo, satrec.inclo, satrec.mo, satrec.no, satrec.nodeo, + satrec); + + if (result != 00) { + return MAKE_RETURN_CODE(result); + } else { + initialized = true; + return HasReturnvaluesIF::RETURN_OK; + } + +} + +ReturnValue_t Sgp4Propagator::propagate(double* position, double* velocity, + timeval time, uint8_t gpsUtcOffset) { + + if (!initialized) { + return TLE_NOT_INITIALIZED; + } + + //Time since epoch in minutes + timeval timeSinceEpoch = time - epoch; + double minutesSinceEpoch = timeSinceEpoch.tv_sec / 60. + + timeSinceEpoch.tv_usec / 60000000.; + + double yearsSinceEpoch = minutesSinceEpoch / 60 / 24 / 365; + + if ((yearsSinceEpoch > 1) || (yearsSinceEpoch < -1)) { + return TLE_TOO_OLD; + } + + double positionTEME[3]; + double velocityTEME[3]; + + uint8_t result = sgp4(whichconst, satrec, minutesSinceEpoch, positionTEME, + velocityTEME); + + VectorOperations::mulScalar(positionTEME, 1000, positionTEME, 3); + VectorOperations::mulScalar(velocityTEME, 1000, velocityTEME, 3); + + //Transform to ECF + double earthRotationMatrix[3][3]; + CoordinateTransformations::getEarthRotationMatrix(time, + earthRotationMatrix); + + MatrixOperations::multiply(earthRotationMatrix[0], positionTEME, + position, 3, 3, 1); + MatrixOperations::multiply(earthRotationMatrix[0], velocityTEME, + velocity, 3, 3, 1); + + double omegaEarth[3] = { 0, 0, Earth::OMEGA }; + double velocityCorrection[3]; + VectorOperations::cross(omegaEarth, position, velocityCorrection); + VectorOperations::subtract(velocity, velocityCorrection, velocity); + + if (result != 0) { + return MAKE_RETURN_CODE(result || 0xB0); + } else { + return HasReturnvaluesIF::RETURN_OK; + } +} diff --git a/coordinates/Sgp4Propagator.h b/coordinates/Sgp4Propagator.h index 95739762..f041ec07 100644 --- a/coordinates/Sgp4Propagator.h +++ b/coordinates/Sgp4Propagator.h @@ -1,44 +1,44 @@ -#ifndef SGP4PROPAGATOR_H_ -#define SGP4PROPAGATOR_H_ - -#include -#include "../contrib/sgp4/sgp4unit.h" -#include - -class Sgp4Propagator { -public: - static const uint8_t INTERFACE_ID = CLASS_ID::SGP4PROPAGATOR_CLASS; - static const ReturnValue_t INVALID_ECCENTRICITY = MAKE_RETURN_CODE(0xA1); - static const ReturnValue_t INVALID_MEAN_MOTION = MAKE_RETURN_CODE(0xA2); - static const ReturnValue_t INVALID_PERTURBATION_ELEMENTS = MAKE_RETURN_CODE(0xA3); - static const ReturnValue_t INVALID_SEMI_LATUS_RECTUM = MAKE_RETURN_CODE(0xA4); - static const ReturnValue_t INVALID_EPOCH_ELEMENTS = MAKE_RETURN_CODE(0xA5); - static const ReturnValue_t SATELLITE_HAS_DECAYED = MAKE_RETURN_CODE(0xA6); - static const ReturnValue_t TLE_TOO_OLD = MAKE_RETURN_CODE(0xB1); - static const ReturnValue_t TLE_NOT_INITIALIZED = MAKE_RETURN_CODE(0xB2); - - - - Sgp4Propagator(); - virtual ~Sgp4Propagator(); - - ReturnValue_t initialize(const uint8_t *line1, const uint8_t *line2); - - /** - * - * @param[out] position in ECF - * @param[out] velocity in ECF - * @param time to which to propagate - * @return - */ - ReturnValue_t propagate(double *position, double *velocity, timeval time, uint8_t gpsUtcOffset); - -private: - bool initialized; - timeval epoch; - elsetrec satrec; - gravconsttype whichconst; - -}; - -#endif /* SGP4PROPAGATOR_H_ */ +#ifndef SGP4PROPAGATOR_H_ +#define SGP4PROPAGATOR_H_ + +#include +#include "../contrib/sgp4/sgp4unit.h" +#include "../returnvalues/HasReturnvaluesIF.h" + +class Sgp4Propagator { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::SGP4PROPAGATOR_CLASS; + static const ReturnValue_t INVALID_ECCENTRICITY = MAKE_RETURN_CODE(0xA1); + static const ReturnValue_t INVALID_MEAN_MOTION = MAKE_RETURN_CODE(0xA2); + static const ReturnValue_t INVALID_PERTURBATION_ELEMENTS = MAKE_RETURN_CODE(0xA3); + static const ReturnValue_t INVALID_SEMI_LATUS_RECTUM = MAKE_RETURN_CODE(0xA4); + static const ReturnValue_t INVALID_EPOCH_ELEMENTS = MAKE_RETURN_CODE(0xA5); + static const ReturnValue_t SATELLITE_HAS_DECAYED = MAKE_RETURN_CODE(0xA6); + static const ReturnValue_t TLE_TOO_OLD = MAKE_RETURN_CODE(0xB1); + static const ReturnValue_t TLE_NOT_INITIALIZED = MAKE_RETURN_CODE(0xB2); + + + + Sgp4Propagator(); + virtual ~Sgp4Propagator(); + + ReturnValue_t initialize(const uint8_t *line1, const uint8_t *line2); + + /** + * + * @param[out] position in ECF + * @param[out] velocity in ECF + * @param time to which to propagate + * @return + */ + ReturnValue_t propagate(double *position, double *velocity, timeval time, uint8_t gpsUtcOffset); + +private: + bool initialized; + timeval epoch; + elsetrec satrec; + gravconsttype whichconst; + +}; + +#endif /* SGP4PROPAGATOR_H_ */ diff --git a/datalinklayer/BCFrame.h b/datalinklayer/BCFrame.h index bcdf5300..785cbb75 100644 --- a/datalinklayer/BCFrame.h +++ b/datalinklayer/BCFrame.h @@ -1,62 +1,62 @@ -/** - * @file BCFrame.h - * @brief This file defines the BCFrame class. - * @date 24.04.2013 - * @author baetz - */ - -#ifndef BCFRAME_H_ -#define BCFRAME_H_ - -#include - -/** - * Small helper class to identify a BcFrame. - * @ingroup ccsds_handling - */ -class BcFrame: public CCSDSReturnValuesIF { -private: - static const uint8_t UNLOCK_COMMAND = 0b00000000;//! Identifier for a certain BC Command. - static const uint8_t SET_V_R_1 = 0b10000010;//! Identifier for a certain BC Command. - static const uint8_t SET_V_R_2 = 0b00000000;//! Identifier for a certain BC Command. - -public: - uint8_t byte1; //!< First content byte - uint8_t byte2; //!< Second content byte - uint8_t vR; //!< vR byte - /** - * Simple default constructor. - */ - BcFrame() : - byte1(0), byte2(0), vR(0) { - } - /** - * Main and only useful method of the class. - * With the buffer and size information passed, the class passes the content - * and checks if it is one of the two valid BC Command Frames. - * @param inBuffer Content of the frame to check, - * @param inSize Size of the data to check. - * @return - #BC_ILLEGAL_COMMAND if it is no command. - * - #BC_IS_UNLOCK_COMMAND if it is an unlock command. - * - #BC_IS_SET_VR_COMMAND if it is such. - */ - ReturnValue_t initialize(const uint8_t* inBuffer, uint16_t inSize) { - ReturnValue_t returnValue = BC_ILLEGAL_COMMAND; - if (inSize == 1) { - byte1 = inBuffer[0]; - if (byte1 == UNLOCK_COMMAND) { - returnValue = BC_IS_UNLOCK_COMMAND; - } - } else if (inSize == 3) { - byte1 = inBuffer[0]; - byte2 = inBuffer[1]; - vR = inBuffer[2]; - if (byte1 == SET_V_R_1 && byte2 == SET_V_R_2) { - returnValue = BC_IS_SET_VR_COMMAND; - } - } - return returnValue; - } -}; - -#endif /* BCFRAME_H_ */ +/** + * @file BCFrame.h + * @brief This file defines the BCFrame class. + * @date 24.04.2013 + * @author baetz + */ + +#ifndef BCFRAME_H_ +#define BCFRAME_H_ + +#include "../datalinklayer/CCSDSReturnValuesIF.h" + +/** + * Small helper class to identify a BcFrame. + * @ingroup ccsds_handling + */ +class BcFrame: public CCSDSReturnValuesIF { +private: + static const uint8_t UNLOCK_COMMAND = 0b00000000;//! Identifier for a certain BC Command. + static const uint8_t SET_V_R_1 = 0b10000010;//! Identifier for a certain BC Command. + static const uint8_t SET_V_R_2 = 0b00000000;//! Identifier for a certain BC Command. + +public: + uint8_t byte1; //!< First content byte + uint8_t byte2; //!< Second content byte + uint8_t vR; //!< vR byte + /** + * Simple default constructor. + */ + BcFrame() : + byte1(0), byte2(0), vR(0) { + } + /** + * Main and only useful method of the class. + * With the buffer and size information passed, the class passes the content + * and checks if it is one of the two valid BC Command Frames. + * @param inBuffer Content of the frame to check, + * @param inSize Size of the data to check. + * @return - #BC_ILLEGAL_COMMAND if it is no command. + * - #BC_IS_UNLOCK_COMMAND if it is an unlock command. + * - #BC_IS_SET_VR_COMMAND if it is such. + */ + ReturnValue_t initialize(const uint8_t* inBuffer, uint16_t inSize) { + ReturnValue_t returnValue = BC_ILLEGAL_COMMAND; + if (inSize == 1) { + byte1 = inBuffer[0]; + if (byte1 == UNLOCK_COMMAND) { + returnValue = BC_IS_UNLOCK_COMMAND; + } + } else if (inSize == 3) { + byte1 = inBuffer[0]; + byte2 = inBuffer[1]; + vR = inBuffer[2]; + if (byte1 == SET_V_R_1 && byte2 == SET_V_R_2) { + returnValue = BC_IS_SET_VR_COMMAND; + } + } + return returnValue; + } +}; + +#endif /* BCFRAME_H_ */ diff --git a/datalinklayer/CCSDSReturnValuesIF.h b/datalinklayer/CCSDSReturnValuesIF.h index 4d4f4bde..054be9e7 100644 --- a/datalinklayer/CCSDSReturnValuesIF.h +++ b/datalinklayer/CCSDSReturnValuesIF.h @@ -1,56 +1,56 @@ -/** - * @file CCSDSReturnValuesIF.h - * @brief This file defines the CCSDSReturnValuesIF class. - * @date 24.04.2013 - * @author baetz - */ - -#ifndef CCSDSRETURNVALUESIF_H_ -#define CCSDSRETURNVALUESIF_H_ - -#include -/** - * This is a helper class to collect special return values that come up during CCSDS Handling. - * @ingroup ccsds_handling - */ -class CCSDSReturnValuesIF: public HasReturnvaluesIF { -public: - static const uint8_t INTERFACE_ID = CLASS_ID::CCSDS_HANDLER_IF; //!< Basic ID of the interface. - - static const ReturnValue_t BC_IS_SET_VR_COMMAND = MAKE_RETURN_CODE( 0x01 ); //!< A value to describe a BC frame. - static const ReturnValue_t BC_IS_UNLOCK_COMMAND = MAKE_RETURN_CODE( 0x02 ); //!< A value to describe a BC frame. - static const ReturnValue_t BC_ILLEGAL_COMMAND = MAKE_RETURN_CODE( 0xB0 );//!< A value to describe an illegal BC frame. - static const ReturnValue_t BOARD_READING_NOT_FINISHED = MAKE_RETURN_CODE( 0xB1 ); //! The CCSDS Board is not yet finished reading, it requires another cycle. - - static const ReturnValue_t NS_POSITIVE_W = MAKE_RETURN_CODE( 0xF0 );//!< NS is in the positive window - static const ReturnValue_t NS_NEGATIVE_W = MAKE_RETURN_CODE( 0xF1 );//!< NS is in the negative window - static const ReturnValue_t NS_LOCKOUT = MAKE_RETURN_CODE( 0xF2 ); //!< NS is in lockout state - static const ReturnValue_t FARM_IN_LOCKOUT = MAKE_RETURN_CODE( 0xF3 );//!< FARM-1 is currently in lockout state - static const ReturnValue_t FARM_IN_WAIT = MAKE_RETURN_CODE( 0xF4 ); //!< FARM-1 is currently in wait state - - static const ReturnValue_t WRONG_SYMBOL = MAKE_RETURN_CODE( 0xE0 ); //!< An error code in the FrameFinder. - static const ReturnValue_t DOUBLE_START = MAKE_RETURN_CODE( 0xE1 ); //!< An error code in the FrameFinder. - static const ReturnValue_t START_SYMBOL_MISSED = MAKE_RETURN_CODE( 0xE2 );//!< An error code in the FrameFinder. - static const ReturnValue_t END_WITHOUT_START = MAKE_RETURN_CODE( 0xE3 );//!< An error code in the FrameFinder. - static const ReturnValue_t TOO_LARGE = MAKE_RETURN_CODE( 0xE4 );//!< An error code for a frame. - static const ReturnValue_t TOO_SHORT = MAKE_RETURN_CODE( 0xE5 );//!< An error code for a frame. - static const ReturnValue_t WRONG_TF_VERSION = MAKE_RETURN_CODE( 0xE6 ); //!< An error code for a frame. - static const ReturnValue_t WRONG_SPACECRAFT_ID = MAKE_RETURN_CODE( 0xE7 );//!< An error code for a frame. - static const ReturnValue_t NO_VALID_FRAME_TYPE = MAKE_RETURN_CODE( 0xE8 );//!< An error code for a frame. - static const ReturnValue_t CRC_FAILED = MAKE_RETURN_CODE( 0xE9 );//!< An error code for a frame. - static const ReturnValue_t VC_NOT_FOUND = MAKE_RETURN_CODE( 0xEA ); //!< An error code for a frame. - static const ReturnValue_t FORWARDING_FAILED = MAKE_RETURN_CODE( 0xEB );//!< An error code for a frame. - static const ReturnValue_t CONTENT_TOO_LARGE = MAKE_RETURN_CODE( 0xEC );//!< An error code for a frame. - static const ReturnValue_t RESIDUAL_DATA = MAKE_RETURN_CODE( 0xED );//!< An error code for a frame. - static const ReturnValue_t DATA_CORRUPTED = MAKE_RETURN_CODE( 0xEE );//!< An error code for a frame. - static const ReturnValue_t ILLEGAL_SEGMENTATION_FLAG = MAKE_RETURN_CODE( 0xEF );//!< An error code for a frame. - static const ReturnValue_t ILLEGAL_FLAG_COMBINATION = MAKE_RETURN_CODE( 0xD0 ); //!< An error code for a frame. - static const ReturnValue_t SHORTER_THAN_HEADER = MAKE_RETURN_CODE( 0xD1 ); //!< An error code for a frame. - static const ReturnValue_t TOO_SHORT_BLOCKED_PACKET = MAKE_RETURN_CODE( 0xD2 ); //!< An error code for a frame. - static const ReturnValue_t TOO_SHORT_MAP_EXTRACTION = MAKE_RETURN_CODE( 0xD3 ); //!< An error code for a frame. - - virtual ~CCSDSReturnValuesIF() { - } //!< Empty virtual destructor -}; - -#endif /* CCSDSRETURNVALUESIF_H_ */ +/** + * @file CCSDSReturnValuesIF.h + * @brief This file defines the CCSDSReturnValuesIF class. + * @date 24.04.2013 + * @author baetz + */ + +#ifndef CCSDSRETURNVALUESIF_H_ +#define CCSDSRETURNVALUESIF_H_ + +#include "../returnvalues/HasReturnvaluesIF.h" +/** + * This is a helper class to collect special return values that come up during CCSDS Handling. + * @ingroup ccsds_handling + */ +class CCSDSReturnValuesIF: public HasReturnvaluesIF { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::CCSDS_HANDLER_IF; //!< Basic ID of the interface. + + static const ReturnValue_t BC_IS_SET_VR_COMMAND = MAKE_RETURN_CODE( 0x01 ); //!< A value to describe a BC frame. + static const ReturnValue_t BC_IS_UNLOCK_COMMAND = MAKE_RETURN_CODE( 0x02 ); //!< A value to describe a BC frame. + static const ReturnValue_t BC_ILLEGAL_COMMAND = MAKE_RETURN_CODE( 0xB0 );//!< A value to describe an illegal BC frame. + static const ReturnValue_t BOARD_READING_NOT_FINISHED = MAKE_RETURN_CODE( 0xB1 ); //! The CCSDS Board is not yet finished reading, it requires another cycle. + + static const ReturnValue_t NS_POSITIVE_W = MAKE_RETURN_CODE( 0xF0 );//!< NS is in the positive window + static const ReturnValue_t NS_NEGATIVE_W = MAKE_RETURN_CODE( 0xF1 );//!< NS is in the negative window + static const ReturnValue_t NS_LOCKOUT = MAKE_RETURN_CODE( 0xF2 ); //!< NS is in lockout state + static const ReturnValue_t FARM_IN_LOCKOUT = MAKE_RETURN_CODE( 0xF3 );//!< FARM-1 is currently in lockout state + static const ReturnValue_t FARM_IN_WAIT = MAKE_RETURN_CODE( 0xF4 ); //!< FARM-1 is currently in wait state + + static const ReturnValue_t WRONG_SYMBOL = MAKE_RETURN_CODE( 0xE0 ); //!< An error code in the FrameFinder. + static const ReturnValue_t DOUBLE_START = MAKE_RETURN_CODE( 0xE1 ); //!< An error code in the FrameFinder. + static const ReturnValue_t START_SYMBOL_MISSED = MAKE_RETURN_CODE( 0xE2 );//!< An error code in the FrameFinder. + static const ReturnValue_t END_WITHOUT_START = MAKE_RETURN_CODE( 0xE3 );//!< An error code in the FrameFinder. + static const ReturnValue_t TOO_LARGE = MAKE_RETURN_CODE( 0xE4 );//!< An error code for a frame. + static const ReturnValue_t TOO_SHORT = MAKE_RETURN_CODE( 0xE5 );//!< An error code for a frame. + static const ReturnValue_t WRONG_TF_VERSION = MAKE_RETURN_CODE( 0xE6 ); //!< An error code for a frame. + static const ReturnValue_t WRONG_SPACECRAFT_ID = MAKE_RETURN_CODE( 0xE7 );//!< An error code for a frame. + static const ReturnValue_t NO_VALID_FRAME_TYPE = MAKE_RETURN_CODE( 0xE8 );//!< An error code for a frame. + static const ReturnValue_t CRC_FAILED = MAKE_RETURN_CODE( 0xE9 );//!< An error code for a frame. + static const ReturnValue_t VC_NOT_FOUND = MAKE_RETURN_CODE( 0xEA ); //!< An error code for a frame. + static const ReturnValue_t FORWARDING_FAILED = MAKE_RETURN_CODE( 0xEB );//!< An error code for a frame. + static const ReturnValue_t CONTENT_TOO_LARGE = MAKE_RETURN_CODE( 0xEC );//!< An error code for a frame. + static const ReturnValue_t RESIDUAL_DATA = MAKE_RETURN_CODE( 0xED );//!< An error code for a frame. + static const ReturnValue_t DATA_CORRUPTED = MAKE_RETURN_CODE( 0xEE );//!< An error code for a frame. + static const ReturnValue_t ILLEGAL_SEGMENTATION_FLAG = MAKE_RETURN_CODE( 0xEF );//!< An error code for a frame. + static const ReturnValue_t ILLEGAL_FLAG_COMBINATION = MAKE_RETURN_CODE( 0xD0 ); //!< An error code for a frame. + static const ReturnValue_t SHORTER_THAN_HEADER = MAKE_RETURN_CODE( 0xD1 ); //!< An error code for a frame. + static const ReturnValue_t TOO_SHORT_BLOCKED_PACKET = MAKE_RETURN_CODE( 0xD2 ); //!< An error code for a frame. + static const ReturnValue_t TOO_SHORT_MAP_EXTRACTION = MAKE_RETURN_CODE( 0xD3 ); //!< An error code for a frame. + + virtual ~CCSDSReturnValuesIF() { + } //!< Empty virtual destructor +}; + +#endif /* CCSDSRETURNVALUESIF_H_ */ diff --git a/datalinklayer/Clcw.cpp b/datalinklayer/Clcw.cpp index ee497e20..53424e8a 100644 --- a/datalinklayer/Clcw.cpp +++ b/datalinklayer/Clcw.cpp @@ -1,63 +1,63 @@ -/** - * @file Clcw.cpp - * @brief This file defines the Clcw class. - * @date 17.04.2013 - * @author baetz - */ - - - -#include -#include - -Clcw::Clcw() { - content.raw = 0; - content.status = STATUS_FIELD_DEFAULT; -} - -Clcw::~Clcw() { -} - -void Clcw::setVirtualChannel(uint8_t setChannel) { - content.virtualChannelIdSpare = ((setChannel & 0x3F) << 2); -} - -void Clcw::setLockoutFlag(bool lockout) { - content.flags = (content.flags & LOCKOUT_FLAG_MASK) | (lockout << LOCKOUT_FLAG_POSITION); -} - -void Clcw::setWaitFlag(bool waitFlag) { - content.flags = (content.flags & WAIT_FLAG_MASK) | (waitFlag << WAIT_FLAG_POSITION); -} - -void Clcw::setRetransmitFlag(bool retransmitFlag) { - content.flags = (content.flags & RETRANSMIT_FLAG_MASK) | (retransmitFlag << RETRANSMIT_FLAG_POSITION); -} - -void Clcw::setFarmBCount(uint8_t count) { - content.flags = (content.flags & FARM_B_COUNT_MASK) | ((count & 0x03) << 1); -} - -void Clcw::setReceiverFrameSequenceNumber(uint8_t vR) { - content.vRValue = vR; -} - -uint32_t Clcw::getAsWhole() { - return content.raw; -} - -void Clcw::setRFAvailable(bool rfAvailable) { - content.flags = (content.flags & NO_RF_AVIALABLE_MASK) | (!rfAvailable << NO_RF_AVIALABLE_POSITION); -} - -void Clcw::setBitLock(bool bitLock) { - content.flags = (content.flags & NO_BIT_LOCK_MASK) | (!bitLock << NO_BIT_LOCK_POSITION); -} - -void Clcw::print() { - sif::debug << "Clcw::print: Clcw is: " << std::hex << getAsWhole() << std::dec << std::endl; -} - -void Clcw::setWhole(uint32_t rawClcw) { - content.raw = rawClcw; -} +/** + * @file Clcw.cpp + * @brief This file defines the Clcw class. + * @date 17.04.2013 + * @author baetz + */ + + + +#include "../datalinklayer/Clcw.h" +#include "../serviceinterface/ServiceInterfaceStream.h" + +Clcw::Clcw() { + content.raw = 0; + content.status = STATUS_FIELD_DEFAULT; +} + +Clcw::~Clcw() { +} + +void Clcw::setVirtualChannel(uint8_t setChannel) { + content.virtualChannelIdSpare = ((setChannel & 0x3F) << 2); +} + +void Clcw::setLockoutFlag(bool lockout) { + content.flags = (content.flags & LOCKOUT_FLAG_MASK) | (lockout << LOCKOUT_FLAG_POSITION); +} + +void Clcw::setWaitFlag(bool waitFlag) { + content.flags = (content.flags & WAIT_FLAG_MASK) | (waitFlag << WAIT_FLAG_POSITION); +} + +void Clcw::setRetransmitFlag(bool retransmitFlag) { + content.flags = (content.flags & RETRANSMIT_FLAG_MASK) | (retransmitFlag << RETRANSMIT_FLAG_POSITION); +} + +void Clcw::setFarmBCount(uint8_t count) { + content.flags = (content.flags & FARM_B_COUNT_MASK) | ((count & 0x03) << 1); +} + +void Clcw::setReceiverFrameSequenceNumber(uint8_t vR) { + content.vRValue = vR; +} + +uint32_t Clcw::getAsWhole() { + return content.raw; +} + +void Clcw::setRFAvailable(bool rfAvailable) { + content.flags = (content.flags & NO_RF_AVIALABLE_MASK) | (!rfAvailable << NO_RF_AVIALABLE_POSITION); +} + +void Clcw::setBitLock(bool bitLock) { + content.flags = (content.flags & NO_BIT_LOCK_MASK) | (!bitLock << NO_BIT_LOCK_POSITION); +} + +void Clcw::print() { + sif::debug << "Clcw::print: Clcw is: " << std::hex << getAsWhole() << std::dec << std::endl; +} + +void Clcw::setWhole(uint32_t rawClcw) { + content.raw = rawClcw; +} diff --git a/datalinklayer/Clcw.h b/datalinklayer/Clcw.h index f19f37b6..72ccd77a 100644 --- a/datalinklayer/Clcw.h +++ b/datalinklayer/Clcw.h @@ -1,66 +1,66 @@ -/** - * @file Clcw.h - * @brief This file defines the Clcw class. - * @date 17.04.2013 - * @author baetz - */ - -#ifndef CLCW_H_ -#define CLCW_H_ - -#include -/** - * Small helper method to handle the Clcw values. - * It has a content struct that manages the register and can be set externally. - * @ingroup ccsds_handling - */ -class Clcw : public ClcwIF { -private: - static const uint8_t STATUS_FIELD_DEFAULT = 0b00000001; //!< Default for the status field. - static const uint8_t NO_RF_AVIALABLE_POSITION = 7; //!< Position of a flag in the register (starting with 0). - static const uint8_t NO_BIT_LOCK_POSITION = 6; //!< Position of a flag in the register (starting with 0). - static const uint8_t LOCKOUT_FLAG_POSITION = 5; //!< Position of a flag in the register (starting with 0). - static const uint8_t WAIT_FLAG_POSITION = 4; //!< Position of a flag in the register (starting with 0). - static const uint8_t RETRANSMIT_FLAG_POSITION = 3; //!< Position of a flag in the register (starting with 0). - static const uint8_t NO_RF_AVIALABLE_MASK = 0xFF xor (1 << NO_RF_AVIALABLE_POSITION); //!< Mask for a flag in the register. - static const uint8_t NO_BIT_LOCK_MASK = 0xFF xor (1 << NO_BIT_LOCK_POSITION); //!< Mask for a flag in the register. - static const uint8_t LOCKOUT_FLAG_MASK = 0xFF xor (1 << LOCKOUT_FLAG_POSITION); //!< Mask for a flag in the register. - static const uint8_t WAIT_FLAG_MASK = 0xFF xor (1 << WAIT_FLAG_POSITION); //!< Mask for a flag in the register. - static const uint8_t RETRANSMIT_FLAG_MASK = 0xFF xor (1 << RETRANSMIT_FLAG_POSITION); //!< Mask for a flag in the register. - static const uint8_t FARM_B_COUNT_MASK = 0b11111001; //!< Mask for a counter in the register. - /** - * This is the data structure of the CLCW register. - */ - union clcwContent { - uint32_t raw; - struct { - uint8_t status; - uint8_t virtualChannelIdSpare; - uint8_t flags; - uint8_t vRValue; - }; - }; - clcwContent content; //!< Represents the content of the register. -public: - /** - * The constructor sets everything to default values. - */ - Clcw(); - /** - * Nothing happens in the destructor. - */ - ~Clcw(); - void setVirtualChannel( uint8_t setChannel ); - void setLockoutFlag( bool lockout ); - void setWaitFlag( bool waitFlag ); - void setRetransmitFlag( bool retransmitFlag ); - void setFarmBCount( uint8_t count ); - void setReceiverFrameSequenceNumber( uint8_t vR ); - void setRFAvailable( bool rfAvailable ); - void setBitLock( bool bitLock ); - uint32_t getAsWhole(); - void setWhole( uint32_t rawClcw ); - void print(); -}; - -#endif /* CLCW_H_ */ +/** + * @file Clcw.h + * @brief This file defines the Clcw class. + * @date 17.04.2013 + * @author baetz + */ + +#ifndef CLCW_H_ +#define CLCW_H_ + +#include "../datalinklayer/ClcwIF.h" +/** + * Small helper method to handle the Clcw values. + * It has a content struct that manages the register and can be set externally. + * @ingroup ccsds_handling + */ +class Clcw : public ClcwIF { +private: + static const uint8_t STATUS_FIELD_DEFAULT = 0b00000001; //!< Default for the status field. + static const uint8_t NO_RF_AVIALABLE_POSITION = 7; //!< Position of a flag in the register (starting with 0). + static const uint8_t NO_BIT_LOCK_POSITION = 6; //!< Position of a flag in the register (starting with 0). + static const uint8_t LOCKOUT_FLAG_POSITION = 5; //!< Position of a flag in the register (starting with 0). + static const uint8_t WAIT_FLAG_POSITION = 4; //!< Position of a flag in the register (starting with 0). + static const uint8_t RETRANSMIT_FLAG_POSITION = 3; //!< Position of a flag in the register (starting with 0). + static const uint8_t NO_RF_AVIALABLE_MASK = 0xFF xor (1 << NO_RF_AVIALABLE_POSITION); //!< Mask for a flag in the register. + static const uint8_t NO_BIT_LOCK_MASK = 0xFF xor (1 << NO_BIT_LOCK_POSITION); //!< Mask for a flag in the register. + static const uint8_t LOCKOUT_FLAG_MASK = 0xFF xor (1 << LOCKOUT_FLAG_POSITION); //!< Mask for a flag in the register. + static const uint8_t WAIT_FLAG_MASK = 0xFF xor (1 << WAIT_FLAG_POSITION); //!< Mask for a flag in the register. + static const uint8_t RETRANSMIT_FLAG_MASK = 0xFF xor (1 << RETRANSMIT_FLAG_POSITION); //!< Mask for a flag in the register. + static const uint8_t FARM_B_COUNT_MASK = 0b11111001; //!< Mask for a counter in the register. + /** + * This is the data structure of the CLCW register. + */ + union clcwContent { + uint32_t raw; + struct { + uint8_t status; + uint8_t virtualChannelIdSpare; + uint8_t flags; + uint8_t vRValue; + }; + }; + clcwContent content; //!< Represents the content of the register. +public: + /** + * The constructor sets everything to default values. + */ + Clcw(); + /** + * Nothing happens in the destructor. + */ + ~Clcw(); + void setVirtualChannel( uint8_t setChannel ); + void setLockoutFlag( bool lockout ); + void setWaitFlag( bool waitFlag ); + void setRetransmitFlag( bool retransmitFlag ); + void setFarmBCount( uint8_t count ); + void setReceiverFrameSequenceNumber( uint8_t vR ); + void setRFAvailable( bool rfAvailable ); + void setBitLock( bool bitLock ); + uint32_t getAsWhole(); + void setWhole( uint32_t rawClcw ); + void print(); +}; + +#endif /* CLCW_H_ */ diff --git a/datalinklayer/DataLinkLayer.cpp b/datalinklayer/DataLinkLayer.cpp index 4ca7f270..83fe1e61 100644 --- a/datalinklayer/DataLinkLayer.cpp +++ b/datalinklayer/DataLinkLayer.cpp @@ -1,139 +1,139 @@ -#include -#include -#include - -DataLinkLayer::DataLinkLayer(uint8_t* set_frame_buffer, ClcwIF* setClcw, - uint8_t set_start_sequence_length, uint16_t set_scid) : - spacecraftId(set_scid), frameBuffer(set_frame_buffer), clcw(setClcw), receivedDataLength(0), currentFrame( - NULL), startSequenceLength(set_start_sequence_length) { - //Nothing to do except from setting the values above. -} - -DataLinkLayer::~DataLinkLayer() { - -} - -ReturnValue_t DataLinkLayer::frameDelimitingAndFillRemoval() { - if ((receivedDataLength - startSequenceLength) < FRAME_PRIMARY_HEADER_LENGTH) { - return SHORTER_THAN_HEADER; - } - //Removing start sequence. - //SHOULDDO: Not implemented here. - while ( *frameBuffer == START_SEQUENCE_PATTERN ) { - frameBuffer++; - } - TcTransferFrame frame_candidate(frameBuffer); - this->currentFrame = frame_candidate; //should work with shallow copy. - - return RETURN_OK; -} - -ReturnValue_t DataLinkLayer::frameValidationCheck() { - //Check TF_version number - if (this->currentFrame.getVersionNumber() != FRAME_VERSION_NUMBER_DEFAULT) { - return WRONG_TF_VERSION; - } - //Check SpaceCraft ID - if (this->currentFrame.getSpacecraftId() != this->spacecraftId) { - return WRONG_SPACECRAFT_ID; - } - //Check other header limitations: - if (!this->currentFrame.bypassFlagSet() && this->currentFrame.controlCommandFlagSet()) { - return NO_VALID_FRAME_TYPE; - } - //- Spares are zero - if (!this->currentFrame.spareIsZero()) { - return NO_VALID_FRAME_TYPE; - } - //Compare detected frame length with the one in the header - uint16_t length = currentFrame.getFullSize(); - if (length > receivedDataLength) { - //Frame is too long or just right -// error << "frameValidationCheck: Too short."; -// currentFrame.print(); - return TOO_SHORT; - } - if (USE_CRC) { - return this->frameCheckCRC(); - } - return RETURN_OK; -} - -ReturnValue_t DataLinkLayer::frameCheckCRC() { - uint16_t checkValue = CRC::crc16ccitt(this->currentFrame.getFullFrame(), - this->currentFrame.getFullSize()); - if (checkValue == 0) { - return RETURN_OK; - } else { - return CRC_FAILED; - } - -} - -ReturnValue_t DataLinkLayer::allFramesReception() { - ReturnValue_t status = this->frameDelimitingAndFillRemoval(); - if (status != RETURN_OK) { - return status; - } - return this->frameValidationCheck(); -} - -ReturnValue_t DataLinkLayer::masterChannelDemultiplexing() { - //Nothing to do at present. Ideally, there would be a map of MCID's identifying which MC to use. - return virtualChannelDemultiplexing(); -} - -ReturnValue_t DataLinkLayer::virtualChannelDemultiplexing() { - uint8_t vcId = currentFrame.getVirtualChannelId(); - virtualChannelIterator iter = virtualChannels.find(vcId); - if (iter == virtualChannels.end()) { - //Do not report because passive board will get this error all the time. - return RETURN_OK; - } else { - return (iter->second)->frameAcceptanceAndReportingMechanism(¤tFrame, clcw); - } -} - -ReturnValue_t DataLinkLayer::processFrame(uint16_t length) { - receivedDataLength = length; - ReturnValue_t status = allFramesReception(); - if (status != RETURN_OK) { - sif::error << "DataLinkLayer::processFrame: frame reception failed. " - "Error code: " << std::hex << status << std::dec << std::endl; -// currentFrame.print(); - return status; - } else { - return masterChannelDemultiplexing(); - } -} - -ReturnValue_t DataLinkLayer::addVirtualChannel(uint8_t virtualChannelId, - VirtualChannelReceptionIF* object) { - std::pair returnValue = virtualChannels.insert( - std::pair(virtualChannelId, object)); - if (returnValue.second == true) { - return RETURN_OK; - } else { - return RETURN_FAILED; - } -} - -ReturnValue_t DataLinkLayer::initialize() { - ReturnValue_t returnValue = RETURN_FAILED; - //Set Virtual Channel ID to first virtual channel instance in this DataLinkLayer instance to avoid faulty information (e.g. 0) in the VCID. - if ( virtualChannels.begin() != virtualChannels.end() ) { - clcw->setVirtualChannel( virtualChannels.begin()->second->getChannelId() ); - } else { - sif::error << "DataLinkLayer::initialize: No VC assigned to this DLL instance! " << std::endl; - return RETURN_FAILED; - } - - for (virtualChannelIterator iterator = virtualChannels.begin(); - iterator != virtualChannels.end(); iterator++) { - returnValue = iterator->second->initialize(); - if (returnValue != RETURN_OK) - break; - } - return returnValue; - -} +#include "../datalinklayer/DataLinkLayer.h" +#include "../globalfunctions/CRC.h" +#include "../serviceinterface/ServiceInterfaceStream.h" + +DataLinkLayer::DataLinkLayer(uint8_t* set_frame_buffer, ClcwIF* setClcw, + uint8_t set_start_sequence_length, uint16_t set_scid) : + spacecraftId(set_scid), frameBuffer(set_frame_buffer), clcw(setClcw), receivedDataLength(0), currentFrame( + NULL), startSequenceLength(set_start_sequence_length) { + //Nothing to do except from setting the values above. +} + +DataLinkLayer::~DataLinkLayer() { + +} + +ReturnValue_t DataLinkLayer::frameDelimitingAndFillRemoval() { + if ((receivedDataLength - startSequenceLength) < FRAME_PRIMARY_HEADER_LENGTH) { + return SHORTER_THAN_HEADER; + } + //Removing start sequence. + //SHOULDDO: Not implemented here. + while ( *frameBuffer == START_SEQUENCE_PATTERN ) { + frameBuffer++; + } + TcTransferFrame frame_candidate(frameBuffer); + this->currentFrame = frame_candidate; //should work with shallow copy. + + return RETURN_OK; +} + +ReturnValue_t DataLinkLayer::frameValidationCheck() { + //Check TF_version number + if (this->currentFrame.getVersionNumber() != FRAME_VERSION_NUMBER_DEFAULT) { + return WRONG_TF_VERSION; + } + //Check SpaceCraft ID + if (this->currentFrame.getSpacecraftId() != this->spacecraftId) { + return WRONG_SPACECRAFT_ID; + } + //Check other header limitations: + if (!this->currentFrame.bypassFlagSet() && this->currentFrame.controlCommandFlagSet()) { + return NO_VALID_FRAME_TYPE; + } + //- Spares are zero + if (!this->currentFrame.spareIsZero()) { + return NO_VALID_FRAME_TYPE; + } + //Compare detected frame length with the one in the header + uint16_t length = currentFrame.getFullSize(); + if (length > receivedDataLength) { + //Frame is too long or just right +// error << "frameValidationCheck: Too short."; +// currentFrame.print(); + return TOO_SHORT; + } + if (USE_CRC) { + return this->frameCheckCRC(); + } + return RETURN_OK; +} + +ReturnValue_t DataLinkLayer::frameCheckCRC() { + uint16_t checkValue = CRC::crc16ccitt(this->currentFrame.getFullFrame(), + this->currentFrame.getFullSize()); + if (checkValue == 0) { + return RETURN_OK; + } else { + return CRC_FAILED; + } + +} + +ReturnValue_t DataLinkLayer::allFramesReception() { + ReturnValue_t status = this->frameDelimitingAndFillRemoval(); + if (status != RETURN_OK) { + return status; + } + return this->frameValidationCheck(); +} + +ReturnValue_t DataLinkLayer::masterChannelDemultiplexing() { + //Nothing to do at present. Ideally, there would be a map of MCID's identifying which MC to use. + return virtualChannelDemultiplexing(); +} + +ReturnValue_t DataLinkLayer::virtualChannelDemultiplexing() { + uint8_t vcId = currentFrame.getVirtualChannelId(); + virtualChannelIterator iter = virtualChannels.find(vcId); + if (iter == virtualChannels.end()) { + //Do not report because passive board will get this error all the time. + return RETURN_OK; + } else { + return (iter->second)->frameAcceptanceAndReportingMechanism(¤tFrame, clcw); + } +} + +ReturnValue_t DataLinkLayer::processFrame(uint16_t length) { + receivedDataLength = length; + ReturnValue_t status = allFramesReception(); + if (status != RETURN_OK) { + sif::error << "DataLinkLayer::processFrame: frame reception failed. " + "Error code: " << std::hex << status << std::dec << std::endl; +// currentFrame.print(); + return status; + } else { + return masterChannelDemultiplexing(); + } +} + +ReturnValue_t DataLinkLayer::addVirtualChannel(uint8_t virtualChannelId, + VirtualChannelReceptionIF* object) { + std::pair returnValue = virtualChannels.insert( + std::pair(virtualChannelId, object)); + if (returnValue.second == true) { + return RETURN_OK; + } else { + return RETURN_FAILED; + } +} + +ReturnValue_t DataLinkLayer::initialize() { + ReturnValue_t returnValue = RETURN_FAILED; + //Set Virtual Channel ID to first virtual channel instance in this DataLinkLayer instance to avoid faulty information (e.g. 0) in the VCID. + if ( virtualChannels.begin() != virtualChannels.end() ) { + clcw->setVirtualChannel( virtualChannels.begin()->second->getChannelId() ); + } else { + sif::error << "DataLinkLayer::initialize: No VC assigned to this DLL instance! " << std::endl; + return RETURN_FAILED; + } + + for (virtualChannelIterator iterator = virtualChannels.begin(); + iterator != virtualChannels.end(); iterator++) { + returnValue = iterator->second->initialize(); + if (returnValue != RETURN_OK) + break; + } + return returnValue; + +} diff --git a/datalinklayer/DataLinkLayer.h b/datalinklayer/DataLinkLayer.h index 8a3bb8e5..cf5cf42e 100644 --- a/datalinklayer/DataLinkLayer.h +++ b/datalinklayer/DataLinkLayer.h @@ -1,112 +1,112 @@ -#ifndef DATALINKLAYER_H_ -#define DATALINKLAYER_H_ - -#include -#include -#include -#include -#include -#include - - -class VirtualChannelReception; -/** - * A complete representation of the CCSDS Data Link Layer. - * The operations of this layer are defined in the CCSDS TC Space Data Link Protocol - * document. It is configured to handle a VC Demultiplexing function. All reception - * steps are performed. - */ -class DataLinkLayer : public CCSDSReturnValuesIF { -public: - static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SYSTEM_1; - static const Event RF_AVAILABLE = MAKE_EVENT(0, SEVERITY::INFO); //!< A RF available signal was detected. P1: raw RFA state, P2: 0 - static const Event RF_LOST = MAKE_EVENT(1, SEVERITY::INFO); //!< A previously found RF available signal was lost. P1: raw RFA state, P2: 0 - static const Event BIT_LOCK = MAKE_EVENT(2, SEVERITY::INFO); //!< A Bit Lock signal. Was detected. P1: raw BLO state, P2: 0 - static const Event BIT_LOCK_LOST = MAKE_EVENT(3, SEVERITY::INFO); //!< A previously found Bit Lock signal was lost. P1: raw BLO state, P2: 0 -// static const Event RF_CHAIN_LOST = MAKE_EVENT(4, SEVERITY::INFO); //!< The CCSDS Board detected that either bit lock or RF available or both are lost. No parameters. - static const Event FRAME_PROCESSING_FAILED = MAKE_EVENT(5, SEVERITY::LOW); //!< The CCSDS Board could not interpret a TC - /** - * The Constructor sets the passed parameters and nothing else. - * @param set_frame_buffer The buffer in which incoming frame candidates are stored. - * @param setClcw The CLCW class to work on when returning CLCW information. - * @param set_start_sequence_length Length of the Start sequence in front of every TC Transfer Frame. - * @param set_scid The SCID to operate on. - */ - DataLinkLayer( uint8_t* set_frame_buffer, ClcwIF* setClcw, uint8_t set_start_sequence_length, uint16_t set_scid ); - /** - * Empty virtual destructor. - */ - ~DataLinkLayer(); - /** - * This method tries to process a frame that is placed in #frameBuffer. - * The procedures described in the Standard are performed. - * @param length Length of the incoming frame candidate. - * @return @c RETURN_OK on successful handling, otherwise the return codes of the higher methods. - */ - ReturnValue_t processFrame( uint16_t length ); - /** - * Configuration method to add a new TC Virtual Channel. - * Shall only be called during initialization. As soon as the method was called, the layer can - * handle Frames directed to this VC. - * @param virtualChannelId Id of the VC. Shall be smaller than 64. - * @param object Reference to the object that handles the Frame. - * @return @c RETURN_OK on success, @c RETURN_FAILED otherwise. - */ - ReturnValue_t addVirtualChannel( uint8_t virtualChannelId, VirtualChannelReceptionIF* object ); - /** - * The initialization method calls the @c initialize routine of all virtual channels. - * @return The return code of the first failed VC initialization or @c RETURN_OK. - */ - ReturnValue_t initialize(); -private: - typedef std::map::iterator virtualChannelIterator; //!< Typedef to simplify handling the #virtualChannels map. - static const uint8_t FRAME_VERSION_NUMBER_DEFAULT = 0x00; //!< Constant for the default value of Frame Version Numbers. - static const uint8_t FRAME_PRIMARY_HEADER_LENGTH = 5; //!< Length of the frame's primary header. - static const uint8_t START_SEQUENCE_PATTERN = 0x00; //!< The start sequence pattern which might be with the frame. - static const bool USE_CRC = true; //!< A global, so called "Managed Parameter" that identifies if incoming frames have CRC's or not. - uint16_t spacecraftId; //!< The Space Craft Identifier (SCID) configured. - uint8_t* frameBuffer; //!< A pointer to point to the current incoming frame. - ClcwIF* clcw; //!< Pointer to store the CLCW to work on. - uint16_t receivedDataLength; //!< Stores the length of the currently processed frame. - TcTransferFrame currentFrame; //!< Stores a more convenient access to the current frame. - uint8_t startSequenceLength; //!< Configured length of the start sequence. Maybe this must be done more variable. - std::map virtualChannels; //!< Map of all virtual channels assigned. - /** - * Method that performs all possible frame validity checks (as specified). - * @return Various error codes or @c RETURN_OK on success. - */ - ReturnValue_t frameValidationCheck(); - /** - * First method to call. - * Removes start sequence bytes and checks if the complete frame was received. - * SHOULDDO: Maybe handling the start sequence must be done more variable. - * @return @c RETURN_OK or @c TOO_SHORT. - */ - ReturnValue_t frameDelimitingAndFillRemoval(); - /** - * Small helper method to check the CRC of the Frame. - * @return @c RETURN_OK or @c CRC_FAILED. - */ - ReturnValue_t frameCheckCRC(); - /** - * Method that groups the reception process of all Frames. - * Calls #frameDelimitingAndFillRemoval and #frameValidationCheck. - * @return The return codes of the sub calls. - */ - ReturnValue_t allFramesReception(); - /** - * Dummy method for master channel demultiplexing. - * As there's only one Master Channel here, the method calls #virtualChannelDemultiplexing. - * @return The return codes of #virtualChannelDemultiplexing. - */ - ReturnValue_t masterChannelDemultiplexing(); - /** - * Method to demultiplex the Frames to Virtual Channels (VC's). - * Looks up the requested VC in #virtualChannels and forwards the Frame to its - * #frameAcceptanceAndReportingMechanism method, if found. - * @return The higher method codes or @c VC_NOT_FOUND. - */ - ReturnValue_t virtualChannelDemultiplexing(); -}; - -#endif /* DATALINKLAYER_H_ */ +#ifndef DATALINKLAYER_H_ +#define DATALINKLAYER_H_ + +#include "../datalinklayer/CCSDSReturnValuesIF.h" +#include "../datalinklayer/ClcwIF.h" +#include "../datalinklayer/TcTransferFrame.h" +#include "../datalinklayer/VirtualChannelReceptionIF.h" +#include "../events/Event.h" +#include + + +class VirtualChannelReception; +/** + * A complete representation of the CCSDS Data Link Layer. + * The operations of this layer are defined in the CCSDS TC Space Data Link Protocol + * document. It is configured to handle a VC Demultiplexing function. All reception + * steps are performed. + */ +class DataLinkLayer : public CCSDSReturnValuesIF { +public: + static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SYSTEM_1; + static const Event RF_AVAILABLE = MAKE_EVENT(0, SEVERITY::INFO); //!< A RF available signal was detected. P1: raw RFA state, P2: 0 + static const Event RF_LOST = MAKE_EVENT(1, SEVERITY::INFO); //!< A previously found RF available signal was lost. P1: raw RFA state, P2: 0 + static const Event BIT_LOCK = MAKE_EVENT(2, SEVERITY::INFO); //!< A Bit Lock signal. Was detected. P1: raw BLO state, P2: 0 + static const Event BIT_LOCK_LOST = MAKE_EVENT(3, SEVERITY::INFO); //!< A previously found Bit Lock signal was lost. P1: raw BLO state, P2: 0 +// static const Event RF_CHAIN_LOST = MAKE_EVENT(4, SEVERITY::INFO); //!< The CCSDS Board detected that either bit lock or RF available or both are lost. No parameters. + static const Event FRAME_PROCESSING_FAILED = MAKE_EVENT(5, SEVERITY::LOW); //!< The CCSDS Board could not interpret a TC + /** + * The Constructor sets the passed parameters and nothing else. + * @param set_frame_buffer The buffer in which incoming frame candidates are stored. + * @param setClcw The CLCW class to work on when returning CLCW information. + * @param set_start_sequence_length Length of the Start sequence in front of every TC Transfer Frame. + * @param set_scid The SCID to operate on. + */ + DataLinkLayer( uint8_t* set_frame_buffer, ClcwIF* setClcw, uint8_t set_start_sequence_length, uint16_t set_scid ); + /** + * Empty virtual destructor. + */ + ~DataLinkLayer(); + /** + * This method tries to process a frame that is placed in #frameBuffer. + * The procedures described in the Standard are performed. + * @param length Length of the incoming frame candidate. + * @return @c RETURN_OK on successful handling, otherwise the return codes of the higher methods. + */ + ReturnValue_t processFrame( uint16_t length ); + /** + * Configuration method to add a new TC Virtual Channel. + * Shall only be called during initialization. As soon as the method was called, the layer can + * handle Frames directed to this VC. + * @param virtualChannelId Id of the VC. Shall be smaller than 64. + * @param object Reference to the object that handles the Frame. + * @return @c RETURN_OK on success, @c RETURN_FAILED otherwise. + */ + ReturnValue_t addVirtualChannel( uint8_t virtualChannelId, VirtualChannelReceptionIF* object ); + /** + * The initialization method calls the @c initialize routine of all virtual channels. + * @return The return code of the first failed VC initialization or @c RETURN_OK. + */ + ReturnValue_t initialize(); +private: + typedef std::map::iterator virtualChannelIterator; //!< Typedef to simplify handling the #virtualChannels map. + static const uint8_t FRAME_VERSION_NUMBER_DEFAULT = 0x00; //!< Constant for the default value of Frame Version Numbers. + static const uint8_t FRAME_PRIMARY_HEADER_LENGTH = 5; //!< Length of the frame's primary header. + static const uint8_t START_SEQUENCE_PATTERN = 0x00; //!< The start sequence pattern which might be with the frame. + static const bool USE_CRC = true; //!< A global, so called "Managed Parameter" that identifies if incoming frames have CRC's or not. + uint16_t spacecraftId; //!< The Space Craft Identifier (SCID) configured. + uint8_t* frameBuffer; //!< A pointer to point to the current incoming frame. + ClcwIF* clcw; //!< Pointer to store the CLCW to work on. + uint16_t receivedDataLength; //!< Stores the length of the currently processed frame. + TcTransferFrame currentFrame; //!< Stores a more convenient access to the current frame. + uint8_t startSequenceLength; //!< Configured length of the start sequence. Maybe this must be done more variable. + std::map virtualChannels; //!< Map of all virtual channels assigned. + /** + * Method that performs all possible frame validity checks (as specified). + * @return Various error codes or @c RETURN_OK on success. + */ + ReturnValue_t frameValidationCheck(); + /** + * First method to call. + * Removes start sequence bytes and checks if the complete frame was received. + * SHOULDDO: Maybe handling the start sequence must be done more variable. + * @return @c RETURN_OK or @c TOO_SHORT. + */ + ReturnValue_t frameDelimitingAndFillRemoval(); + /** + * Small helper method to check the CRC of the Frame. + * @return @c RETURN_OK or @c CRC_FAILED. + */ + ReturnValue_t frameCheckCRC(); + /** + * Method that groups the reception process of all Frames. + * Calls #frameDelimitingAndFillRemoval and #frameValidationCheck. + * @return The return codes of the sub calls. + */ + ReturnValue_t allFramesReception(); + /** + * Dummy method for master channel demultiplexing. + * As there's only one Master Channel here, the method calls #virtualChannelDemultiplexing. + * @return The return codes of #virtualChannelDemultiplexing. + */ + ReturnValue_t masterChannelDemultiplexing(); + /** + * Method to demultiplex the Frames to Virtual Channels (VC's). + * Looks up the requested VC in #virtualChannels and forwards the Frame to its + * #frameAcceptanceAndReportingMechanism method, if found. + * @return The higher method codes or @c VC_NOT_FOUND. + */ + ReturnValue_t virtualChannelDemultiplexing(); +}; + +#endif /* DATALINKLAYER_H_ */ diff --git a/datalinklayer/Farm1StateIF.h b/datalinklayer/Farm1StateIF.h index 25836e6a..ef02d891 100644 --- a/datalinklayer/Farm1StateIF.h +++ b/datalinklayer/Farm1StateIF.h @@ -1,54 +1,54 @@ -/** - * @file Farm1StateIF.h - * @brief This file defines the Farm1StateIF class. - * @date 24.04.2013 - * @author baetz - */ - -#ifndef FARM1STATEIF_H_ -#define FARM1STATEIF_H_ - -#include -class VirtualChannelReception; -class TcTransferFrame; -class ClcwIF; - -/** - * This is the interface for states of the FARM-1 state machine. - * Classes implementing this interface can be used as FARM-1 states. This is a simple implementation - * of the state pattern. - */ -class Farm1StateIF : public CCSDSReturnValuesIF { -public: - /** - * A method that shall handle an incoming frame as AD Frame. - * @param frame The frame to handle. - * @param clcw Any changes to the CLCW shall be done with the help of this interface. - * @return If forwarding to a MAP Channel is required, the return value shall be #FRAME_OK. - * Otherwise, an appropriate return value or error code shall be generated. - */ - virtual ReturnValue_t handleADFrame( TcTransferFrame* frame, ClcwIF* clcw ) = 0; - /** - * This method shall handle frames that have been successfully identified as BC Unlock frames. - * @param clcw Any changes to the CLCW shall be done with the help of this interface. - * @return If forwarding to a MAP Channel is required, the return value shall be #FRAME_OK. - * Otherwise, an appropriate return value or error code shall be generated. - */ - virtual ReturnValue_t handleBCUnlockCommand( ClcwIF* clcw ) = 0; - /** - * This method shall handle frames that have been successfully identified as BC Set VR frames. - * @param clcw Any changes to the CLCW shall be done with the help of this interface. - * @param vr The V(r) value found in the frame. - * @return If forwarding to a MAP Channel is required, the return value shall be #FRAME_OK. - * Otherwise, an appropriate return value or error code shall be generated. - */ - virtual ReturnValue_t handleBCSetVrCommand( ClcwIF* clcw, uint8_t vr ) = 0; - /** - * Empty virtual destructor. - */ - virtual ~Farm1StateIF() { - - } -}; - -#endif /* FARM1STATEIF_H_ */ +/** + * @file Farm1StateIF.h + * @brief This file defines the Farm1StateIF class. + * @date 24.04.2013 + * @author baetz + */ + +#ifndef FARM1STATEIF_H_ +#define FARM1STATEIF_H_ + +#include "../datalinklayer/CCSDSReturnValuesIF.h" +class VirtualChannelReception; +class TcTransferFrame; +class ClcwIF; + +/** + * This is the interface for states of the FARM-1 state machine. + * Classes implementing this interface can be used as FARM-1 states. This is a simple implementation + * of the state pattern. + */ +class Farm1StateIF : public CCSDSReturnValuesIF { +public: + /** + * A method that shall handle an incoming frame as AD Frame. + * @param frame The frame to handle. + * @param clcw Any changes to the CLCW shall be done with the help of this interface. + * @return If forwarding to a MAP Channel is required, the return value shall be #FRAME_OK. + * Otherwise, an appropriate return value or error code shall be generated. + */ + virtual ReturnValue_t handleADFrame( TcTransferFrame* frame, ClcwIF* clcw ) = 0; + /** + * This method shall handle frames that have been successfully identified as BC Unlock frames. + * @param clcw Any changes to the CLCW shall be done with the help of this interface. + * @return If forwarding to a MAP Channel is required, the return value shall be #FRAME_OK. + * Otherwise, an appropriate return value or error code shall be generated. + */ + virtual ReturnValue_t handleBCUnlockCommand( ClcwIF* clcw ) = 0; + /** + * This method shall handle frames that have been successfully identified as BC Set VR frames. + * @param clcw Any changes to the CLCW shall be done with the help of this interface. + * @param vr The V(r) value found in the frame. + * @return If forwarding to a MAP Channel is required, the return value shall be #FRAME_OK. + * Otherwise, an appropriate return value or error code shall be generated. + */ + virtual ReturnValue_t handleBCSetVrCommand( ClcwIF* clcw, uint8_t vr ) = 0; + /** + * Empty virtual destructor. + */ + virtual ~Farm1StateIF() { + + } +}; + +#endif /* FARM1STATEIF_H_ */ diff --git a/datalinklayer/Farm1StateLockout.cpp b/datalinklayer/Farm1StateLockout.cpp index 45ae47f9..f8dca9fd 100644 --- a/datalinklayer/Farm1StateLockout.cpp +++ b/datalinklayer/Farm1StateLockout.cpp @@ -1,35 +1,35 @@ -/** - * @file Farm1StateLockout.cpp - * @brief This file defines the Farm1StateLockout class. - * @date 24.04.2013 - * @author baetz - */ - - - -#include -#include -#include -#include -Farm1StateLockout::Farm1StateLockout(VirtualChannelReception* setMyVC) : myVC(setMyVC) { -} - -ReturnValue_t Farm1StateLockout::handleADFrame(TcTransferFrame* frame, - ClcwIF* clcw) { - return FARM_IN_LOCKOUT; -} - -ReturnValue_t Farm1StateLockout::handleBCUnlockCommand(ClcwIF* clcw) { - myVC->farmBCounter++; - clcw->setRetransmitFlag(false); - clcw->setLockoutFlag( false ); - clcw->setWaitFlag( false ); - myVC->currentState = &(myVC->openState); - return BC_IS_UNLOCK_COMMAND; -} - -ReturnValue_t Farm1StateLockout::handleBCSetVrCommand(ClcwIF* clcw, - uint8_t vr) { - myVC->farmBCounter++; - return BC_IS_SET_VR_COMMAND; -} +/** + * @file Farm1StateLockout.cpp + * @brief This file defines the Farm1StateLockout class. + * @date 24.04.2013 + * @author baetz + */ + + + +#include "../datalinklayer/ClcwIF.h" +#include "../datalinklayer/Farm1StateLockout.h" +#include "../datalinklayer/TcTransferFrame.h" +#include "../datalinklayer/VirtualChannelReception.h" +Farm1StateLockout::Farm1StateLockout(VirtualChannelReception* setMyVC) : myVC(setMyVC) { +} + +ReturnValue_t Farm1StateLockout::handleADFrame(TcTransferFrame* frame, + ClcwIF* clcw) { + return FARM_IN_LOCKOUT; +} + +ReturnValue_t Farm1StateLockout::handleBCUnlockCommand(ClcwIF* clcw) { + myVC->farmBCounter++; + clcw->setRetransmitFlag(false); + clcw->setLockoutFlag( false ); + clcw->setWaitFlag( false ); + myVC->currentState = &(myVC->openState); + return BC_IS_UNLOCK_COMMAND; +} + +ReturnValue_t Farm1StateLockout::handleBCSetVrCommand(ClcwIF* clcw, + uint8_t vr) { + myVC->farmBCounter++; + return BC_IS_SET_VR_COMMAND; +} diff --git a/datalinklayer/Farm1StateLockout.h b/datalinklayer/Farm1StateLockout.h index aac8ed74..9e3713cc 100644 --- a/datalinklayer/Farm1StateLockout.h +++ b/datalinklayer/Farm1StateLockout.h @@ -1,59 +1,59 @@ -/** - * @file Farm1StateLockout.h - * @brief This file defines the Farm1StateLockout class. - * @date 24.04.2013 - * @author baetz - */ - -#ifndef FARM1STATELOCKOUT_H_ -#define FARM1STATELOCKOUT_H_ - -#include - -/** - * This class represents the FARM-1 "Lockout" State. - * The Lockout state is reached if the received Transfer Frame Sequence Number is completely wrong - * (i.e. within the Lockout Window). No AD Frames are forwarded. To leave the State, a BC Unlock - * command is required. - */ -class Farm1StateLockout : public Farm1StateIF { -private: - /** - * This is a reference to the "owner" class the State works on. - */ - VirtualChannelReception* myVC; -public: - /** - * The default constructor if the State. - * Sets the "owner" of the State. - * @param setMyVC The "owner" class. - */ - Farm1StateLockout( VirtualChannelReception* setMyVC ); - /** - * All AD Frames are rejected with FARM_IN_LOCKOUT - * @param frame The frame to handle. - * @param clcw Any changes to the CLCW shall be done with the help of this interface. - * @return FARM_IN_LOCKOUT - */ - ReturnValue_t handleADFrame( TcTransferFrame* frame, ClcwIF* clcw ); - /** - * These commands are handled as specified. - * State changes to Farm1StateOpen. - * @param clcw Any changes to the CLCW shall be done with the help of this interface. - * @return As the frame needs no forwarding to a MAP Channel, #BC_IS_UNLOCK_COMMAND - * is returned. - */ - ReturnValue_t handleBCUnlockCommand( ClcwIF* clcw ); - /** - * These commands are handled as specified. - * The V(r) value is not set in Lockout State, even though the Command itself is accepted. - * @param clcw Any changes to the CLCW shall be done with the help of this interface. - * @param vr The V(r) value found in the frame. - * @return As the frame needs no forwarding to a MAP Channel, #BC_IS_SET_VR_COMMAND - * is returned. - */ - ReturnValue_t handleBCSetVrCommand( ClcwIF* clcw, uint8_t vr ); -}; - - -#endif /* FARM1STATELOCKOUT_H_ */ +/** + * @file Farm1StateLockout.h + * @brief This file defines the Farm1StateLockout class. + * @date 24.04.2013 + * @author baetz + */ + +#ifndef FARM1STATELOCKOUT_H_ +#define FARM1STATELOCKOUT_H_ + +#include "../datalinklayer/Farm1StateIF.h" + +/** + * This class represents the FARM-1 "Lockout" State. + * The Lockout state is reached if the received Transfer Frame Sequence Number is completely wrong + * (i.e. within the Lockout Window). No AD Frames are forwarded. To leave the State, a BC Unlock + * command is required. + */ +class Farm1StateLockout : public Farm1StateIF { +private: + /** + * This is a reference to the "owner" class the State works on. + */ + VirtualChannelReception* myVC; +public: + /** + * The default constructor if the State. + * Sets the "owner" of the State. + * @param setMyVC The "owner" class. + */ + Farm1StateLockout( VirtualChannelReception* setMyVC ); + /** + * All AD Frames are rejected with FARM_IN_LOCKOUT + * @param frame The frame to handle. + * @param clcw Any changes to the CLCW shall be done with the help of this interface. + * @return FARM_IN_LOCKOUT + */ + ReturnValue_t handleADFrame( TcTransferFrame* frame, ClcwIF* clcw ); + /** + * These commands are handled as specified. + * State changes to Farm1StateOpen. + * @param clcw Any changes to the CLCW shall be done with the help of this interface. + * @return As the frame needs no forwarding to a MAP Channel, #BC_IS_UNLOCK_COMMAND + * is returned. + */ + ReturnValue_t handleBCUnlockCommand( ClcwIF* clcw ); + /** + * These commands are handled as specified. + * The V(r) value is not set in Lockout State, even though the Command itself is accepted. + * @param clcw Any changes to the CLCW shall be done with the help of this interface. + * @param vr The V(r) value found in the frame. + * @return As the frame needs no forwarding to a MAP Channel, #BC_IS_SET_VR_COMMAND + * is returned. + */ + ReturnValue_t handleBCSetVrCommand( ClcwIF* clcw, uint8_t vr ); +}; + + +#endif /* FARM1STATELOCKOUT_H_ */ diff --git a/datalinklayer/Farm1StateOpen.cpp b/datalinklayer/Farm1StateOpen.cpp index b06cff48..b7837013 100644 --- a/datalinklayer/Farm1StateOpen.cpp +++ b/datalinklayer/Farm1StateOpen.cpp @@ -1,49 +1,49 @@ -/** - * @file Farm1StateOpen.cpp - * @brief This file defines the Farm1StateOpen class. - * @date 24.04.2013 - * @author baetz - */ - - - - -#include -#include -#include -#include - -Farm1StateOpen::Farm1StateOpen(VirtualChannelReception* setMyVC) : myVC(setMyVC) { -} - -ReturnValue_t Farm1StateOpen::handleADFrame(TcTransferFrame* frame, - ClcwIF* clcw) { - int8_t diff = frame->getSequenceNumber() - myVC->vR; - if (diff == 0 ) { - myVC->vR++; - clcw->setRetransmitFlag(false); - return RETURN_OK; - } else if (diff < myVC->positiveWindow && diff > 0 ) { - clcw->setRetransmitFlag(true); - return NS_POSITIVE_W; - } else if (diff < 0 && diff >= -myVC->negativeWindow) { - return NS_NEGATIVE_W; - } else { - clcw->setLockoutFlag(true); - myVC->currentState = &(myVC->lockoutState); - return NS_LOCKOUT; - } -} - -ReturnValue_t Farm1StateOpen::handleBCUnlockCommand( ClcwIF* clcw ) { - myVC->farmBCounter++; - clcw->setRetransmitFlag(false); - return BC_IS_UNLOCK_COMMAND; -} - -ReturnValue_t Farm1StateOpen::handleBCSetVrCommand( ClcwIF* clcw, uint8_t vr ) { - myVC->farmBCounter++; - clcw->setRetransmitFlag(false); - myVC->vR = vr; - return BC_IS_SET_VR_COMMAND; -} +/** + * @file Farm1StateOpen.cpp + * @brief This file defines the Farm1StateOpen class. + * @date 24.04.2013 + * @author baetz + */ + + + + +#include "../datalinklayer/ClcwIF.h" +#include "../datalinklayer/Farm1StateOpen.h" +#include "../datalinklayer/TcTransferFrame.h" +#include "../datalinklayer/VirtualChannelReception.h" + +Farm1StateOpen::Farm1StateOpen(VirtualChannelReception* setMyVC) : myVC(setMyVC) { +} + +ReturnValue_t Farm1StateOpen::handleADFrame(TcTransferFrame* frame, + ClcwIF* clcw) { + int8_t diff = frame->getSequenceNumber() - myVC->vR; + if (diff == 0 ) { + myVC->vR++; + clcw->setRetransmitFlag(false); + return RETURN_OK; + } else if (diff < myVC->positiveWindow && diff > 0 ) { + clcw->setRetransmitFlag(true); + return NS_POSITIVE_W; + } else if (diff < 0 && diff >= -myVC->negativeWindow) { + return NS_NEGATIVE_W; + } else { + clcw->setLockoutFlag(true); + myVC->currentState = &(myVC->lockoutState); + return NS_LOCKOUT; + } +} + +ReturnValue_t Farm1StateOpen::handleBCUnlockCommand( ClcwIF* clcw ) { + myVC->farmBCounter++; + clcw->setRetransmitFlag(false); + return BC_IS_UNLOCK_COMMAND; +} + +ReturnValue_t Farm1StateOpen::handleBCSetVrCommand( ClcwIF* clcw, uint8_t vr ) { + myVC->farmBCounter++; + clcw->setRetransmitFlag(false); + myVC->vR = vr; + return BC_IS_SET_VR_COMMAND; +} diff --git a/datalinklayer/Farm1StateOpen.h b/datalinklayer/Farm1StateOpen.h index 09caacbb..ebc3b333 100644 --- a/datalinklayer/Farm1StateOpen.h +++ b/datalinklayer/Farm1StateOpen.h @@ -1,62 +1,62 @@ -/** - * @file Farm1StateOpen.h - * @brief This file defines the Farm1StateOpen class. - * @date 24.04.2013 - * @author baetz - */ - -#ifndef FARM1STATEOPEN_H_ -#define FARM1STATEOPEN_H_ - -#include - -/** - * This class represents the FARM-1 "Open" State. - * The Open state is the state of normal operation. It handles all types of frames, - * including AD Frames. If a wrong Frame Sequence Number is detected in an AD Frame, the - * State reacts as specified. - */ -class Farm1StateOpen : public Farm1StateIF { -private: - /** - * This is a reference to the "owner" class the State works on. - */ - VirtualChannelReception* myVC; -public: - /** - * The default constructor if the State. - * Sets the "owner" of the State. - * @param setMyVC The "owner" class. - */ - Farm1StateOpen( VirtualChannelReception* setMyVC ); - /** - * Method to check the validity of AD Frames. - * It checks the Frame Sequence Number and reacts as specified in the standard. The state may - * change to Farm1StateLockout. - * @param frame The frame to handle. - * @param clcw Any changes to the CLCW shall be done with the help of this interface. - * @return If the Sequence Number is ok, it returns #RETURN_OK. Otherwise either #NS_POSITIVE_W, - * #NS_NEGATIVE_W or NS_LOCKOUT is returned. - */ - ReturnValue_t handleADFrame( TcTransferFrame* frame, ClcwIF* clcw ); - /** - * These commands are handled as specified. - * State does not change. - * @param clcw Any changes to the CLCW shall be done with the help of this interface. - * @return As the frame needs no forwarding to a MAP Channel, #BC_IS_UNLOCK_COMMAND - * is returned. - */ - ReturnValue_t handleBCUnlockCommand( ClcwIF* clcw ); - /** - * These commands are handled as specified. - * State does not change. - * @param clcw Any changes to the CLCW shall be done with the help of this interface. - * @param vr The V(r) value found in the frame. - * @return As the frame needs no forwarding to a MAP Channel, #BC_IS_SET_VR_COMMAND - * is returned. - */ - ReturnValue_t handleBCSetVrCommand( ClcwIF* clcw, uint8_t vr ); -}; - - -#endif /* FARM1STATEOPEN_H_ */ +/** + * @file Farm1StateOpen.h + * @brief This file defines the Farm1StateOpen class. + * @date 24.04.2013 + * @author baetz + */ + +#ifndef FARM1STATEOPEN_H_ +#define FARM1STATEOPEN_H_ + +#include "../datalinklayer/Farm1StateIF.h" + +/** + * This class represents the FARM-1 "Open" State. + * The Open state is the state of normal operation. It handles all types of frames, + * including AD Frames. If a wrong Frame Sequence Number is detected in an AD Frame, the + * State reacts as specified. + */ +class Farm1StateOpen : public Farm1StateIF { +private: + /** + * This is a reference to the "owner" class the State works on. + */ + VirtualChannelReception* myVC; +public: + /** + * The default constructor if the State. + * Sets the "owner" of the State. + * @param setMyVC The "owner" class. + */ + Farm1StateOpen( VirtualChannelReception* setMyVC ); + /** + * Method to check the validity of AD Frames. + * It checks the Frame Sequence Number and reacts as specified in the standard. The state may + * change to Farm1StateLockout. + * @param frame The frame to handle. + * @param clcw Any changes to the CLCW shall be done with the help of this interface. + * @return If the Sequence Number is ok, it returns #RETURN_OK. Otherwise either #NS_POSITIVE_W, + * #NS_NEGATIVE_W or NS_LOCKOUT is returned. + */ + ReturnValue_t handleADFrame( TcTransferFrame* frame, ClcwIF* clcw ); + /** + * These commands are handled as specified. + * State does not change. + * @param clcw Any changes to the CLCW shall be done with the help of this interface. + * @return As the frame needs no forwarding to a MAP Channel, #BC_IS_UNLOCK_COMMAND + * is returned. + */ + ReturnValue_t handleBCUnlockCommand( ClcwIF* clcw ); + /** + * These commands are handled as specified. + * State does not change. + * @param clcw Any changes to the CLCW shall be done with the help of this interface. + * @param vr The V(r) value found in the frame. + * @return As the frame needs no forwarding to a MAP Channel, #BC_IS_SET_VR_COMMAND + * is returned. + */ + ReturnValue_t handleBCSetVrCommand( ClcwIF* clcw, uint8_t vr ); +}; + + +#endif /* FARM1STATEOPEN_H_ */ diff --git a/datalinklayer/Farm1StateWait.cpp b/datalinklayer/Farm1StateWait.cpp index 1c72e68f..c3cc85de 100644 --- a/datalinklayer/Farm1StateWait.cpp +++ b/datalinklayer/Farm1StateWait.cpp @@ -1,43 +1,43 @@ -/** - * @file Farm1StateWait.cpp - * @brief This file defines the Farm1StateWait class. - * @date 24.04.2013 - * @author baetz - */ - - -#include -#include -#include -#include - -Farm1StateWait::Farm1StateWait(VirtualChannelReception* setMyVC) : myVC(setMyVC) { -} - -ReturnValue_t Farm1StateWait::handleADFrame(TcTransferFrame* frame, - ClcwIF* clcw) { - - int8_t diff = frame->getSequenceNumber() - myVC->vR; - if ( diff < -myVC->negativeWindow || diff >= myVC->positiveWindow ) { - clcw->setLockoutFlag(true); - myVC->currentState = &(myVC->lockoutState); - } - return FARM_IN_WAIT; -} - -ReturnValue_t Farm1StateWait::handleBCUnlockCommand(ClcwIF* clcw) { - myVC->farmBCounter++; - clcw->setRetransmitFlag(false); - clcw->setWaitFlag( false ); - myVC->currentState = &(myVC->openState); - return BC_IS_UNLOCK_COMMAND; -} - -ReturnValue_t Farm1StateWait::handleBCSetVrCommand(ClcwIF* clcw, uint8_t vr) { - myVC->farmBCounter++; - clcw->setWaitFlag( false ); - clcw->setRetransmitFlag(false); - myVC->vR = vr; - myVC->currentState = &(myVC->openState); - return BC_IS_SET_VR_COMMAND; -} +/** + * @file Farm1StateWait.cpp + * @brief This file defines the Farm1StateWait class. + * @date 24.04.2013 + * @author baetz + */ + + +#include "../datalinklayer/ClcwIF.h" +#include "../datalinklayer/Farm1StateWait.h" +#include "../datalinklayer/TcTransferFrame.h" +#include "../datalinklayer/VirtualChannelReception.h" + +Farm1StateWait::Farm1StateWait(VirtualChannelReception* setMyVC) : myVC(setMyVC) { +} + +ReturnValue_t Farm1StateWait::handleADFrame(TcTransferFrame* frame, + ClcwIF* clcw) { + + int8_t diff = frame->getSequenceNumber() - myVC->vR; + if ( diff < -myVC->negativeWindow || diff >= myVC->positiveWindow ) { + clcw->setLockoutFlag(true); + myVC->currentState = &(myVC->lockoutState); + } + return FARM_IN_WAIT; +} + +ReturnValue_t Farm1StateWait::handleBCUnlockCommand(ClcwIF* clcw) { + myVC->farmBCounter++; + clcw->setRetransmitFlag(false); + clcw->setWaitFlag( false ); + myVC->currentState = &(myVC->openState); + return BC_IS_UNLOCK_COMMAND; +} + +ReturnValue_t Farm1StateWait::handleBCSetVrCommand(ClcwIF* clcw, uint8_t vr) { + myVC->farmBCounter++; + clcw->setWaitFlag( false ); + clcw->setRetransmitFlag(false); + myVC->vR = vr; + myVC->currentState = &(myVC->openState); + return BC_IS_SET_VR_COMMAND; +} diff --git a/datalinklayer/Farm1StateWait.h b/datalinklayer/Farm1StateWait.h index f1201791..aa456664 100644 --- a/datalinklayer/Farm1StateWait.h +++ b/datalinklayer/Farm1StateWait.h @@ -1,58 +1,58 @@ -/** - * @file Farm1StateWait.h - * @brief This file defines the Farm1StateWait class. - * @date 24.04.2013 - * @author baetz - */ - -#ifndef FARM1STATEWAIT_H_ -#define FARM1STATEWAIT_H_ - -#include - -/** - * This class represents the FARM-1 "Wait" State. - * The Wait state is reached if higher level procedures inform the FARM-1 Machine to wait - * for a certain period. Currently, it is not in use. - */ -class Farm1StateWait : public Farm1StateIF { -private: - /** - * This is a reference to the "owner" class the State works on. - */ - VirtualChannelReception* myVC; -public: - /** - * The default constructor if the State. - * Sets the "owner" of the State. - * @param setMyVC The "owner" class. - */ - Farm1StateWait( VirtualChannelReception* setMyVC ); - /** - * AD Frames are always discarded. - * If the frame number is in the lockout window, the state changes to Farm1StateLockout. - * @param frame The frame to handle. - * @param clcw Any changes to the CLCW shall be done with the help of this interface. - * @return Always returns FARM_IN_WAIT. - */ - ReturnValue_t handleADFrame( TcTransferFrame* frame, ClcwIF* clcw ); - /** - * These commands are handled as specified. - * State changes to Farm1StateOpen. - * @param clcw Any changes to the CLCW shall be done with the help of this interface. - * @return As the frame needs no forwarding to a MAP Channel, #BC_IS_UNLOCK_COMMAND - * is returned. - */ - ReturnValue_t handleBCUnlockCommand( ClcwIF* clcw ); - /** - * These commands are handled as specified. - * @param clcw Any changes to the CLCW shall be done with the help of this interface. - * @param vr The V(r) value found in the frame. - * @return As the frame needs no forwarding to a MAP Channel, #BC_IS_SET_VR_COMMAND - * is returned. - */ - ReturnValue_t handleBCSetVrCommand( ClcwIF* clcw, uint8_t vr ); -}; - - -#endif /* FARM1STATEWAIT_H_ */ +/** + * @file Farm1StateWait.h + * @brief This file defines the Farm1StateWait class. + * @date 24.04.2013 + * @author baetz + */ + +#ifndef FARM1STATEWAIT_H_ +#define FARM1STATEWAIT_H_ + +#include "../datalinklayer/Farm1StateIF.h" + +/** + * This class represents the FARM-1 "Wait" State. + * The Wait state is reached if higher level procedures inform the FARM-1 Machine to wait + * for a certain period. Currently, it is not in use. + */ +class Farm1StateWait : public Farm1StateIF { +private: + /** + * This is a reference to the "owner" class the State works on. + */ + VirtualChannelReception* myVC; +public: + /** + * The default constructor if the State. + * Sets the "owner" of the State. + * @param setMyVC The "owner" class. + */ + Farm1StateWait( VirtualChannelReception* setMyVC ); + /** + * AD Frames are always discarded. + * If the frame number is in the lockout window, the state changes to Farm1StateLockout. + * @param frame The frame to handle. + * @param clcw Any changes to the CLCW shall be done with the help of this interface. + * @return Always returns FARM_IN_WAIT. + */ + ReturnValue_t handleADFrame( TcTransferFrame* frame, ClcwIF* clcw ); + /** + * These commands are handled as specified. + * State changes to Farm1StateOpen. + * @param clcw Any changes to the CLCW shall be done with the help of this interface. + * @return As the frame needs no forwarding to a MAP Channel, #BC_IS_UNLOCK_COMMAND + * is returned. + */ + ReturnValue_t handleBCUnlockCommand( ClcwIF* clcw ); + /** + * These commands are handled as specified. + * @param clcw Any changes to the CLCW shall be done with the help of this interface. + * @param vr The V(r) value found in the frame. + * @return As the frame needs no forwarding to a MAP Channel, #BC_IS_SET_VR_COMMAND + * is returned. + */ + ReturnValue_t handleBCSetVrCommand( ClcwIF* clcw, uint8_t vr ); +}; + + +#endif /* FARM1STATEWAIT_H_ */ diff --git a/datalinklayer/MapPacketExtraction.cpp b/datalinklayer/MapPacketExtraction.cpp index 4ea45e89..a14bcefe 100644 --- a/datalinklayer/MapPacketExtraction.cpp +++ b/datalinklayer/MapPacketExtraction.cpp @@ -1,154 +1,154 @@ -/** - * @file MapPacketExtraction.cpp - * @brief This file defines the MapPacketExtraction class. - * @date 26.03.2013 - * @author baetz - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -MapPacketExtraction::MapPacketExtraction(uint8_t setMapId, - object_id_t setPacketDestination) : - lastSegmentationFlag(NO_SEGMENTATION), mapId(setMapId), packetLength(0), - bufferPosition(packetBuffer), packetDestination(setPacketDestination), - packetStore(nullptr), tcQueueId(MessageQueueMessageIF::NO_QUEUE) { - memset(packetBuffer, 0, sizeof(packetBuffer)); -} - -ReturnValue_t MapPacketExtraction::extractPackets(TcTransferFrame* frame) { - uint8_t segmentationFlag = frame->getSequenceFlags(); - ReturnValue_t status = TOO_SHORT_MAP_EXTRACTION; - switch (segmentationFlag) { - case NO_SEGMENTATION: - status = unpackBlockingPackets(frame); - break; - case FIRST_PORTION: - packetLength = frame->getDataLength(); - if (packetLength <= MAX_PACKET_SIZE) { - memcpy(packetBuffer, frame->getDataField(), packetLength); - bufferPosition = &packetBuffer[packetLength]; - status = RETURN_OK; - } else { - sif::error - << "MapPacketExtraction::extractPackets. Packet too large! Size: " - << packetLength << std::endl; - clearBuffers(); - status = CONTENT_TOO_LARGE; - } - break; - case CONTINUING_PORTION: - case LAST_PORTION: - if (lastSegmentationFlag == FIRST_PORTION - || lastSegmentationFlag == CONTINUING_PORTION) { - packetLength += frame->getDataLength(); - if (packetLength <= MAX_PACKET_SIZE) { - memcpy(bufferPosition, frame->getDataField(), - frame->getDataLength()); - bufferPosition = &packetBuffer[packetLength]; - if (segmentationFlag == LAST_PORTION) { - status = sendCompletePacket(packetBuffer, packetLength); - clearBuffers(); - } - status = RETURN_OK; - } else { - sif::error - << "MapPacketExtraction::extractPackets. Packet too large! Size: " - << packetLength << std::endl; - clearBuffers(); - status = CONTENT_TOO_LARGE; - } - } else { - sif::error - << "MapPacketExtraction::extractPackets. Illegal segment! Last flag: " - << (int) lastSegmentationFlag << std::endl; - clearBuffers(); - status = ILLEGAL_SEGMENTATION_FLAG; - } - break; - default: - sif::error - << "MapPacketExtraction::extractPackets. Illegal segmentationFlag: " - << (int) segmentationFlag << std::endl; - clearBuffers(); - status = DATA_CORRUPTED; - break; - } - lastSegmentationFlag = segmentationFlag; - return status; -} - -ReturnValue_t MapPacketExtraction::unpackBlockingPackets( - TcTransferFrame* frame) { - ReturnValue_t status = TOO_SHORT_BLOCKED_PACKET; - uint32_t totalLength = frame->getDataLength(); - if (totalLength > MAX_PACKET_SIZE) - return CONTENT_TOO_LARGE; - uint8_t* position = frame->getDataField(); - while ((totalLength > SpacePacketBase::MINIMUM_SIZE)) { - SpacePacketBase packet(position); - uint32_t packetSize = packet.getFullSize(); - if (packetSize <= totalLength) { - status = sendCompletePacket(packet.getWholeData(), - packet.getFullSize()); - totalLength -= packet.getFullSize(); - position += packet.getFullSize(); - status = RETURN_OK; - } else { - status = DATA_CORRUPTED; - totalLength = 0; - } - } - if (totalLength > 0) { - status = RESIDUAL_DATA; - } - return status; -} - -ReturnValue_t MapPacketExtraction::sendCompletePacket(uint8_t* data, - uint32_t size) { - store_address_t store_id; - ReturnValue_t status = this->packetStore->addData(&store_id, data, size); - if (status == RETURN_OK) { - TmTcMessage message(store_id); - status = MessageQueueSenderIF::sendMessage(tcQueueId,&message); - } - return status; -} - -void MapPacketExtraction::clearBuffers() { - memset(packetBuffer, 0, sizeof(packetBuffer)); - bufferPosition = packetBuffer; - packetLength = 0; - lastSegmentationFlag = NO_SEGMENTATION; -} - -ReturnValue_t MapPacketExtraction::initialize() { - packetStore = objectManager->get(objects::TC_STORE); - AcceptsTelecommandsIF* distributor = objectManager->get< - AcceptsTelecommandsIF>(packetDestination); - if ((packetStore != NULL) && (distributor != NULL)) { - tcQueueId = distributor->getRequestQueue(); - return RETURN_OK; - } else { - return RETURN_FAILED; - } -} - -void MapPacketExtraction::printPacketBuffer(void) { - sif::debug << "DLL: packet_buffer contains: " << std::endl; - for (uint32_t i = 0; i < this->packetLength; ++i) { - sif::debug << "packet_buffer[" << std::dec << i << "]: 0x" << std::hex - << (uint16_t) this->packetBuffer[i] << std::endl; - } -} - -uint8_t MapPacketExtraction::getMapId() const { - return mapId; -} +/** + * @file MapPacketExtraction.cpp + * @brief This file defines the MapPacketExtraction class. + * @date 26.03.2013 + * @author baetz + */ + +#include "../datalinklayer/MapPacketExtraction.h" +#include "../ipc/QueueFactory.h" +#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../storagemanager/StorageManagerIF.h" +#include "../tmtcpacket/SpacePacketBase.h" +#include "../tmtcservices/AcceptsTelecommandsIF.h" +#include "../tmtcservices/TmTcMessage.h" +#include + +MapPacketExtraction::MapPacketExtraction(uint8_t setMapId, + object_id_t setPacketDestination) : + lastSegmentationFlag(NO_SEGMENTATION), mapId(setMapId), packetLength(0), + bufferPosition(packetBuffer), packetDestination(setPacketDestination), + packetStore(nullptr), tcQueueId(MessageQueueMessageIF::NO_QUEUE) { + memset(packetBuffer, 0, sizeof(packetBuffer)); +} + +ReturnValue_t MapPacketExtraction::extractPackets(TcTransferFrame* frame) { + uint8_t segmentationFlag = frame->getSequenceFlags(); + ReturnValue_t status = TOO_SHORT_MAP_EXTRACTION; + switch (segmentationFlag) { + case NO_SEGMENTATION: + status = unpackBlockingPackets(frame); + break; + case FIRST_PORTION: + packetLength = frame->getDataLength(); + if (packetLength <= MAX_PACKET_SIZE) { + memcpy(packetBuffer, frame->getDataField(), packetLength); + bufferPosition = &packetBuffer[packetLength]; + status = RETURN_OK; + } else { + sif::error + << "MapPacketExtraction::extractPackets. Packet too large! Size: " + << packetLength << std::endl; + clearBuffers(); + status = CONTENT_TOO_LARGE; + } + break; + case CONTINUING_PORTION: + case LAST_PORTION: + if (lastSegmentationFlag == FIRST_PORTION + || lastSegmentationFlag == CONTINUING_PORTION) { + packetLength += frame->getDataLength(); + if (packetLength <= MAX_PACKET_SIZE) { + memcpy(bufferPosition, frame->getDataField(), + frame->getDataLength()); + bufferPosition = &packetBuffer[packetLength]; + if (segmentationFlag == LAST_PORTION) { + status = sendCompletePacket(packetBuffer, packetLength); + clearBuffers(); + } + status = RETURN_OK; + } else { + sif::error + << "MapPacketExtraction::extractPackets. Packet too large! Size: " + << packetLength << std::endl; + clearBuffers(); + status = CONTENT_TOO_LARGE; + } + } else { + sif::error + << "MapPacketExtraction::extractPackets. Illegal segment! Last flag: " + << (int) lastSegmentationFlag << std::endl; + clearBuffers(); + status = ILLEGAL_SEGMENTATION_FLAG; + } + break; + default: + sif::error + << "MapPacketExtraction::extractPackets. Illegal segmentationFlag: " + << (int) segmentationFlag << std::endl; + clearBuffers(); + status = DATA_CORRUPTED; + break; + } + lastSegmentationFlag = segmentationFlag; + return status; +} + +ReturnValue_t MapPacketExtraction::unpackBlockingPackets( + TcTransferFrame* frame) { + ReturnValue_t status = TOO_SHORT_BLOCKED_PACKET; + uint32_t totalLength = frame->getDataLength(); + if (totalLength > MAX_PACKET_SIZE) + return CONTENT_TOO_LARGE; + uint8_t* position = frame->getDataField(); + while ((totalLength > SpacePacketBase::MINIMUM_SIZE)) { + SpacePacketBase packet(position); + uint32_t packetSize = packet.getFullSize(); + if (packetSize <= totalLength) { + status = sendCompletePacket(packet.getWholeData(), + packet.getFullSize()); + totalLength -= packet.getFullSize(); + position += packet.getFullSize(); + status = RETURN_OK; + } else { + status = DATA_CORRUPTED; + totalLength = 0; + } + } + if (totalLength > 0) { + status = RESIDUAL_DATA; + } + return status; +} + +ReturnValue_t MapPacketExtraction::sendCompletePacket(uint8_t* data, + uint32_t size) { + store_address_t store_id; + ReturnValue_t status = this->packetStore->addData(&store_id, data, size); + if (status == RETURN_OK) { + TmTcMessage message(store_id); + status = MessageQueueSenderIF::sendMessage(tcQueueId,&message); + } + return status; +} + +void MapPacketExtraction::clearBuffers() { + memset(packetBuffer, 0, sizeof(packetBuffer)); + bufferPosition = packetBuffer; + packetLength = 0; + lastSegmentationFlag = NO_SEGMENTATION; +} + +ReturnValue_t MapPacketExtraction::initialize() { + packetStore = objectManager->get(objects::TC_STORE); + AcceptsTelecommandsIF* distributor = objectManager->get< + AcceptsTelecommandsIF>(packetDestination); + if ((packetStore != NULL) && (distributor != NULL)) { + tcQueueId = distributor->getRequestQueue(); + return RETURN_OK; + } else { + return RETURN_FAILED; + } +} + +void MapPacketExtraction::printPacketBuffer(void) { + sif::debug << "DLL: packet_buffer contains: " << std::endl; + for (uint32_t i = 0; i < this->packetLength; ++i) { + sif::debug << "packet_buffer[" << std::dec << i << "]: 0x" << std::hex + << (uint16_t) this->packetBuffer[i] << std::endl; + } +} + +uint8_t MapPacketExtraction::getMapId() const { + return mapId; +} diff --git a/datalinklayer/MapPacketExtraction.h b/datalinklayer/MapPacketExtraction.h index 5a32366c..cb09c27f 100644 --- a/datalinklayer/MapPacketExtraction.h +++ b/datalinklayer/MapPacketExtraction.h @@ -1,78 +1,78 @@ -/** - * @file MapPacketExtraction.h - * @brief This file defines the MapPacketExtraction class. - * @date 26.03.2013 - * @author baetz - */ - -#ifndef MAPPACKETEXTRACTION_H_ -#define MAPPACKETEXTRACTION_H_ - -#include -#include -#include -#include - -class StorageManagerIF; - -/** - * Implementation of a MAP Packet Extraction class. - * The class implements the full MAP Packet Extraction functionality as described in the CCSDS - * TC Space Data Link Protocol. It internally stores incomplete segmented packets until they are - * fully received. All found packets are forwarded to a single distribution entity. - */ -class MapPacketExtraction: public MapPacketExtractionIF { -private: - static const uint32_t MAX_PACKET_SIZE = 4096; - uint8_t lastSegmentationFlag; //!< The segmentation flag of the last received frame. - uint8_t mapId; //!< MAP ID of this MAP Channel. - uint32_t packetLength; //!< Complete length of the current Space Packet. - uint8_t* bufferPosition; //!< Position to write to in the internal Packet buffer. - uint8_t packetBuffer[MAX_PACKET_SIZE]; //!< The internal Space Packet Buffer. - object_id_t packetDestination; - StorageManagerIF* packetStore; //!< Pointer to the store where full TC packets are stored. - MessageQueueId_t tcQueueId; //!< QueueId to send found packets to the distributor. - /** - * Debug method to print the packet Buffer's content. - */ - void printPacketBuffer(); - /** - * Method that is called if the segmentation flag is @c NO_SEGMENTATION. - * The method extracts one or more packets within the frame and forwards them to the OBSW. - * @param frame The TC Transfer Frame to work on. - * @return @c RETURN_OK if all Packets were extracted. If something is entirely wrong, - * @c DATA_CORRUPTED is returned, if some bytes are left over @c RESIDUAL_DATA. - */ - ReturnValue_t unpackBlockingPackets(TcTransferFrame* frame); - /** - * Helper method to forward a complete packet to the OBSW. - * @param data Pointer to the data, either directly from the frame or from the packetBuffer. - * @param size Complete total size of the packet. - * @return Return Code of the Packet Store or the Message Queue. - */ - ReturnValue_t sendCompletePacket( uint8_t* data, uint32_t size ); - /** - * Helper method to reset the internal buffer. - */ - void clearBuffers(); -public: - /** - * Default constructor. - * Members are set to default values. - * @param setMapId The MAP ID of the instance. - */ - MapPacketExtraction( uint8_t setMapId, object_id_t setPacketDestination ); - ReturnValue_t extractPackets(TcTransferFrame* frame); - /** - * The #packetStore and the default destination of #tcQueue are initialized here. - * @return @c RETURN_OK on success, @c RETURN_FAILED otherwise. - */ - ReturnValue_t initialize(); - /** - * Getter. - * @return The MAP ID of this instance. - */ - uint8_t getMapId() const; -}; - -#endif /* MAPPACKETEXTRACTION_H_ */ +/** + * @file MapPacketExtraction.h + * @brief This file defines the MapPacketExtraction class. + * @date 26.03.2013 + * @author baetz + */ + +#ifndef MAPPACKETEXTRACTION_H_ +#define MAPPACKETEXTRACTION_H_ + +#include "../datalinklayer/MapPacketExtractionIF.h" +#include "../objectmanager/ObjectManagerIF.h" +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../ipc/MessageQueueSenderIF.h" + +class StorageManagerIF; + +/** + * Implementation of a MAP Packet Extraction class. + * The class implements the full MAP Packet Extraction functionality as described in the CCSDS + * TC Space Data Link Protocol. It internally stores incomplete segmented packets until they are + * fully received. All found packets are forwarded to a single distribution entity. + */ +class MapPacketExtraction: public MapPacketExtractionIF { +private: + static const uint32_t MAX_PACKET_SIZE = 4096; + uint8_t lastSegmentationFlag; //!< The segmentation flag of the last received frame. + uint8_t mapId; //!< MAP ID of this MAP Channel. + uint32_t packetLength; //!< Complete length of the current Space Packet. + uint8_t* bufferPosition; //!< Position to write to in the internal Packet buffer. + uint8_t packetBuffer[MAX_PACKET_SIZE]; //!< The internal Space Packet Buffer. + object_id_t packetDestination; + StorageManagerIF* packetStore; //!< Pointer to the store where full TC packets are stored. + MessageQueueId_t tcQueueId; //!< QueueId to send found packets to the distributor. + /** + * Debug method to print the packet Buffer's content. + */ + void printPacketBuffer(); + /** + * Method that is called if the segmentation flag is @c NO_SEGMENTATION. + * The method extracts one or more packets within the frame and forwards them to the OBSW. + * @param frame The TC Transfer Frame to work on. + * @return @c RETURN_OK if all Packets were extracted. If something is entirely wrong, + * @c DATA_CORRUPTED is returned, if some bytes are left over @c RESIDUAL_DATA. + */ + ReturnValue_t unpackBlockingPackets(TcTransferFrame* frame); + /** + * Helper method to forward a complete packet to the OBSW. + * @param data Pointer to the data, either directly from the frame or from the packetBuffer. + * @param size Complete total size of the packet. + * @return Return Code of the Packet Store or the Message Queue. + */ + ReturnValue_t sendCompletePacket( uint8_t* data, uint32_t size ); + /** + * Helper method to reset the internal buffer. + */ + void clearBuffers(); +public: + /** + * Default constructor. + * Members are set to default values. + * @param setMapId The MAP ID of the instance. + */ + MapPacketExtraction( uint8_t setMapId, object_id_t setPacketDestination ); + ReturnValue_t extractPackets(TcTransferFrame* frame); + /** + * The #packetStore and the default destination of #tcQueue are initialized here. + * @return @c RETURN_OK on success, @c RETURN_FAILED otherwise. + */ + ReturnValue_t initialize(); + /** + * Getter. + * @return The MAP ID of this instance. + */ + uint8_t getMapId() const; +}; + +#endif /* MAPPACKETEXTRACTION_H_ */ diff --git a/datalinklayer/MapPacketExtractionIF.h b/datalinklayer/MapPacketExtractionIF.h index 802a893d..d66831de 100644 --- a/datalinklayer/MapPacketExtractionIF.h +++ b/datalinklayer/MapPacketExtractionIF.h @@ -1,47 +1,47 @@ -/** - * @file MapPacketExtractionIF.h - * @brief This file defines the MapPacketExtractionIF class. - * @date 25.03.2013 - * @author baetz - */ - -#ifndef MAPPACKETEXTRACTIONIF_H_ -#define MAPPACKETEXTRACTIONIF_H_ - -#include -#include - -/** - * This is the interface for MAP Packet Extraction classes. - * All classes implementing this interface shall be able to extract blocked or segmented Space - * Packets on a certain MAP channel. This is done in accordance with the CCSDS TC Space Data Link - * Protocol. - */ -class MapPacketExtractionIF : public CCSDSReturnValuesIF { -protected: - static const uint8_t FIRST_PORTION = 0b01; //!< Identification of the first part of a segmented Packet. - static const uint8_t CONTINUING_PORTION = 0b00; //!< Identification of a continuing part of segmented Packets. - static const uint8_t LAST_PORTION = 0b10; //!< The last portion of a segmented Packet. - static const uint8_t NO_SEGMENTATION = 0b11; //!< A Frame without segmentation but maybe with blocking. -public: - /** - * Empty virtual destructor. - */ - virtual ~MapPacketExtractionIF() { - } - /** - * Method to call to handle a single Transfer Frame. - * The method tries to extract Packets from the frame as stated in the Standard. - * @param frame - * @return - */ - virtual ReturnValue_t extractPackets( TcTransferFrame* frame ) = 0; - /** - * Any post-instantiation initialization shall be done in this method. - * @return - */ - virtual ReturnValue_t initialize() = 0; -}; - - -#endif /* MAPPACKETEXTRACTIONIF_H_ */ +/** + * @file MapPacketExtractionIF.h + * @brief This file defines the MapPacketExtractionIF class. + * @date 25.03.2013 + * @author baetz + */ + +#ifndef MAPPACKETEXTRACTIONIF_H_ +#define MAPPACKETEXTRACTIONIF_H_ + +#include "../datalinklayer/CCSDSReturnValuesIF.h" +#include "../datalinklayer/TcTransferFrame.h" + +/** + * This is the interface for MAP Packet Extraction classes. + * All classes implementing this interface shall be able to extract blocked or segmented Space + * Packets on a certain MAP channel. This is done in accordance with the CCSDS TC Space Data Link + * Protocol. + */ +class MapPacketExtractionIF : public CCSDSReturnValuesIF { +protected: + static const uint8_t FIRST_PORTION = 0b01; //!< Identification of the first part of a segmented Packet. + static const uint8_t CONTINUING_PORTION = 0b00; //!< Identification of a continuing part of segmented Packets. + static const uint8_t LAST_PORTION = 0b10; //!< The last portion of a segmented Packet. + static const uint8_t NO_SEGMENTATION = 0b11; //!< A Frame without segmentation but maybe with blocking. +public: + /** + * Empty virtual destructor. + */ + virtual ~MapPacketExtractionIF() { + } + /** + * Method to call to handle a single Transfer Frame. + * The method tries to extract Packets from the frame as stated in the Standard. + * @param frame + * @return + */ + virtual ReturnValue_t extractPackets( TcTransferFrame* frame ) = 0; + /** + * Any post-instantiation initialization shall be done in this method. + * @return + */ + virtual ReturnValue_t initialize() = 0; +}; + + +#endif /* MAPPACKETEXTRACTIONIF_H_ */ diff --git a/datalinklayer/TcTransferFrame.cpp b/datalinklayer/TcTransferFrame.cpp index 30398e9b..8a3e1d76 100644 --- a/datalinklayer/TcTransferFrame.cpp +++ b/datalinklayer/TcTransferFrame.cpp @@ -1,102 +1,102 @@ -/** - * @file TcTransferFrame.cpp - * @brief This file defines the TcTransferFrame class. - * @date 27.04.2013 - * @author baetz - */ - - - -#include -#include - -TcTransferFrame::TcTransferFrame() { - frame = NULL; -} - -TcTransferFrame::TcTransferFrame(uint8_t* setData) { - this->frame = (tc_transfer_frame*)setData; -} - -uint8_t TcTransferFrame::getVersionNumber() { - return (this->frame->header.flagsAndScid & 0b11000000) >> 6; -} - -bool TcTransferFrame::bypassFlagSet() { - return (this->frame->header.flagsAndScid & 0b00100000) != 0; -} - -bool TcTransferFrame::controlCommandFlagSet() { - return (this->frame->header.flagsAndScid & 0b00010000) != 0; -} - -bool TcTransferFrame::spareIsZero() { - return ( (this->frame->header.flagsAndScid & 0b00001100) == 0 ); -} - -uint16_t TcTransferFrame::getSpacecraftId() { - return ( (this->frame->header.flagsAndScid & 0b00000011) << 8 ) + this->frame->header.spacecraftId_l; -} - -uint8_t TcTransferFrame::getVirtualChannelId() { - return (this->frame->header.vcidAndLength_h & 0b11111100) >> 2; -} - -uint16_t TcTransferFrame::getFrameLength() { - return ( (this->frame->header.vcidAndLength_h & 0b00000011) << 8 ) + this->frame->header.length_l; -} - -uint16_t TcTransferFrame::getDataLength() { - return this->getFrameLength() - this->getHeaderSize() -1 - FRAME_CRC_SIZE + 1; // -1 for the segment header. -} - -uint8_t TcTransferFrame::getSequenceNumber() { - return this->frame->header.sequenceNumber; -} - -uint8_t TcTransferFrame::getSequenceFlags() { - return (this->frame->dataField & 0b11000000)>>6; -} - -uint8_t TcTransferFrame::getMAPId() { - return this->frame->dataField & 0b00111111; -} - -uint8_t* TcTransferFrame::getDataField() { - return &(this->frame->dataField) + 1; -} - -uint8_t* TcTransferFrame::getFullFrame() { - return (uint8_t*)this->frame; -} - -uint16_t TcTransferFrame::getFullSize() { - return this->getFrameLength() + 1; -} - -uint16_t TcTransferFrame::getHeaderSize() { - return sizeof(frame->header); -} - -uint16_t TcTransferFrame::getFullDataLength() { - return this->getFrameLength() - this->getHeaderSize() - FRAME_CRC_SIZE + 1; -} - -uint8_t* TcTransferFrame::getFullDataField() { - return &frame->dataField; -} - -void TcTransferFrame::print() { - sif::debug << "Raw Frame: " << std::hex << std::endl; - for (uint16_t count = 0; count < this->getFullSize(); count++ ) { - sif::debug << (uint16_t)this->getFullFrame()[count] << " "; - } - sif::debug << std::dec << std::endl; -// debug << "Frame Header:" << std::endl; -// debug << "Version Number: " << std::hex << (uint16_t)this->current_frame.getVersionNumber() << std::endl; -// debug << "Bypass Flag set?| Ctrl Cmd Flag set?: " << (uint16_t)this->current_frame.bypassFlagSet() << " | " << (uint16_t)this->current_frame.controlCommandFlagSet() << std::endl; -// debug << "SCID : " << this->current_frame.getSpacecraftId() << std::endl; -// debug << "VCID : " << (uint16_t)this->current_frame.getVirtualChannelId() << std::endl; -// debug << "Frame length: " << std::dec << this->current_frame.getFrameLength() << std::endl; -// debug << "Sequence Number: " << (uint16_t)this->current_frame.getSequenceNumber() << std::endl; -} +/** + * @file TcTransferFrame.cpp + * @brief This file defines the TcTransferFrame class. + * @date 27.04.2013 + * @author baetz + */ + + + +#include "../datalinklayer/TcTransferFrame.h" +#include "../serviceinterface/ServiceInterfaceStream.h" + +TcTransferFrame::TcTransferFrame() { + frame = NULL; +} + +TcTransferFrame::TcTransferFrame(uint8_t* setData) { + this->frame = (tc_transfer_frame*)setData; +} + +uint8_t TcTransferFrame::getVersionNumber() { + return (this->frame->header.flagsAndScid & 0b11000000) >> 6; +} + +bool TcTransferFrame::bypassFlagSet() { + return (this->frame->header.flagsAndScid & 0b00100000) != 0; +} + +bool TcTransferFrame::controlCommandFlagSet() { + return (this->frame->header.flagsAndScid & 0b00010000) != 0; +} + +bool TcTransferFrame::spareIsZero() { + return ( (this->frame->header.flagsAndScid & 0b00001100) == 0 ); +} + +uint16_t TcTransferFrame::getSpacecraftId() { + return ( (this->frame->header.flagsAndScid & 0b00000011) << 8 ) + this->frame->header.spacecraftId_l; +} + +uint8_t TcTransferFrame::getVirtualChannelId() { + return (this->frame->header.vcidAndLength_h & 0b11111100) >> 2; +} + +uint16_t TcTransferFrame::getFrameLength() { + return ( (this->frame->header.vcidAndLength_h & 0b00000011) << 8 ) + this->frame->header.length_l; +} + +uint16_t TcTransferFrame::getDataLength() { + return this->getFrameLength() - this->getHeaderSize() -1 - FRAME_CRC_SIZE + 1; // -1 for the segment header. +} + +uint8_t TcTransferFrame::getSequenceNumber() { + return this->frame->header.sequenceNumber; +} + +uint8_t TcTransferFrame::getSequenceFlags() { + return (this->frame->dataField & 0b11000000)>>6; +} + +uint8_t TcTransferFrame::getMAPId() { + return this->frame->dataField & 0b00111111; +} + +uint8_t* TcTransferFrame::getDataField() { + return &(this->frame->dataField) + 1; +} + +uint8_t* TcTransferFrame::getFullFrame() { + return (uint8_t*)this->frame; +} + +uint16_t TcTransferFrame::getFullSize() { + return this->getFrameLength() + 1; +} + +uint16_t TcTransferFrame::getHeaderSize() { + return sizeof(frame->header); +} + +uint16_t TcTransferFrame::getFullDataLength() { + return this->getFrameLength() - this->getHeaderSize() - FRAME_CRC_SIZE + 1; +} + +uint8_t* TcTransferFrame::getFullDataField() { + return &frame->dataField; +} + +void TcTransferFrame::print() { + sif::debug << "Raw Frame: " << std::hex << std::endl; + for (uint16_t count = 0; count < this->getFullSize(); count++ ) { + sif::debug << (uint16_t)this->getFullFrame()[count] << " "; + } + sif::debug << std::dec << std::endl; +// debug << "Frame Header:" << std::endl; +// debug << "Version Number: " << std::hex << (uint16_t)this->current_frame.getVersionNumber() << std::endl; +// debug << "Bypass Flag set?| Ctrl Cmd Flag set?: " << (uint16_t)this->current_frame.bypassFlagSet() << " | " << (uint16_t)this->current_frame.controlCommandFlagSet() << std::endl; +// debug << "SCID : " << this->current_frame.getSpacecraftId() << std::endl; +// debug << "VCID : " << (uint16_t)this->current_frame.getVirtualChannelId() << std::endl; +// debug << "Frame length: " << std::dec << this->current_frame.getFrameLength() << std::endl; +// debug << "Sequence Number: " << (uint16_t)this->current_frame.getSequenceNumber() << std::endl; +} diff --git a/datalinklayer/TcTransferFrameLocal.cpp b/datalinklayer/TcTransferFrameLocal.cpp index 79e14167..0bffa586 100644 --- a/datalinklayer/TcTransferFrameLocal.cpp +++ b/datalinklayer/TcTransferFrameLocal.cpp @@ -1,49 +1,49 @@ -/** - * @file TcTransferFrameLocal.cpp - * @brief This file defines the TcTransferFrameLocal class. - * @date 27.04.2013 - * @author baetz - */ - -#include -#include -#include -#include - -TcTransferFrameLocal::TcTransferFrameLocal(bool bypass, bool controlCommand, uint16_t scid, - uint8_t vcId, uint8_t sequenceNumber, uint8_t setSegmentHeader, uint8_t* data, uint16_t dataSize, uint16_t forceCrc) { - this->frame = (tc_transfer_frame*)&localData; - frame->header.flagsAndScid = (bypass << 5) + (controlCommand << 4) + ((scid & 0x0300) >> 8); - frame->header.spacecraftId_l = (scid & 0x00FF); - frame->header.vcidAndLength_h = (vcId & 0b00111111) << 2; - frame->header.length_l = sizeof(TcTransferFramePrimaryHeader) -1; - frame->header.sequenceNumber = sequenceNumber; - frame->dataField = setSegmentHeader; - if (data != NULL) { - if (bypass && controlCommand) { - memcpy(&(frame->dataField), data, dataSize); - uint16_t totalSize = sizeof(TcTransferFramePrimaryHeader) + dataSize + FRAME_CRC_SIZE -1; - frame->header.vcidAndLength_h |= (totalSize & 0x0300) >> 8; - frame->header.length_l = (totalSize & 0x00FF); - uint16_t crc = CRC::crc16ccitt(getFullFrame(), getFullSize() -2); - this->getFullFrame()[getFullSize()-2] = (crc & 0xFF00) >> 8; - this->getFullFrame()[getFullSize()-1] = (crc & 0x00FF); - } else if (dataSize <= 1016) { - memcpy(&(frame->dataField) +1, data, dataSize); - uint16_t dataCrcSize = sizeof(TcTransferFramePrimaryHeader) + 1 + dataSize + FRAME_CRC_SIZE -1; - frame->header.vcidAndLength_h |= (dataCrcSize & 0x0300) >> 8; - frame->header.length_l = (dataCrcSize & 0x00FF); - uint16_t crc = CRC::crc16ccitt(getFullFrame(), getFullSize() -2); - this->getFullFrame()[getFullSize()-2] = (crc & 0xFF00) >> 8; - this->getFullFrame()[getFullSize()-1] = (crc & 0x00FF); - } else { - sif::debug << "TcTransferFrameLocal: dataSize too large: " << dataSize << std::endl; - } - } else { - //No data in frame - } - if (forceCrc != 0 ) { - localData.data[getFullSize()-2] = (forceCrc & 0xFF00) >> 8; - localData.data[getFullSize()-1] = (forceCrc & 0x00FF); - } -} +/** + * @file TcTransferFrameLocal.cpp + * @brief This file defines the TcTransferFrameLocal class. + * @date 27.04.2013 + * @author baetz + */ + +#include "../datalinklayer/TcTransferFrameLocal.h" +#include "../globalfunctions/CRC.h" +#include "../serviceinterface/ServiceInterfaceStream.h" +#include + +TcTransferFrameLocal::TcTransferFrameLocal(bool bypass, bool controlCommand, uint16_t scid, + uint8_t vcId, uint8_t sequenceNumber, uint8_t setSegmentHeader, uint8_t* data, uint16_t dataSize, uint16_t forceCrc) { + this->frame = (tc_transfer_frame*)&localData; + frame->header.flagsAndScid = (bypass << 5) + (controlCommand << 4) + ((scid & 0x0300) >> 8); + frame->header.spacecraftId_l = (scid & 0x00FF); + frame->header.vcidAndLength_h = (vcId & 0b00111111) << 2; + frame->header.length_l = sizeof(TcTransferFramePrimaryHeader) -1; + frame->header.sequenceNumber = sequenceNumber; + frame->dataField = setSegmentHeader; + if (data != NULL) { + if (bypass && controlCommand) { + memcpy(&(frame->dataField), data, dataSize); + uint16_t totalSize = sizeof(TcTransferFramePrimaryHeader) + dataSize + FRAME_CRC_SIZE -1; + frame->header.vcidAndLength_h |= (totalSize & 0x0300) >> 8; + frame->header.length_l = (totalSize & 0x00FF); + uint16_t crc = CRC::crc16ccitt(getFullFrame(), getFullSize() -2); + this->getFullFrame()[getFullSize()-2] = (crc & 0xFF00) >> 8; + this->getFullFrame()[getFullSize()-1] = (crc & 0x00FF); + } else if (dataSize <= 1016) { + memcpy(&(frame->dataField) +1, data, dataSize); + uint16_t dataCrcSize = sizeof(TcTransferFramePrimaryHeader) + 1 + dataSize + FRAME_CRC_SIZE -1; + frame->header.vcidAndLength_h |= (dataCrcSize & 0x0300) >> 8; + frame->header.length_l = (dataCrcSize & 0x00FF); + uint16_t crc = CRC::crc16ccitt(getFullFrame(), getFullSize() -2); + this->getFullFrame()[getFullSize()-2] = (crc & 0xFF00) >> 8; + this->getFullFrame()[getFullSize()-1] = (crc & 0x00FF); + } else { + sif::debug << "TcTransferFrameLocal: dataSize too large: " << dataSize << std::endl; + } + } else { + //No data in frame + } + if (forceCrc != 0 ) { + localData.data[getFullSize()-2] = (forceCrc & 0xFF00) >> 8; + localData.data[getFullSize()-1] = (forceCrc & 0x00FF); + } +} diff --git a/datalinklayer/TcTransferFrameLocal.h b/datalinklayer/TcTransferFrameLocal.h index f20f12ec..d98350fe 100644 --- a/datalinklayer/TcTransferFrameLocal.h +++ b/datalinklayer/TcTransferFrameLocal.h @@ -1,49 +1,49 @@ -/** - * @file TcTransferFrameLocal.h - * @brief This file defines the TcTransferFrameLocal class. - * @date 27.04.2013 - * @author baetz - */ - -#ifndef TCTRANSFERFRAMELOCAL_H_ -#define TCTRANSFERFRAMELOCAL_H_ - -#include - -/** - * This is a helper class to locally create TC Transfer Frames. - * This is mainly required for testing purposes and therefore not very sophisticated. - * @ingroup ccsds_handling - */ -class TcTransferFrameLocal : public TcTransferFrame { -private: - /** - * A stuct to locally store the complete data. - */ - struct frameData { - TcTransferFramePrimaryHeader header; //!< The primary header. - uint8_t data[1019]; //!< The data field. - }; -public: - frameData localData; //!< The local data in the Frame. - /** - * The default Constructor. - * All parameters in the Header are passed. - * If a BC Frame is detected no segment header is created. - * Otherwise (AD and BD), the Segment Header is set. - * @param bypass The bypass flag. - * @param controlCommand The Control Command flag. - * @param scid The SCID. - * @param vcId The VCID. - * @param sequenceNumber The Frame Sequence Number N(s) - * @param setSegmentHeader A value for the Segment Header. - * @param data Data to put into the Frame Data Field. - * @param dataSize Size of the Data. - * @param forceCrc if != 0, the value is used as CRC. - */ - TcTransferFrameLocal(bool bypass, bool controlCommand, uint16_t scid, uint8_t vcId, uint8_t sequenceNumber, - uint8_t setSegmentHeader = 0xC0, uint8_t* data = NULL, uint16_t dataSize = 0, uint16_t forceCrc = 0); -}; - - -#endif /* TCTRANSFERFRAMELOCAL_H_ */ +/** + * @file TcTransferFrameLocal.h + * @brief This file defines the TcTransferFrameLocal class. + * @date 27.04.2013 + * @author baetz + */ + +#ifndef TCTRANSFERFRAMELOCAL_H_ +#define TCTRANSFERFRAMELOCAL_H_ + +#include "../datalinklayer/TcTransferFrame.h" + +/** + * This is a helper class to locally create TC Transfer Frames. + * This is mainly required for testing purposes and therefore not very sophisticated. + * @ingroup ccsds_handling + */ +class TcTransferFrameLocal : public TcTransferFrame { +private: + /** + * A stuct to locally store the complete data. + */ + struct frameData { + TcTransferFramePrimaryHeader header; //!< The primary header. + uint8_t data[1019]; //!< The data field. + }; +public: + frameData localData; //!< The local data in the Frame. + /** + * The default Constructor. + * All parameters in the Header are passed. + * If a BC Frame is detected no segment header is created. + * Otherwise (AD and BD), the Segment Header is set. + * @param bypass The bypass flag. + * @param controlCommand The Control Command flag. + * @param scid The SCID. + * @param vcId The VCID. + * @param sequenceNumber The Frame Sequence Number N(s) + * @param setSegmentHeader A value for the Segment Header. + * @param data Data to put into the Frame Data Field. + * @param dataSize Size of the Data. + * @param forceCrc if != 0, the value is used as CRC. + */ + TcTransferFrameLocal(bool bypass, bool controlCommand, uint16_t scid, uint8_t vcId, uint8_t sequenceNumber, + uint8_t setSegmentHeader = 0xC0, uint8_t* data = NULL, uint16_t dataSize = 0, uint16_t forceCrc = 0); +}; + + +#endif /* TCTRANSFERFRAMELOCAL_H_ */ diff --git a/datalinklayer/VirtualChannelReception.cpp b/datalinklayer/VirtualChannelReception.cpp index 373f6c62..55169c42 100644 --- a/datalinklayer/VirtualChannelReception.cpp +++ b/datalinklayer/VirtualChannelReception.cpp @@ -1,121 +1,121 @@ -/** - * @file VirtualChannelReception.cpp - * @brief This file defines the VirtualChannelReception class. - * @date 26.03.2013 - * @author baetz - */ - -#include -#include -#include - -VirtualChannelReception::VirtualChannelReception(uint8_t setChannelId, - uint8_t setSlidingWindowWidth) : - channelId(setChannelId), slidingWindowWidth(setSlidingWindowWidth), positiveWindow( - setSlidingWindowWidth / 2), negativeWindow(setSlidingWindowWidth / 2), currentState( - &openState), openState(this), waitState(this), lockoutState(this), vR(0), farmBCounter( - 0) { - internalClcw.setVirtualChannel(channelId); -} - -ReturnValue_t VirtualChannelReception::mapDemultiplexing(TcTransferFrame* frame) { - uint8_t mapId = frame->getMAPId(); - mapChannelIterator iter = mapChannels.find(mapId); - if (iter == mapChannels.end()) { -// error << "VirtualChannelReception::mapDemultiplexing on VC " << std::hex << (int) channelId -// << ": MapChannel " << (int) mapId << std::dec << " not found." << std::endl; - return VC_NOT_FOUND; - } else { - return (iter->second)->extractPackets(frame); - } -} - -ReturnValue_t VirtualChannelReception::doFARM(TcTransferFrame* frame, ClcwIF* clcw) { - uint8_t bypass = frame->bypassFlagSet(); - uint8_t controlCommand = frame->controlCommandFlagSet(); - uint8_t typeValue = (bypass << 1) + controlCommand; - switch (typeValue) { - case AD_FRAME: - return currentState->handleADFrame(frame, clcw); - case BD_FRAME: - return handleBDFrame(frame, clcw); - case BC_FRAME: - return handleBCFrame(frame, clcw); - default: - return ILLEGAL_FLAG_COMBINATION; - } -} - -ReturnValue_t VirtualChannelReception::frameAcceptanceAndReportingMechanism(TcTransferFrame* frame, - ClcwIF* clcw) { - ReturnValue_t result = RETURN_OK; - result = doFARM(frame, &internalClcw); - internalClcw.setReceiverFrameSequenceNumber(vR); - internalClcw.setFarmBCount(farmBCounter); - clcw->setWhole(internalClcw.getAsWhole()); - switch (result) { - case RETURN_OK: - return mapDemultiplexing(frame); - case BC_IS_SET_VR_COMMAND: - case BC_IS_UNLOCK_COMMAND: - //Need to catch these codes to avoid error reporting later. - return RETURN_OK; - default: - break; - } - return result; -} - -ReturnValue_t VirtualChannelReception::addMapChannel(uint8_t mapId, MapPacketExtractionIF* object) { - std::pair returnValue = mapChannels.insert( - std::pair(mapId, object)); - if (returnValue.second == true) { - return RETURN_OK; - } else { - return RETURN_FAILED; - } -} - -ReturnValue_t VirtualChannelReception::handleBDFrame(TcTransferFrame* frame, ClcwIF* clcw) { - farmBCounter++; - return RETURN_OK; -} - -ReturnValue_t VirtualChannelReception::handleBCFrame(TcTransferFrame* frame, ClcwIF* clcw) { - BcFrame content; - ReturnValue_t returnValue = content.initialize(frame->getFullDataField(), - frame->getFullDataLength()); - if (returnValue == BC_IS_UNLOCK_COMMAND) { - returnValue = currentState->handleBCUnlockCommand(clcw); - } else if (returnValue == BC_IS_SET_VR_COMMAND) { - returnValue = currentState->handleBCSetVrCommand(clcw, content.vR); - } else { - //Do nothing - } - return returnValue; -} - -uint8_t VirtualChannelReception::getChannelId() const { - return channelId; -} - -ReturnValue_t VirtualChannelReception::initialize() { - ReturnValue_t returnValue = RETURN_FAILED; - if ((slidingWindowWidth > 254) || (slidingWindowWidth % 2 != 0)) { - sif::error << "VirtualChannelReception::initialize: Illegal sliding window width: " - << (int) slidingWindowWidth << std::endl; - return RETURN_FAILED; - } - for (mapChannelIterator iterator = mapChannels.begin(); iterator != mapChannels.end(); - iterator++) { - returnValue = iterator->second->initialize(); - if (returnValue != RETURN_OK) - break; - } - return returnValue; -} - -void VirtualChannelReception::setToWaitState() { - internalClcw.setWaitFlag(true); - this->currentState = &waitState; -} +/** + * @file VirtualChannelReception.cpp + * @brief This file defines the VirtualChannelReception class. + * @date 26.03.2013 + * @author baetz + */ + +#include "../datalinklayer/BCFrame.h" +#include "../datalinklayer/VirtualChannelReception.h" +#include "../serviceinterface/ServiceInterfaceStream.h" + +VirtualChannelReception::VirtualChannelReception(uint8_t setChannelId, + uint8_t setSlidingWindowWidth) : + channelId(setChannelId), slidingWindowWidth(setSlidingWindowWidth), positiveWindow( + setSlidingWindowWidth / 2), negativeWindow(setSlidingWindowWidth / 2), currentState( + &openState), openState(this), waitState(this), lockoutState(this), vR(0), farmBCounter( + 0) { + internalClcw.setVirtualChannel(channelId); +} + +ReturnValue_t VirtualChannelReception::mapDemultiplexing(TcTransferFrame* frame) { + uint8_t mapId = frame->getMAPId(); + mapChannelIterator iter = mapChannels.find(mapId); + if (iter == mapChannels.end()) { +// error << "VirtualChannelReception::mapDemultiplexing on VC " << std::hex << (int) channelId +// << ": MapChannel " << (int) mapId << std::dec << " not found." << std::endl; + return VC_NOT_FOUND; + } else { + return (iter->second)->extractPackets(frame); + } +} + +ReturnValue_t VirtualChannelReception::doFARM(TcTransferFrame* frame, ClcwIF* clcw) { + uint8_t bypass = frame->bypassFlagSet(); + uint8_t controlCommand = frame->controlCommandFlagSet(); + uint8_t typeValue = (bypass << 1) + controlCommand; + switch (typeValue) { + case AD_FRAME: + return currentState->handleADFrame(frame, clcw); + case BD_FRAME: + return handleBDFrame(frame, clcw); + case BC_FRAME: + return handleBCFrame(frame, clcw); + default: + return ILLEGAL_FLAG_COMBINATION; + } +} + +ReturnValue_t VirtualChannelReception::frameAcceptanceAndReportingMechanism(TcTransferFrame* frame, + ClcwIF* clcw) { + ReturnValue_t result = RETURN_OK; + result = doFARM(frame, &internalClcw); + internalClcw.setReceiverFrameSequenceNumber(vR); + internalClcw.setFarmBCount(farmBCounter); + clcw->setWhole(internalClcw.getAsWhole()); + switch (result) { + case RETURN_OK: + return mapDemultiplexing(frame); + case BC_IS_SET_VR_COMMAND: + case BC_IS_UNLOCK_COMMAND: + //Need to catch these codes to avoid error reporting later. + return RETURN_OK; + default: + break; + } + return result; +} + +ReturnValue_t VirtualChannelReception::addMapChannel(uint8_t mapId, MapPacketExtractionIF* object) { + std::pair returnValue = mapChannels.insert( + std::pair(mapId, object)); + if (returnValue.second == true) { + return RETURN_OK; + } else { + return RETURN_FAILED; + } +} + +ReturnValue_t VirtualChannelReception::handleBDFrame(TcTransferFrame* frame, ClcwIF* clcw) { + farmBCounter++; + return RETURN_OK; +} + +ReturnValue_t VirtualChannelReception::handleBCFrame(TcTransferFrame* frame, ClcwIF* clcw) { + BcFrame content; + ReturnValue_t returnValue = content.initialize(frame->getFullDataField(), + frame->getFullDataLength()); + if (returnValue == BC_IS_UNLOCK_COMMAND) { + returnValue = currentState->handleBCUnlockCommand(clcw); + } else if (returnValue == BC_IS_SET_VR_COMMAND) { + returnValue = currentState->handleBCSetVrCommand(clcw, content.vR); + } else { + //Do nothing + } + return returnValue; +} + +uint8_t VirtualChannelReception::getChannelId() const { + return channelId; +} + +ReturnValue_t VirtualChannelReception::initialize() { + ReturnValue_t returnValue = RETURN_FAILED; + if ((slidingWindowWidth > 254) || (slidingWindowWidth % 2 != 0)) { + sif::error << "VirtualChannelReception::initialize: Illegal sliding window width: " + << (int) slidingWindowWidth << std::endl; + return RETURN_FAILED; + } + for (mapChannelIterator iterator = mapChannels.begin(); iterator != mapChannels.end(); + iterator++) { + returnValue = iterator->second->initialize(); + if (returnValue != RETURN_OK) + break; + } + return returnValue; +} + +void VirtualChannelReception::setToWaitState() { + internalClcw.setWaitFlag(true); + this->currentState = &waitState; +} diff --git a/datalinklayer/VirtualChannelReception.h b/datalinklayer/VirtualChannelReception.h index f364c6e5..f7111e42 100644 --- a/datalinklayer/VirtualChannelReception.h +++ b/datalinklayer/VirtualChannelReception.h @@ -1,114 +1,114 @@ -/** - * @file VirtualChannelReception.h - * @brief This file defines the VirtualChannelReception class. - * @date 25.03.2013 - * @author baetz - */ - -#ifndef VIRTUALCHANNELRECEPTION_H_ -#define VIRTUALCHANNELRECEPTION_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -/** - * Implementation of a TC Virtual Channel. - * This is a full implementation of a virtual channel as specified in the CCSDS TC Space Data Link - * Protocol. It is designed to operate within an instance of the @c DataLinkLayer class. - * Features: - * - any (6bit) Virtual Channel ID is assignable. - * - Supports an arbitrary number of MAP Channels (with a map). - * - Has a complete FARM-1 Machine built-in. - * - * The FARM-1 state machine uses the State Pattern. - */ -class VirtualChannelReception : public VirtualChannelReceptionIF, public CCSDSReturnValuesIF { - friend class Farm1StateOpen; - friend class Farm1StateWait; - friend class Farm1StateLockout; -private: - uint8_t channelId; //!< Stores the VCID that was assigned on construction. - uint8_t slidingWindowWidth; //!< A constant to set the FARM-1 sliding window width. - uint8_t positiveWindow; //!< The positive window for the FARM-1 machine. - uint8_t negativeWindow; //!< The negative window for the FARM-1 machine. -protected: - Farm1StateIF* currentState; //!< The current state. To change, one of the other states must be assigned to this pointer. - Farm1StateOpen openState; //!< Instance of the FARM-1 State "Open". - Farm1StateWait waitState; //!< Instance of the FARM-1 State "Wait". - Farm1StateLockout lockoutState; //!< Instance of the FARM-1 State "Lockout". - Clcw internalClcw; //!< A CLCW class to internally set the values before writing them back to the TTC System. - uint8_t vR; //!< The Receiver Frame Sequence Number V(R) as it shall be maintained for every Virtual Channel. - uint8_t farmBCounter; //!< The FARM-B COunter as it shall be maintained for every Virtual Channel. - typedef std::map::iterator mapChannelIterator; //!< Typedef to simplify handling of the mapChannels map. - std::map mapChannels; //!< A map that maintains all map Channels. Channels must be configured on initialization. MAy be omitted in a simplified version. - /** - * This method handles demultiplexing to different map channels. - * It parses the entries of #mapChannels and forwards the Frame to a found MAP Channel. - * @param frame The frame to forward. - * @return #VC_NOT_FOUND or the return value of the map channel extraction. - */ - ReturnValue_t mapDemultiplexing( TcTransferFrame* frame ); - /** - * A sub-method that actually does the FARM-1 handling for different Frame types. - * @param frame The Tc Transfer Frame to handle. - * @param clcw Any changes on the CLCW shall be done with this method. - * @return The return code of higher methods or @c ILLEGAL_FLAG_COMBINATION. - */ - ReturnValue_t doFARM(TcTransferFrame* frame, ClcwIF* clcw); - /** - * Handles incoming BD Frames. - * Handling these Frames is independent of the State, so no subcall to #currentState is - * required. - * @param frame The Tc Transfer Frame to handle. - * @param clcw Any changes on the CLCW shall be done with this method. - * @return Always returns @c RETURN_OK. - */ - ReturnValue_t handleBDFrame( TcTransferFrame* frame, ClcwIF* clcw ); - /** - * Handles incoming BC Frames. - * The type of the BC Frame is detected and checked first, then methods of #currentState are called. - * @param frame The Tc Transfer Frame to handle. - * @param clcw Any changes on the CLCW shall be done with this method. - * @return The failure code of BC Frame interpretation or the return code of higher methods. - */ - ReturnValue_t handleBCFrame( TcTransferFrame* frame, ClcwIF* clcw ); -public: - /** - * Default constructor. - * Only sets the channelId of the channel. Setting the Sliding Window width is possible as well. - * @param setChannelId Virtual Channel Identifier (VCID) of the channel. - */ - VirtualChannelReception( uint8_t setChannelId, uint8_t setSlidingWindowWidth ); - ReturnValue_t frameAcceptanceAndReportingMechanism( TcTransferFrame* frame, ClcwIF* clcw ); - /** - * Helper method to simplify adding a mapChannel during construction. - * @param mapId The mapId of the object to add. - * @param object Pointer to the MapPacketExtraction object itself. - * @return @c RETURN_OK if the channel was successfully inserted, @c RETURN_FAILED otherwise. - */ - ReturnValue_t addMapChannel( uint8_t mapId, MapPacketExtractionIF* object ); - /** - * The initialization routine checks the set #slidingWindowWidth and initializes all MAP - * channels. - * @return @c RETURN_OK on successful initialization, @c RETURN_FAILED otherwise. - */ - ReturnValue_t initialize(); - /** - * Getter for the VCID. - * @return The #channelId. - */ - uint8_t getChannelId() const; - /** - * Small method to set the state to Farm1StateWait. - */ - void setToWaitState(); -}; - - -#endif /* VIRTUALCHANNELRECEPTION_H_ */ +/** + * @file VirtualChannelReception.h + * @brief This file defines the VirtualChannelReception class. + * @date 25.03.2013 + * @author baetz + */ + +#ifndef VIRTUALCHANNELRECEPTION_H_ +#define VIRTUALCHANNELRECEPTION_H_ + +#include "../datalinklayer/CCSDSReturnValuesIF.h" +#include "../datalinklayer/Clcw.h" +#include "../datalinklayer/Farm1StateIF.h" +#include "../datalinklayer/Farm1StateLockout.h" +#include "../datalinklayer/Farm1StateOpen.h" +#include "../datalinklayer/Farm1StateWait.h" +#include "../datalinklayer/MapPacketExtractionIF.h" +#include "../datalinklayer/VirtualChannelReceptionIF.h" +#include +/** + * Implementation of a TC Virtual Channel. + * This is a full implementation of a virtual channel as specified in the CCSDS TC Space Data Link + * Protocol. It is designed to operate within an instance of the @c DataLinkLayer class. + * Features: + * - any (6bit) Virtual Channel ID is assignable. + * - Supports an arbitrary number of MAP Channels (with a map). + * - Has a complete FARM-1 Machine built-in. + * + * The FARM-1 state machine uses the State Pattern. + */ +class VirtualChannelReception : public VirtualChannelReceptionIF, public CCSDSReturnValuesIF { + friend class Farm1StateOpen; + friend class Farm1StateWait; + friend class Farm1StateLockout; +private: + uint8_t channelId; //!< Stores the VCID that was assigned on construction. + uint8_t slidingWindowWidth; //!< A constant to set the FARM-1 sliding window width. + uint8_t positiveWindow; //!< The positive window for the FARM-1 machine. + uint8_t negativeWindow; //!< The negative window for the FARM-1 machine. +protected: + Farm1StateIF* currentState; //!< The current state. To change, one of the other states must be assigned to this pointer. + Farm1StateOpen openState; //!< Instance of the FARM-1 State "Open". + Farm1StateWait waitState; //!< Instance of the FARM-1 State "Wait". + Farm1StateLockout lockoutState; //!< Instance of the FARM-1 State "Lockout". + Clcw internalClcw; //!< A CLCW class to internally set the values before writing them back to the TTC System. + uint8_t vR; //!< The Receiver Frame Sequence Number V(R) as it shall be maintained for every Virtual Channel. + uint8_t farmBCounter; //!< The FARM-B COunter as it shall be maintained for every Virtual Channel. + typedef std::map::iterator mapChannelIterator; //!< Typedef to simplify handling of the mapChannels map. + std::map mapChannels; //!< A map that maintains all map Channels. Channels must be configured on initialization. MAy be omitted in a simplified version. + /** + * This method handles demultiplexing to different map channels. + * It parses the entries of #mapChannels and forwards the Frame to a found MAP Channel. + * @param frame The frame to forward. + * @return #VC_NOT_FOUND or the return value of the map channel extraction. + */ + ReturnValue_t mapDemultiplexing( TcTransferFrame* frame ); + /** + * A sub-method that actually does the FARM-1 handling for different Frame types. + * @param frame The Tc Transfer Frame to handle. + * @param clcw Any changes on the CLCW shall be done with this method. + * @return The return code of higher methods or @c ILLEGAL_FLAG_COMBINATION. + */ + ReturnValue_t doFARM(TcTransferFrame* frame, ClcwIF* clcw); + /** + * Handles incoming BD Frames. + * Handling these Frames is independent of the State, so no subcall to #currentState is + * required. + * @param frame The Tc Transfer Frame to handle. + * @param clcw Any changes on the CLCW shall be done with this method. + * @return Always returns @c RETURN_OK. + */ + ReturnValue_t handleBDFrame( TcTransferFrame* frame, ClcwIF* clcw ); + /** + * Handles incoming BC Frames. + * The type of the BC Frame is detected and checked first, then methods of #currentState are called. + * @param frame The Tc Transfer Frame to handle. + * @param clcw Any changes on the CLCW shall be done with this method. + * @return The failure code of BC Frame interpretation or the return code of higher methods. + */ + ReturnValue_t handleBCFrame( TcTransferFrame* frame, ClcwIF* clcw ); +public: + /** + * Default constructor. + * Only sets the channelId of the channel. Setting the Sliding Window width is possible as well. + * @param setChannelId Virtual Channel Identifier (VCID) of the channel. + */ + VirtualChannelReception( uint8_t setChannelId, uint8_t setSlidingWindowWidth ); + ReturnValue_t frameAcceptanceAndReportingMechanism( TcTransferFrame* frame, ClcwIF* clcw ); + /** + * Helper method to simplify adding a mapChannel during construction. + * @param mapId The mapId of the object to add. + * @param object Pointer to the MapPacketExtraction object itself. + * @return @c RETURN_OK if the channel was successfully inserted, @c RETURN_FAILED otherwise. + */ + ReturnValue_t addMapChannel( uint8_t mapId, MapPacketExtractionIF* object ); + /** + * The initialization routine checks the set #slidingWindowWidth and initializes all MAP + * channels. + * @return @c RETURN_OK on successful initialization, @c RETURN_FAILED otherwise. + */ + ReturnValue_t initialize(); + /** + * Getter for the VCID. + * @return The #channelId. + */ + uint8_t getChannelId() const; + /** + * Small method to set the state to Farm1StateWait. + */ + void setToWaitState(); +}; + + +#endif /* VIRTUALCHANNELRECEPTION_H_ */ diff --git a/datalinklayer/VirtualChannelReceptionIF.h b/datalinklayer/VirtualChannelReceptionIF.h index 98a9b72c..da544081 100644 --- a/datalinklayer/VirtualChannelReceptionIF.h +++ b/datalinklayer/VirtualChannelReceptionIF.h @@ -1,57 +1,57 @@ -/** - * @file VirtualChannelReceptionIF.h - * @brief This file defines the VirtualChannelReceptionIF class. - * @date 25.03.2013 - * @author baetz - */ - -#ifndef VIRTUALCHANNELRECEPTIONIF_H_ -#define VIRTUALCHANNELRECEPTIONIF_H_ - -#include -#include -#include - -/** - * This is the interface for Virtual Channel reception classes. - * It represents a single TC Virtual Channel that operates on one IO - */ -class VirtualChannelReceptionIF { -public: - /** - * Enum including all valid types of frames. - * The type is made up by two flags, so 0b1111 is definitely illegal. - */ - enum frameType { - AD_FRAME = 0b00, - BC_FRAME = 0b11, - BD_FRAME = 0b10, - ILLEGAL_FRAME = 0b1111 - }; - /** - * Empty virtual destructor. - */ - virtual ~VirtualChannelReceptionIF() { - } - /** - * This method shall accept frames and do all FARM-1 stuff. - * Handling the Frame includes forwarding to higher-level procedures. - * @param frame The Tc Transfer Frame that was received and checked. - * @param clcw Any changes to the CLCW value are forwarded by using this parameter. - * @return The return Value shall indicate successful processing with @c RETURN_OK. - */ - virtual ReturnValue_t frameAcceptanceAndReportingMechanism( TcTransferFrame* frame, ClcwIF* clcw ) = 0; - /** - * If any other System Objects are required for operation they shall be initialized here. - * @return @c RETURN_OK for successful initialization. - */ - virtual ReturnValue_t initialize() = 0; - /** - * Getter for the VCID. - * @return The #channelId. - */ - virtual uint8_t getChannelId() const = 0; -}; - - -#endif /* VIRTUALCHANNELRECEPTIONIF_H_ */ +/** + * @file VirtualChannelReceptionIF.h + * @brief This file defines the VirtualChannelReceptionIF class. + * @date 25.03.2013 + * @author baetz + */ + +#ifndef VIRTUALCHANNELRECEPTIONIF_H_ +#define VIRTUALCHANNELRECEPTIONIF_H_ + +#include "../datalinklayer/ClcwIF.h" +#include "../datalinklayer/TcTransferFrame.h" +#include "../returnvalues/HasReturnvaluesIF.h" + +/** + * This is the interface for Virtual Channel reception classes. + * It represents a single TC Virtual Channel that operates on one IO + */ +class VirtualChannelReceptionIF { +public: + /** + * Enum including all valid types of frames. + * The type is made up by two flags, so 0b1111 is definitely illegal. + */ + enum frameType { + AD_FRAME = 0b00, + BC_FRAME = 0b11, + BD_FRAME = 0b10, + ILLEGAL_FRAME = 0b1111 + }; + /** + * Empty virtual destructor. + */ + virtual ~VirtualChannelReceptionIF() { + } + /** + * This method shall accept frames and do all FARM-1 stuff. + * Handling the Frame includes forwarding to higher-level procedures. + * @param frame The Tc Transfer Frame that was received and checked. + * @param clcw Any changes to the CLCW value are forwarded by using this parameter. + * @return The return Value shall indicate successful processing with @c RETURN_OK. + */ + virtual ReturnValue_t frameAcceptanceAndReportingMechanism( TcTransferFrame* frame, ClcwIF* clcw ) = 0; + /** + * If any other System Objects are required for operation they shall be initialized here. + * @return @c RETURN_OK for successful initialization. + */ + virtual ReturnValue_t initialize() = 0; + /** + * Getter for the VCID. + * @return The #channelId. + */ + virtual uint8_t getChannelId() const = 0; +}; + + +#endif /* VIRTUALCHANNELRECEPTIONIF_H_ */ diff --git a/datapool/ControllerSet.cpp b/datapool/ControllerSet.cpp index eb4f6d0f..f83b38d5 100644 --- a/datapool/ControllerSet.cpp +++ b/datapool/ControllerSet.cpp @@ -1,14 +1,14 @@ -#include - -ControllerSet::ControllerSet() { - -} - -ControllerSet::~ControllerSet() { -} - -void ControllerSet::setInvalid() { - read(); - setToDefault(); - commit(PoolVariableIF::INVALID); -} +#include "../datapool/ControllerSet.h" + +ControllerSet::ControllerSet() { + +} + +ControllerSet::~ControllerSet() { +} + +void ControllerSet::setInvalid() { + read(); + setToDefault(); + commit(PoolVariableIF::INVALID); +} diff --git a/datapool/ControllerSet.h b/datapool/ControllerSet.h index 7625c3d1..da6a9bf4 100644 --- a/datapool/ControllerSet.h +++ b/datapool/ControllerSet.h @@ -1,15 +1,15 @@ -#ifndef CONTROLLERSET_H_ -#define CONTROLLERSET_H_ - -#include - -class ControllerSet :public GlobDataSet { -public: - ControllerSet(); - virtual ~ControllerSet(); - - virtual void setToDefault() = 0; - void setInvalid(); -}; - -#endif /* CONTROLLERSET_H_ */ +#ifndef CONTROLLERSET_H_ +#define CONTROLLERSET_H_ + +#include "../datapoolglob/GlobalDataSet.h" + +class ControllerSet :public GlobDataSet { +public: + ControllerSet(); + virtual ~ControllerSet(); + + virtual void setToDefault() = 0; + void setInvalid(); +}; + +#endif /* CONTROLLERSET_H_ */ diff --git a/datapool/DataSetBase.cpp b/datapool/DataSetBase.cpp index cb7a7899..b7dd2cee 100644 --- a/datapool/DataSetBase.cpp +++ b/datapool/DataSetBase.cpp @@ -1,168 +1,168 @@ -#include -#include - -DataSetBase::DataSetBase(PoolVariableIF** registeredVariablesArray, - const size_t maxFillCount): - registeredVariables(registeredVariablesArray), - maxFillCount(maxFillCount) { - for (uint8_t count = 0; count < maxFillCount; count++) { - registeredVariables[count] = nullptr; - } -} - -DataSetBase::~DataSetBase() {} - -ReturnValue_t DataSetBase::registerVariable( - PoolVariableIF *variable) { - if (state != States::DATA_SET_UNINITIALISED) { - sif::error << "DataSet::registerVariable: " - "Call made in wrong position." << std::endl; - return DataSetIF::DATA_SET_UNINITIALISED; - } - if (variable == nullptr) { - sif::error << "DataSet::registerVariable: " - "Pool variable is nullptr." << std::endl; - return DataSetIF::POOL_VAR_NULL; - } - if (fillCount >= maxFillCount) { - sif::error << "DataSet::registerVariable: " - "DataSet is full." << std::endl; - return DataSetIF::DATA_SET_FULL; - } - registeredVariables[fillCount] = variable; - fillCount++; - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t DataSetBase::read(uint32_t lockTimeout) { - ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; - if (state == States::DATA_SET_UNINITIALISED) { - lockDataPool(lockTimeout); - for (uint16_t count = 0; count < fillCount; count++) { - result = readVariable(count); - if(result != RETURN_OK) { - break; - } - } - state = States::DATA_SET_WAS_READ; - unlockDataPool(); - } - else { - sif::error << "DataSet::read(): " - "Call made in wrong position. Don't forget to commit" - " member datasets!" << std::endl; - result = SET_WAS_ALREADY_READ; - } - return result; -} - -uint16_t DataSetBase::getFillCount() const { - return fillCount; -} - -ReturnValue_t DataSetBase::readVariable(uint16_t count) { - ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; - // These checks are often performed by the respective - // variable implementation too, but I guess a double check does not hurt. - if (registeredVariables[count]->getReadWriteMode() != - PoolVariableIF::VAR_WRITE and - registeredVariables[count]->getDataPoolId() - != PoolVariableIF::NO_PARAMETER) - { - result = registeredVariables[count]->readWithoutLock(); - if(result != HasReturnvaluesIF::RETURN_OK) { - result = INVALID_PARAMETER_DEFINITION; - } - } - return result; -} - -ReturnValue_t DataSetBase::commit(uint32_t lockTimeout) { - if (state == States::DATA_SET_WAS_READ) { - handleAlreadyReadDatasetCommit(lockTimeout); - return HasReturnvaluesIF::RETURN_OK; - } - else { - return handleUnreadDatasetCommit(lockTimeout); - } -} - -void DataSetBase::handleAlreadyReadDatasetCommit(uint32_t lockTimeout) { - lockDataPool(lockTimeout); - for (uint16_t count = 0; count < fillCount; count++) { - if (registeredVariables[count]->getReadWriteMode() - != PoolVariableIF::VAR_READ - && registeredVariables[count]->getDataPoolId() - != PoolVariableIF::NO_PARAMETER) { - registeredVariables[count]->commitWithoutLock(); - } - } - state = States::DATA_SET_UNINITIALISED; - unlockDataPool(); -} - -ReturnValue_t DataSetBase::handleUnreadDatasetCommit(uint32_t lockTimeout) { - ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; - lockDataPool(lockTimeout); - for (uint16_t count = 0; count < fillCount; count++) { - if (registeredVariables[count]->getReadWriteMode() - == PoolVariableIF::VAR_WRITE - && registeredVariables[count]->getDataPoolId() - != PoolVariableIF::NO_PARAMETER) { - registeredVariables[count]->commitWithoutLock(); - } else if (registeredVariables[count]->getDataPoolId() - != PoolVariableIF::NO_PARAMETER) { - if (result != COMMITING_WITHOUT_READING) { - sif::error << "DataSet::commit(): commit-without-read call made " - "with non write-only variable." << std::endl; - result = COMMITING_WITHOUT_READING; - } - } - } - state = States::DATA_SET_UNINITIALISED; - unlockDataPool(); - return result; -} - - -ReturnValue_t DataSetBase::lockDataPool(uint32_t timeoutMs) { - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t DataSetBase::unlockDataPool() { - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t DataSetBase::serialize(uint8_t** buffer, size_t* size, - const size_t maxSize, SerializeIF::Endianness streamEndianness) const { - ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; - for (uint16_t count = 0; count < fillCount; count++) { - result = registeredVariables[count]->serialize(buffer, size, maxSize, - streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - } - return result; -} - -ReturnValue_t DataSetBase::deSerialize(const uint8_t** buffer, size_t* size, - SerializeIF::Endianness streamEndianness) { - ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; - for (uint16_t count = 0; count < fillCount; count++) { - result = registeredVariables[count]->deSerialize(buffer, size, - streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - } - return result; -} - -size_t DataSetBase::getSerializedSize() const { - uint32_t size = 0; - for (uint16_t count = 0; count < fillCount; count++) { - size += registeredVariables[count]->getSerializedSize(); - } - return size; -} +#include "../datapool/DataSetBase.h" +#include "../serviceinterface/ServiceInterfaceStream.h" + +DataSetBase::DataSetBase(PoolVariableIF** registeredVariablesArray, + const size_t maxFillCount): + registeredVariables(registeredVariablesArray), + maxFillCount(maxFillCount) { + for (uint8_t count = 0; count < maxFillCount; count++) { + registeredVariables[count] = nullptr; + } +} + +DataSetBase::~DataSetBase() {} + +ReturnValue_t DataSetBase::registerVariable( + PoolVariableIF *variable) { + if (state != States::DATA_SET_UNINITIALISED) { + sif::error << "DataSet::registerVariable: " + "Call made in wrong position." << std::endl; + return DataSetIF::DATA_SET_UNINITIALISED; + } + if (variable == nullptr) { + sif::error << "DataSet::registerVariable: " + "Pool variable is nullptr." << std::endl; + return DataSetIF::POOL_VAR_NULL; + } + if (fillCount >= maxFillCount) { + sif::error << "DataSet::registerVariable: " + "DataSet is full." << std::endl; + return DataSetIF::DATA_SET_FULL; + } + registeredVariables[fillCount] = variable; + fillCount++; + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t DataSetBase::read(uint32_t lockTimeout) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + if (state == States::DATA_SET_UNINITIALISED) { + lockDataPool(lockTimeout); + for (uint16_t count = 0; count < fillCount; count++) { + result = readVariable(count); + if(result != RETURN_OK) { + break; + } + } + state = States::DATA_SET_WAS_READ; + unlockDataPool(); + } + else { + sif::error << "DataSet::read(): " + "Call made in wrong position. Don't forget to commit" + " member datasets!" << std::endl; + result = SET_WAS_ALREADY_READ; + } + return result; +} + +uint16_t DataSetBase::getFillCount() const { + return fillCount; +} + +ReturnValue_t DataSetBase::readVariable(uint16_t count) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + // These checks are often performed by the respective + // variable implementation too, but I guess a double check does not hurt. + if (registeredVariables[count]->getReadWriteMode() != + PoolVariableIF::VAR_WRITE and + registeredVariables[count]->getDataPoolId() + != PoolVariableIF::NO_PARAMETER) + { + result = registeredVariables[count]->readWithoutLock(); + if(result != HasReturnvaluesIF::RETURN_OK) { + result = INVALID_PARAMETER_DEFINITION; + } + } + return result; +} + +ReturnValue_t DataSetBase::commit(uint32_t lockTimeout) { + if (state == States::DATA_SET_WAS_READ) { + handleAlreadyReadDatasetCommit(lockTimeout); + return HasReturnvaluesIF::RETURN_OK; + } + else { + return handleUnreadDatasetCommit(lockTimeout); + } +} + +void DataSetBase::handleAlreadyReadDatasetCommit(uint32_t lockTimeout) { + lockDataPool(lockTimeout); + for (uint16_t count = 0; count < fillCount; count++) { + if (registeredVariables[count]->getReadWriteMode() + != PoolVariableIF::VAR_READ + && registeredVariables[count]->getDataPoolId() + != PoolVariableIF::NO_PARAMETER) { + registeredVariables[count]->commitWithoutLock(); + } + } + state = States::DATA_SET_UNINITIALISED; + unlockDataPool(); +} + +ReturnValue_t DataSetBase::handleUnreadDatasetCommit(uint32_t lockTimeout) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + lockDataPool(lockTimeout); + for (uint16_t count = 0; count < fillCount; count++) { + if (registeredVariables[count]->getReadWriteMode() + == PoolVariableIF::VAR_WRITE + && registeredVariables[count]->getDataPoolId() + != PoolVariableIF::NO_PARAMETER) { + registeredVariables[count]->commitWithoutLock(); + } else if (registeredVariables[count]->getDataPoolId() + != PoolVariableIF::NO_PARAMETER) { + if (result != COMMITING_WITHOUT_READING) { + sif::error << "DataSet::commit(): commit-without-read call made " + "with non write-only variable." << std::endl; + result = COMMITING_WITHOUT_READING; + } + } + } + state = States::DATA_SET_UNINITIALISED; + unlockDataPool(); + return result; +} + + +ReturnValue_t DataSetBase::lockDataPool(uint32_t timeoutMs) { + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t DataSetBase::unlockDataPool() { + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t DataSetBase::serialize(uint8_t** buffer, size_t* size, + const size_t maxSize, SerializeIF::Endianness streamEndianness) const { + ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; + for (uint16_t count = 0; count < fillCount; count++) { + result = registeredVariables[count]->serialize(buffer, size, maxSize, + streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + return result; +} + +ReturnValue_t DataSetBase::deSerialize(const uint8_t** buffer, size_t* size, + SerializeIF::Endianness streamEndianness) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; + for (uint16_t count = 0; count < fillCount; count++) { + result = registeredVariables[count]->deSerialize(buffer, size, + streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + return result; +} + +size_t DataSetBase::getSerializedSize() const { + uint32_t size = 0; + for (uint16_t count = 0; count < fillCount; count++) { + size += registeredVariables[count]->getSerializedSize(); + } + return size; +} diff --git a/datapool/DataSetBase.h b/datapool/DataSetBase.h index cc16aa9e..ed7eaa28 100644 --- a/datapool/DataSetBase.h +++ b/datapool/DataSetBase.h @@ -1,149 +1,149 @@ -#ifndef FRAMEWORK_DATAPOOL_DATASETBASE_H_ -#define FRAMEWORK_DATAPOOL_DATASETBASE_H_ -#include -#include -#include - -/** - * @brief The DataSetBase class manages a set of locally checked out variables. - * @details - * This class manages a list, where a set of local variables (or pool variables) - * are registered. They are checked-out (i.e. their values are looked - * up and copied) with the read call. After the user finishes working with the - * pool variables, he can write back all variable values to the pool with - * the commit call. The data set manages locking and freeing the data pool, - * to ensure that all values are read and written back at once. - * - * An internal state manages usage of this class. Variables may only be - * registered before the read call is made, and the commit call only - * after the read call. - * - * If pool variables are writable and not committed until destruction - * of the set, the DataSet class automatically sets the valid flag in the - * data pool to invalid (without) changing the variable's value. - * - * The base class lockDataPool und unlockDataPool implementation are empty - * and should be implemented to protect the underlying pool type. - * @author Bastian Baetz - * @ingroup data_pool - */ -class DataSetBase: public DataSetIF, - public SerializeIF, - public HasReturnvaluesIF { -public: - - /** - * @brief Creates an empty dataset. Use registerVariable or - * supply a pointer to this dataset to PoolVariable - * initializations to register pool variables. - */ - DataSetBase(PoolVariableIF** registeredVariablesArray, - const size_t maxFillCount); - virtual~ DataSetBase(); - - /** - * @brief The read call initializes reading out all registered variables. - * @details - * It iterates through the list of registered variables and calls all read() - * functions of the registered pool variables (which read out their values - * from the data pool) which are not write-only. - * In case of an error (e.g. a wrong data type, or an invalid data pool id), - * the operation is aborted and @c INVALID_PARAMETER_DEFINITION returned. - * - * The data pool is locked during the whole read operation and - * freed afterwards.The state changes to "was written" after this operation. - * @return - * - @c RETURN_OK if all variables were read successfully. - * - @c INVALID_PARAMETER_DEFINITION if PID, size or type of the - * requested variable is invalid. - * - @c SET_WAS_ALREADY_READ if read() is called twice without calling - * commit() in between - */ - virtual ReturnValue_t read(uint32_t lockTimeout = - MutexIF::BLOCKING) override; - /** - * @brief The commit call initializes writing back the registered variables. - * @details - * It iterates through the list of registered variables and calls the - * commit() method of the remaining registered variables (which write back - * their values to the pool). - * - * The data pool is locked during the whole commit operation and - * freed afterwards. The state changes to "was committed" after this operation. - * - * If the set does contain at least one variable which is not write-only - * commit() can only be called after read(). If the set only contains - * variables which are write only, commit() can be called without a - * preceding read() call. - * @return - @c RETURN_OK if all variables were read successfully. - * - @c COMMITING_WITHOUT_READING if set was not read yet and - * contains non write-only variables - */ - virtual ReturnValue_t commit(uint32_t lockTimeout = - MutexIF::BLOCKING) override; - - /** - * Register the passed pool variable instance into the data set. - * @param variable - * @return - */ - virtual ReturnValue_t registerVariable( PoolVariableIF* variable) override; - /** - * Provides the means to lock the underlying data structure to ensure - * thread-safety. Default implementation is empty - * @return Always returns -@c RETURN_OK - */ - virtual ReturnValue_t lockDataPool(uint32_t timeoutMs = - MutexIF::BLOCKING) override; - /** - * Provides the means to unlock the underlying data structure to ensure - * thread-safety. Default implementation is empty - * @return Always returns -@c RETURN_OK - */ - virtual ReturnValue_t unlockDataPool() override; - - virtual uint16_t getFillCount() const; - - /* SerializeIF implementations */ - virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, - const size_t maxSize, - SerializeIF::Endianness streamEndianness) const override; - virtual size_t getSerializedSize() const override; - virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - SerializeIF::Endianness streamEndianness) override; - -protected: - /** - * @brief The fill_count attribute ensures that the variables - * register in the correct array position and that the maximum - * number of variables is not exceeded. - */ - uint16_t fillCount = 0; - /** - * States of the seet. - */ - enum class States { - DATA_SET_UNINITIALISED, //!< DATA_SET_UNINITIALISED - DATA_SET_WAS_READ //!< DATA_SET_WAS_READ - }; - /** - * @brief state manages the internal state of the data set, - * which is important e.g. for the behavior on destruction. - */ - States state = States::DATA_SET_UNINITIALISED; - - /** - * @brief This array represents all pool variables registered in this set. - * Child classes can use a static or dynamic container to create - * an array of registered variables and assign the first entry here. - */ - PoolVariableIF** registeredVariables = nullptr; - const size_t maxFillCount = 0; - -private: - ReturnValue_t readVariable(uint16_t count); - void handleAlreadyReadDatasetCommit(uint32_t lockTimeout); - ReturnValue_t handleUnreadDatasetCommit(uint32_t lockTimeout); -}; - -#endif /* FRAMEWORK_DATAPOOL_DATASETBASE_H_ */ +#ifndef FRAMEWORK_DATAPOOL_DATASETBASE_H_ +#define FRAMEWORK_DATAPOOL_DATASETBASE_H_ +#include "../datapool/DataSetIF.h" +#include "../datapool/PoolVariableIF.h" +#include "../ipc/MutexIF.h" + +/** + * @brief The DataSetBase class manages a set of locally checked out variables. + * @details + * This class manages a list, where a set of local variables (or pool variables) + * are registered. They are checked-out (i.e. their values are looked + * up and copied) with the read call. After the user finishes working with the + * pool variables, he can write back all variable values to the pool with + * the commit call. The data set manages locking and freeing the data pool, + * to ensure that all values are read and written back at once. + * + * An internal state manages usage of this class. Variables may only be + * registered before the read call is made, and the commit call only + * after the read call. + * + * If pool variables are writable and not committed until destruction + * of the set, the DataSet class automatically sets the valid flag in the + * data pool to invalid (without) changing the variable's value. + * + * The base class lockDataPool und unlockDataPool implementation are empty + * and should be implemented to protect the underlying pool type. + * @author Bastian Baetz + * @ingroup data_pool + */ +class DataSetBase: public DataSetIF, + public SerializeIF, + public HasReturnvaluesIF { +public: + + /** + * @brief Creates an empty dataset. Use registerVariable or + * supply a pointer to this dataset to PoolVariable + * initializations to register pool variables. + */ + DataSetBase(PoolVariableIF** registeredVariablesArray, + const size_t maxFillCount); + virtual~ DataSetBase(); + + /** + * @brief The read call initializes reading out all registered variables. + * @details + * It iterates through the list of registered variables and calls all read() + * functions of the registered pool variables (which read out their values + * from the data pool) which are not write-only. + * In case of an error (e.g. a wrong data type, or an invalid data pool id), + * the operation is aborted and @c INVALID_PARAMETER_DEFINITION returned. + * + * The data pool is locked during the whole read operation and + * freed afterwards.The state changes to "was written" after this operation. + * @return + * - @c RETURN_OK if all variables were read successfully. + * - @c INVALID_PARAMETER_DEFINITION if PID, size or type of the + * requested variable is invalid. + * - @c SET_WAS_ALREADY_READ if read() is called twice without calling + * commit() in between + */ + virtual ReturnValue_t read(uint32_t lockTimeout = + MutexIF::BLOCKING) override; + /** + * @brief The commit call initializes writing back the registered variables. + * @details + * It iterates through the list of registered variables and calls the + * commit() method of the remaining registered variables (which write back + * their values to the pool). + * + * The data pool is locked during the whole commit operation and + * freed afterwards. The state changes to "was committed" after this operation. + * + * If the set does contain at least one variable which is not write-only + * commit() can only be called after read(). If the set only contains + * variables which are write only, commit() can be called without a + * preceding read() call. + * @return - @c RETURN_OK if all variables were read successfully. + * - @c COMMITING_WITHOUT_READING if set was not read yet and + * contains non write-only variables + */ + virtual ReturnValue_t commit(uint32_t lockTimeout = + MutexIF::BLOCKING) override; + + /** + * Register the passed pool variable instance into the data set. + * @param variable + * @return + */ + virtual ReturnValue_t registerVariable( PoolVariableIF* variable) override; + /** + * Provides the means to lock the underlying data structure to ensure + * thread-safety. Default implementation is empty + * @return Always returns -@c RETURN_OK + */ + virtual ReturnValue_t lockDataPool(uint32_t timeoutMs = + MutexIF::BLOCKING) override; + /** + * Provides the means to unlock the underlying data structure to ensure + * thread-safety. Default implementation is empty + * @return Always returns -@c RETURN_OK + */ + virtual ReturnValue_t unlockDataPool() override; + + virtual uint16_t getFillCount() const; + + /* SerializeIF implementations */ + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t maxSize, + SerializeIF::Endianness streamEndianness) const override; + virtual size_t getSerializedSize() const override; + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + SerializeIF::Endianness streamEndianness) override; + +protected: + /** + * @brief The fill_count attribute ensures that the variables + * register in the correct array position and that the maximum + * number of variables is not exceeded. + */ + uint16_t fillCount = 0; + /** + * States of the seet. + */ + enum class States { + DATA_SET_UNINITIALISED, //!< DATA_SET_UNINITIALISED + DATA_SET_WAS_READ //!< DATA_SET_WAS_READ + }; + /** + * @brief state manages the internal state of the data set, + * which is important e.g. for the behavior on destruction. + */ + States state = States::DATA_SET_UNINITIALISED; + + /** + * @brief This array represents all pool variables registered in this set. + * Child classes can use a static or dynamic container to create + * an array of registered variables and assign the first entry here. + */ + PoolVariableIF** registeredVariables = nullptr; + const size_t maxFillCount = 0; + +private: + ReturnValue_t readVariable(uint16_t count); + void handleAlreadyReadDatasetCommit(uint32_t lockTimeout); + ReturnValue_t handleUnreadDatasetCommit(uint32_t lockTimeout); +}; + +#endif /* FRAMEWORK_DATAPOOL_DATASETBASE_H_ */ diff --git a/datapool/DataSetIF.h b/datapool/DataSetIF.h index 437f324f..88e82e50 100644 --- a/datapool/DataSetIF.h +++ b/datapool/DataSetIF.h @@ -1,62 +1,62 @@ -#ifndef DATASETIF_H_ -#define DATASETIF_H_ - -#include -#include -class PoolVariableIF; - -/** - * @brief This class defines a small interface to register on a DataSet. - * - * @details - * Currently, the only purpose of this interface is to provide a - * method for locally checked-out variables to register on a data set. - * Still, it may become useful for other purposes as well. - * @author Bastian Baetz - * @ingroup data_pool - */ -class DataSetIF { -public: - static constexpr uint8_t INTERFACE_ID = CLASS_ID::DATA_SET_CLASS; - static constexpr ReturnValue_t INVALID_PARAMETER_DEFINITION = - MAKE_RETURN_CODE( 0x01 ); - static constexpr ReturnValue_t SET_WAS_ALREADY_READ = MAKE_RETURN_CODE( 0x02 ); - static constexpr ReturnValue_t COMMITING_WITHOUT_READING = - MAKE_RETURN_CODE(0x03); - - static constexpr ReturnValue_t DATA_SET_UNINITIALISED = MAKE_RETURN_CODE( 0x04 ); - static constexpr ReturnValue_t DATA_SET_FULL = MAKE_RETURN_CODE( 0x05 ); - static constexpr ReturnValue_t POOL_VAR_NULL = MAKE_RETURN_CODE( 0x06 ); - - /** - * @brief This is an empty virtual destructor, - * as it is proposed for C++ interfaces. - */ - virtual ~DataSetIF() {} - - virtual ReturnValue_t read(uint32_t lockTimeout) = 0; - virtual ReturnValue_t commit(uint32_t lockTimeout) = 0; - /** - * @brief This operation provides a method to register local data pool - * variables to register in a data set by passing itself - * to this DataSet operation. - */ - virtual ReturnValue_t registerVariable(PoolVariableIF* variable) = 0; - - virtual uint16_t getFillCount() const = 0; -private: - /** - * @brief Most underlying data structures will have a pool like structure - * and will require a lock and unlock mechanism to ensure - * thread-safety - * @return Lock operation result - */ - virtual ReturnValue_t lockDataPool(uint32_t timeoutMs) = 0; - /** - * @brief Unlock call corresponding to the lock call. - * @return Unlock operation result - */ - virtual ReturnValue_t unlockDataPool() = 0; -}; - -#endif /* DATASETIF_H_ */ +#ifndef DATASETIF_H_ +#define DATASETIF_H_ + +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../timemanager/Clock.h" +class PoolVariableIF; + +/** + * @brief This class defines a small interface to register on a DataSet. + * + * @details + * Currently, the only purpose of this interface is to provide a + * method for locally checked-out variables to register on a data set. + * Still, it may become useful for other purposes as well. + * @author Bastian Baetz + * @ingroup data_pool + */ +class DataSetIF { +public: + static constexpr uint8_t INTERFACE_ID = CLASS_ID::DATA_SET_CLASS; + static constexpr ReturnValue_t INVALID_PARAMETER_DEFINITION = + MAKE_RETURN_CODE( 0x01 ); + static constexpr ReturnValue_t SET_WAS_ALREADY_READ = MAKE_RETURN_CODE( 0x02 ); + static constexpr ReturnValue_t COMMITING_WITHOUT_READING = + MAKE_RETURN_CODE(0x03); + + static constexpr ReturnValue_t DATA_SET_UNINITIALISED = MAKE_RETURN_CODE( 0x04 ); + static constexpr ReturnValue_t DATA_SET_FULL = MAKE_RETURN_CODE( 0x05 ); + static constexpr ReturnValue_t POOL_VAR_NULL = MAKE_RETURN_CODE( 0x06 ); + + /** + * @brief This is an empty virtual destructor, + * as it is proposed for C++ interfaces. + */ + virtual ~DataSetIF() {} + + virtual ReturnValue_t read(uint32_t lockTimeout) = 0; + virtual ReturnValue_t commit(uint32_t lockTimeout) = 0; + /** + * @brief This operation provides a method to register local data pool + * variables to register in a data set by passing itself + * to this DataSet operation. + */ + virtual ReturnValue_t registerVariable(PoolVariableIF* variable) = 0; + + virtual uint16_t getFillCount() const = 0; +private: + /** + * @brief Most underlying data structures will have a pool like structure + * and will require a lock and unlock mechanism to ensure + * thread-safety + * @return Lock operation result + */ + virtual ReturnValue_t lockDataPool(uint32_t timeoutMs) = 0; + /** + * @brief Unlock call corresponding to the lock call. + * @return Unlock operation result + */ + virtual ReturnValue_t unlockDataPool() = 0; +}; + +#endif /* DATASETIF_H_ */ diff --git a/datapool/HkSwitchHelper.cpp b/datapool/HkSwitchHelper.cpp index cf5114f7..5a59f94c 100644 --- a/datapool/HkSwitchHelper.cpp +++ b/datapool/HkSwitchHelper.cpp @@ -1,75 +1,75 @@ -#include -#include - -HkSwitchHelper::HkSwitchHelper(EventReportingProxyIF* eventProxy) : - commandActionHelper(this), eventProxy(eventProxy) { - actionQueue = QueueFactory::instance()->createMessageQueue(); -} - -HkSwitchHelper::~HkSwitchHelper() { - // TODO Auto-generated destructor stub -} - -ReturnValue_t HkSwitchHelper::initialize() { - ReturnValue_t result = commandActionHelper.initialize(); - - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - return result; -} - -ReturnValue_t HkSwitchHelper::performOperation(uint8_t operationCode) { - CommandMessage command; - while (actionQueue->receiveMessage(&command) == HasReturnvaluesIF::RETURN_OK) { - ReturnValue_t result = commandActionHelper.handleReply(&command); - if (result == HasReturnvaluesIF::RETURN_OK) { - continue; - } - command.setToUnknownCommand(); - actionQueue->reply(&command); - } - - return HasReturnvaluesIF::RETURN_OK; -} - -void HkSwitchHelper::stepSuccessfulReceived(ActionId_t actionId, uint8_t step) { -} - -void HkSwitchHelper::stepFailedReceived(ActionId_t actionId, uint8_t step, - ReturnValue_t returnCode) { - eventProxy->forwardEvent(SWITCHING_TM_FAILED, returnCode, actionId); -} - -void HkSwitchHelper::dataReceived(ActionId_t actionId, const uint8_t* data, - uint32_t size) { -} - -void HkSwitchHelper::completionSuccessfulReceived(ActionId_t actionId) { -} - -void HkSwitchHelper::completionFailedReceived(ActionId_t actionId, - ReturnValue_t returnCode) { - eventProxy->forwardEvent(SWITCHING_TM_FAILED, returnCode, actionId); -} - -ReturnValue_t HkSwitchHelper::switchHK(SerializeIF* sids, bool enable) { -// ActionId_t action = HKService::DISABLE_HK; -// if (enable) { -// action = HKService::ENABLE_HK; -// } -// -// ReturnValue_t result = commandActionHelper.commandAction( -// objects::PUS_HK_SERVICE, action, sids); -// -// if (result != HasReturnvaluesIF::RETURN_OK) { -// eventProxy->forwardEvent(SWITCHING_TM_FAILED, result); -// } -// return result; - return HasReturnvaluesIF::RETURN_OK; -} - -MessageQueueIF* HkSwitchHelper::getCommandQueuePtr() { - return actionQueue; -} +#include "../datapool/HkSwitchHelper.h" +#include "../ipc/QueueFactory.h" + +HkSwitchHelper::HkSwitchHelper(EventReportingProxyIF* eventProxy) : + commandActionHelper(this), eventProxy(eventProxy) { + actionQueue = QueueFactory::instance()->createMessageQueue(); +} + +HkSwitchHelper::~HkSwitchHelper() { + // TODO Auto-generated destructor stub +} + +ReturnValue_t HkSwitchHelper::initialize() { + ReturnValue_t result = commandActionHelper.initialize(); + + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + return result; +} + +ReturnValue_t HkSwitchHelper::performOperation(uint8_t operationCode) { + CommandMessage command; + while (actionQueue->receiveMessage(&command) == HasReturnvaluesIF::RETURN_OK) { + ReturnValue_t result = commandActionHelper.handleReply(&command); + if (result == HasReturnvaluesIF::RETURN_OK) { + continue; + } + command.setToUnknownCommand(); + actionQueue->reply(&command); + } + + return HasReturnvaluesIF::RETURN_OK; +} + +void HkSwitchHelper::stepSuccessfulReceived(ActionId_t actionId, uint8_t step) { +} + +void HkSwitchHelper::stepFailedReceived(ActionId_t actionId, uint8_t step, + ReturnValue_t returnCode) { + eventProxy->forwardEvent(SWITCHING_TM_FAILED, returnCode, actionId); +} + +void HkSwitchHelper::dataReceived(ActionId_t actionId, const uint8_t* data, + uint32_t size) { +} + +void HkSwitchHelper::completionSuccessfulReceived(ActionId_t actionId) { +} + +void HkSwitchHelper::completionFailedReceived(ActionId_t actionId, + ReturnValue_t returnCode) { + eventProxy->forwardEvent(SWITCHING_TM_FAILED, returnCode, actionId); +} + +ReturnValue_t HkSwitchHelper::switchHK(SerializeIF* sids, bool enable) { +// ActionId_t action = HKService::DISABLE_HK; +// if (enable) { +// action = HKService::ENABLE_HK; +// } +// +// ReturnValue_t result = commandActionHelper.commandAction( +// objects::PUS_HK_SERVICE, action, sids); +// +// if (result != HasReturnvaluesIF::RETURN_OK) { +// eventProxy->forwardEvent(SWITCHING_TM_FAILED, result); +// } +// return result; + return HasReturnvaluesIF::RETURN_OK; +} + +MessageQueueIF* HkSwitchHelper::getCommandQueuePtr() { + return actionQueue; +} diff --git a/datapool/HkSwitchHelper.h b/datapool/HkSwitchHelper.h index 1a3b6275..de34ab23 100644 --- a/datapool/HkSwitchHelper.h +++ b/datapool/HkSwitchHelper.h @@ -1,46 +1,46 @@ -#ifndef FRAMEWORK_DATAPOOL_HKSWITCHHELPER_H_ -#define FRAMEWORK_DATAPOOL_HKSWITCHHELPER_H_ - -#include -#include -#include - -//TODO this class violations separation between mission and framework -//but it is only a transitional solution until the Datapool is -//implemented decentrally - -class HkSwitchHelper: public ExecutableObjectIF, public CommandsActionsIF { -public: - - static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::HK; - static const Event SWITCHING_TM_FAILED = MAKE_EVENT(1, SEVERITY::LOW); //!< Commanding the HK Service failed, p1: error code, p2 action: 0 disable / 1 enable - - HkSwitchHelper(EventReportingProxyIF *eventProxy); - virtual ~HkSwitchHelper(); - - ReturnValue_t initialize(); - - virtual ReturnValue_t performOperation(uint8_t operationCode = 0); - - ReturnValue_t switchHK(SerializeIF *sids, bool enable); - - virtual void setTaskIF(PeriodicTaskIF* task_){}; - -protected: - virtual void stepSuccessfulReceived(ActionId_t actionId, uint8_t step); - virtual void stepFailedReceived(ActionId_t actionId, uint8_t step, - ReturnValue_t returnCode); - virtual void dataReceived(ActionId_t actionId, const uint8_t* data, - uint32_t size); - virtual void completionSuccessfulReceived(ActionId_t actionId); - virtual void completionFailedReceived(ActionId_t actionId, - ReturnValue_t returnCode); - virtual MessageQueueIF* getCommandQueuePtr(); - -private: - CommandActionHelper commandActionHelper; - MessageQueueIF* actionQueue; - EventReportingProxyIF *eventProxy; -}; - -#endif /* FRAMEWORK_DATAPOOL_HKSWITCHHELPER_H_ */ +#ifndef FRAMEWORK_DATAPOOL_HKSWITCHHELPER_H_ +#define FRAMEWORK_DATAPOOL_HKSWITCHHELPER_H_ + +#include "../tasks/ExecutableObjectIF.h" +#include "../action/CommandsActionsIF.h" +#include "../events/EventReportingProxyIF.h" + +//TODO this class violations separation between mission and framework +//but it is only a transitional solution until the Datapool is +//implemented decentrally + +class HkSwitchHelper: public ExecutableObjectIF, public CommandsActionsIF { +public: + + static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::HK; + static const Event SWITCHING_TM_FAILED = MAKE_EVENT(1, SEVERITY::LOW); //!< Commanding the HK Service failed, p1: error code, p2 action: 0 disable / 1 enable + + HkSwitchHelper(EventReportingProxyIF *eventProxy); + virtual ~HkSwitchHelper(); + + ReturnValue_t initialize(); + + virtual ReturnValue_t performOperation(uint8_t operationCode = 0); + + ReturnValue_t switchHK(SerializeIF *sids, bool enable); + + virtual void setTaskIF(PeriodicTaskIF* task_){}; + +protected: + virtual void stepSuccessfulReceived(ActionId_t actionId, uint8_t step); + virtual void stepFailedReceived(ActionId_t actionId, uint8_t step, + ReturnValue_t returnCode); + virtual void dataReceived(ActionId_t actionId, const uint8_t* data, + uint32_t size); + virtual void completionSuccessfulReceived(ActionId_t actionId); + virtual void completionFailedReceived(ActionId_t actionId, + ReturnValue_t returnCode); + virtual MessageQueueIF* getCommandQueuePtr(); + +private: + CommandActionHelper commandActionHelper; + MessageQueueIF* actionQueue; + EventReportingProxyIF *eventProxy; +}; + +#endif /* FRAMEWORK_DATAPOOL_HKSWITCHHELPER_H_ */ diff --git a/datapool/PoolEntry.cpp b/datapool/PoolEntry.cpp index d535a72b..a21d521f 100644 --- a/datapool/PoolEntry.cpp +++ b/datapool/PoolEntry.cpp @@ -1,87 +1,87 @@ -#include -#include -#include -#include - -template -PoolEntry::PoolEntry(std::initializer_list initValue, uint8_t setLength, - bool setValid ) : length(setLength), valid(setValid) { - this->address = new T[this->length]; - if(initValue.size() == 0) { - std::memset(this->address, 0, this->getByteSize()); - } - else if (initValue.size() != setLength){ - sif::warning << "PoolEntry: setLength is not equal to initializer list" - "length! Performing zero initialization with given setLength" - << std::endl; - std::memset(this->address, 0, this->getByteSize()); - } - else { - std::copy(initValue.begin(), initValue.end(), this->address); - } -} - -template -PoolEntry::PoolEntry( T* initValue, uint8_t setLength, bool setValid ) : - length(setLength), valid(setValid) { - this->address = new T[this->length]; - if (initValue != nullptr) { - std::memcpy(this->address, initValue, this->getByteSize() ); - } else { - std::memset(this->address, 0, this->getByteSize() ); - } -} - -//As the data pool is global, this dtor is only be called on program exit. -//Warning! Never copy pool entries! -template -PoolEntry::~PoolEntry() { - delete[] this->address; -} - -template -uint16_t PoolEntry::getByteSize() { - return ( sizeof(T) * this->length ); -} - -template -uint8_t PoolEntry::getSize() { - return this->length; -} - -template -void* PoolEntry::getRawData() { - return this->address; -} - -template -void PoolEntry::setValid(bool isValid) { - this->valid = isValid; -} - -template -bool PoolEntry::getValid() { - return valid; -} - -template -void PoolEntry::print() { - sif::debug << "Pool Entry Validity: " << - (this->valid? " (valid) " : " (invalid) ") << std::endl; - arrayprinter::print(reinterpret_cast(address), length); - sif::debug << std::dec << std::endl; -} - -template -Type PoolEntry::getType() { - return PodTypeConversion::type; -} - -template class PoolEntry; -template class PoolEntry; -template class PoolEntry; -template class PoolEntry; -template class PoolEntry; -template class PoolEntry; -template class PoolEntry; -template class PoolEntry; +#include "../datapool/PoolEntry.h" +#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../globalfunctions/arrayprinter.h" +#include + +template +PoolEntry::PoolEntry(std::initializer_list initValue, uint8_t setLength, + bool setValid ) : length(setLength), valid(setValid) { + this->address = new T[this->length]; + if(initValue.size() == 0) { + std::memset(this->address, 0, this->getByteSize()); + } + else if (initValue.size() != setLength){ + sif::warning << "PoolEntry: setLength is not equal to initializer list" + "length! Performing zero initialization with given setLength" + << std::endl; + std::memset(this->address, 0, this->getByteSize()); + } + else { + std::copy(initValue.begin(), initValue.end(), this->address); + } +} + +template +PoolEntry::PoolEntry( T* initValue, uint8_t setLength, bool setValid ) : + length(setLength), valid(setValid) { + this->address = new T[this->length]; + if (initValue != nullptr) { + std::memcpy(this->address, initValue, this->getByteSize() ); + } else { + std::memset(this->address, 0, this->getByteSize() ); + } +} + +//As the data pool is global, this dtor is only be called on program exit. +//Warning! Never copy pool entries! +template +PoolEntry::~PoolEntry() { + delete[] this->address; +} + +template +uint16_t PoolEntry::getByteSize() { + return ( sizeof(T) * this->length ); +} + +template +uint8_t PoolEntry::getSize() { + return this->length; +} + +template +void* PoolEntry::getRawData() { + return this->address; +} + +template +void PoolEntry::setValid(bool isValid) { + this->valid = isValid; +} + +template +bool PoolEntry::getValid() { + return valid; +} + +template +void PoolEntry::print() { + sif::debug << "Pool Entry Validity: " << + (this->valid? " (valid) " : " (invalid) ") << std::endl; + arrayprinter::print(reinterpret_cast(address), length); + sif::debug << std::dec << std::endl; +} + +template +Type PoolEntry::getType() { + return PodTypeConversion::type; +} + +template class PoolEntry; +template class PoolEntry; +template class PoolEntry; +template class PoolEntry; +template class PoolEntry; +template class PoolEntry; +template class PoolEntry; +template class PoolEntry; diff --git a/datapool/PoolEntry.h b/datapool/PoolEntry.h index 1a22bb63..67891af8 100644 --- a/datapool/PoolEntry.h +++ b/datapool/PoolEntry.h @@ -1,130 +1,130 @@ -#ifndef FRAMEWORK_DATAPOOL_POOLENTRY_H_ -#define FRAMEWORK_DATAPOOL_POOLENTRY_H_ - -#include - -#include -#include -#include - -/** - * @brief This is a small helper class that defines a single data pool entry. - * @details - * The helper is used to store all information together with the data as a - * single data pool entry. The content's type is defined by the template - * argument. - * - * It is prepared for use with plain old data types, but may be - * extended to complex types if necessary. It can be initialized with a - * certain value, size and validity flag. - * - * It holds a pointer to the real data and offers methods to access this data - * and to acquire additional information (such as validity and array/byte size). - * It is NOT intended to be used outside DataPool implementations as it performs - * dynamic memory allocation. - * - * @ingroup data_pool - */ -template -class PoolEntry : public PoolEntryIF { -public: - static_assert(not std::is_same::value, - "Do not use boolean for the PoolEntry type, use uint8_t " - "instead! The ECSS standard defines a boolean as a one bit " - "field. Therefore it is preferred to store a boolean as an " - "uint8_t"); - /** - * @brief In the classe's constructor, space is allocated on the heap and - * potential init values are copied to that space. - * @details - * Not passing any arguments will initialize an non-array pool entry - * (setLength = 1) with an initial invalid state. - * Please note that if an initializer list is passed, the correct - * corresponding length should be passed too, otherwise a zero - * initialization will be performed with the given setLength. - * @param initValue - * Initializer list with values to initialize with, for example {0,0} to - * initialize the two entries to zero. - * @param setLength - * Defines the array length of this entry. Should be equal to the - * intializer list length. - * @param setValid - * Sets the initialization flag. It is invalid by default. - */ - PoolEntry(std::initializer_list initValue = {}, uint8_t setLength = 1, - bool setValid = false); - /** - * @brief In the classe's constructor, space is allocated on the heap and - * potential init values are copied to that space. - * @param initValue - * A pointer to the single value or array that holds the init value. - * With the default value (nullptr), the entry is initalized with all 0. - * @param setLength - * Defines the array length of this entry. - * @param setValid - * Sets the initialization flag. It is invalid by default. - */ - PoolEntry(T* initValue, uint8_t setLength = 1, bool setValid = false); - - //! Explicitely deleted copy ctor, copying is not allowed! - PoolEntry(const PoolEntry&) = delete; - //! Explicitely deleted copy assignment, copying is not allowed! - PoolEntry& operator=(const PoolEntry&) = delete; - - /** - * @brief The allocated memory for the variable is freed - * in the destructor. - * @details - * As the data pool is global, this dtor is only called on program exit. - * PoolEntries shall never be copied, as a copy might delete the variable - * on the heap. - */ - ~PoolEntry(); - - /** - * @brief This is the address pointing to the allocated memory. - */ - T* address; - /** - * @brief This attribute stores the length information. - */ - uint8_t length; - /** - * @brief Here, the validity information for a variable is stored. - * Every entry (single variable or vector) has one valid flag. - */ - uint8_t valid; - /** - * @brief getSize returns the array size of the entry. - * @details A single parameter has size 1. - */ - uint8_t getSize(); - /** - * @brief This operation returns the size in bytes. - * @details The size is calculated by sizeof(type) * array_size. - */ - uint16_t getByteSize(); - /** - * @brief This operation returns a the address pointer casted to void*. - */ - void* getRawData(); - /** - * @brief This method allows to set the valid information - * of the pool entry. - */ - void setValid( bool isValid ); - /** - * @brief This method allows to get the valid information - * of the pool entry. - */ - bool getValid(); - /** - * @brief This is a debug method that prints all values and the valid - * information to the screen. It prints all array entries in a row. - */ - void print(); - - Type getType(); -}; - -#endif /* POOLENTRY_H_ */ +#ifndef FRAMEWORK_DATAPOOL_POOLENTRY_H_ +#define FRAMEWORK_DATAPOOL_POOLENTRY_H_ + +#include "../datapool/PoolEntryIF.h" + +#include +#include +#include + +/** + * @brief This is a small helper class that defines a single data pool entry. + * @details + * The helper is used to store all information together with the data as a + * single data pool entry. The content's type is defined by the template + * argument. + * + * It is prepared for use with plain old data types, but may be + * extended to complex types if necessary. It can be initialized with a + * certain value, size and validity flag. + * + * It holds a pointer to the real data and offers methods to access this data + * and to acquire additional information (such as validity and array/byte size). + * It is NOT intended to be used outside DataPool implementations as it performs + * dynamic memory allocation. + * + * @ingroup data_pool + */ +template +class PoolEntry : public PoolEntryIF { +public: + static_assert(not std::is_same::value, + "Do not use boolean for the PoolEntry type, use uint8_t " + "instead! The ECSS standard defines a boolean as a one bit " + "field. Therefore it is preferred to store a boolean as an " + "uint8_t"); + /** + * @brief In the classe's constructor, space is allocated on the heap and + * potential init values are copied to that space. + * @details + * Not passing any arguments will initialize an non-array pool entry + * (setLength = 1) with an initial invalid state. + * Please note that if an initializer list is passed, the correct + * corresponding length should be passed too, otherwise a zero + * initialization will be performed with the given setLength. + * @param initValue + * Initializer list with values to initialize with, for example {0,0} to + * initialize the two entries to zero. + * @param setLength + * Defines the array length of this entry. Should be equal to the + * intializer list length. + * @param setValid + * Sets the initialization flag. It is invalid by default. + */ + PoolEntry(std::initializer_list initValue = {}, uint8_t setLength = 1, + bool setValid = false); + /** + * @brief In the classe's constructor, space is allocated on the heap and + * potential init values are copied to that space. + * @param initValue + * A pointer to the single value or array that holds the init value. + * With the default value (nullptr), the entry is initalized with all 0. + * @param setLength + * Defines the array length of this entry. + * @param setValid + * Sets the initialization flag. It is invalid by default. + */ + PoolEntry(T* initValue, uint8_t setLength = 1, bool setValid = false); + + //! Explicitely deleted copy ctor, copying is not allowed! + PoolEntry(const PoolEntry&) = delete; + //! Explicitely deleted copy assignment, copying is not allowed! + PoolEntry& operator=(const PoolEntry&) = delete; + + /** + * @brief The allocated memory for the variable is freed + * in the destructor. + * @details + * As the data pool is global, this dtor is only called on program exit. + * PoolEntries shall never be copied, as a copy might delete the variable + * on the heap. + */ + ~PoolEntry(); + + /** + * @brief This is the address pointing to the allocated memory. + */ + T* address; + /** + * @brief This attribute stores the length information. + */ + uint8_t length; + /** + * @brief Here, the validity information for a variable is stored. + * Every entry (single variable or vector) has one valid flag. + */ + uint8_t valid; + /** + * @brief getSize returns the array size of the entry. + * @details A single parameter has size 1. + */ + uint8_t getSize(); + /** + * @brief This operation returns the size in bytes. + * @details The size is calculated by sizeof(type) * array_size. + */ + uint16_t getByteSize(); + /** + * @brief This operation returns a the address pointer casted to void*. + */ + void* getRawData(); + /** + * @brief This method allows to set the valid information + * of the pool entry. + */ + void setValid( bool isValid ); + /** + * @brief This method allows to get the valid information + * of the pool entry. + */ + bool getValid(); + /** + * @brief This is a debug method that prints all values and the valid + * information to the screen. It prints all array entries in a row. + */ + void print(); + + Type getType(); +}; + +#endif /* POOLENTRY_H_ */ diff --git a/datapool/PoolEntryIF.h b/datapool/PoolEntryIF.h index a075436e..a9fb44ef 100644 --- a/datapool/PoolEntryIF.h +++ b/datapool/PoolEntryIF.h @@ -1,63 +1,63 @@ -#ifndef FRAMEWORK_DATAPOOL_POOLENTRYIF_H_ -#define FRAMEWORK_DATAPOOL_POOLENTRYIF_H_ - -#include -#include - -/** - * @brief This interface defines the access possibilities to a - * single data pool entry. - * @details - * The interface provides methods to determine the size and the validity - * information of a value. It also defines a method to receive a pointer to the - * raw data content. It is mainly used by DataPool itself, but also as a - * return pointer. - * - * @author Bastian Baetz - * @ingroup data_pool - * - */ -class PoolEntryIF { -public: - /** - * @brief This is an empty virtual destructor, - * as it is required for C++ interfaces. - */ - virtual ~PoolEntryIF() { - } - /** - * @brief getSize returns the array size of the entry. - * A single variable parameter has size 1. - */ - virtual uint8_t getSize() = 0; - /** - * @brief This operation returns the size in bytes, which is calculated by - * sizeof(type) * array_size. - */ - virtual uint16_t getByteSize() = 0; - /** - * @brief This operation returns a the address pointer casted to void*. - */ - virtual void* getRawData() = 0; - /** - * @brief This method allows to set the valid information of the pool entry. - */ - virtual void setValid(bool isValid) = 0; - /** - * @brief This method allows to set the valid information of the pool entry. - */ - virtual bool getValid() = 0; - /** - * @brief This is a debug method that prints all values and the valid - * information to the screen. It prints all array entries in a row. - * @details - * Also displays whether the pool entry is valid or invalid. - */ - virtual void print() = 0; - /** - * Returns the type of the entry. - */ - virtual Type getType() = 0; -}; - -#endif /* POOLENTRYIF_H_ */ +#ifndef FRAMEWORK_DATAPOOL_POOLENTRYIF_H_ +#define FRAMEWORK_DATAPOOL_POOLENTRYIF_H_ + +#include "../globalfunctions/Type.h" +#include + +/** + * @brief This interface defines the access possibilities to a + * single data pool entry. + * @details + * The interface provides methods to determine the size and the validity + * information of a value. It also defines a method to receive a pointer to the + * raw data content. It is mainly used by DataPool itself, but also as a + * return pointer. + * + * @author Bastian Baetz + * @ingroup data_pool + * + */ +class PoolEntryIF { +public: + /** + * @brief This is an empty virtual destructor, + * as it is required for C++ interfaces. + */ + virtual ~PoolEntryIF() { + } + /** + * @brief getSize returns the array size of the entry. + * A single variable parameter has size 1. + */ + virtual uint8_t getSize() = 0; + /** + * @brief This operation returns the size in bytes, which is calculated by + * sizeof(type) * array_size. + */ + virtual uint16_t getByteSize() = 0; + /** + * @brief This operation returns a the address pointer casted to void*. + */ + virtual void* getRawData() = 0; + /** + * @brief This method allows to set the valid information of the pool entry. + */ + virtual void setValid(bool isValid) = 0; + /** + * @brief This method allows to set the valid information of the pool entry. + */ + virtual bool getValid() = 0; + /** + * @brief This is a debug method that prints all values and the valid + * information to the screen. It prints all array entries in a row. + * @details + * Also displays whether the pool entry is valid or invalid. + */ + virtual void print() = 0; + /** + * Returns the type of the entry. + */ + virtual Type getType() = 0; +}; + +#endif /* POOLENTRYIF_H_ */ diff --git a/datapool/PoolRawAccessHelper.cpp b/datapool/PoolRawAccessHelper.cpp index 2324a56c..272bb502 100644 --- a/datapool/PoolRawAccessHelper.cpp +++ b/datapool/PoolRawAccessHelper.cpp @@ -5,10 +5,10 @@ * @author R. Mueller */ -#include -#include -#include -#include +#include "../datapool/PoolRawAccessHelper.h" +#include "../datapoolglob/GlobalDataSet.h" +#include "../serialize/SerializeAdapter.h" +#include "../serviceinterface/ServiceInterfaceStream.h" #include #include diff --git a/datapool/PoolRawAccessHelper.h b/datapool/PoolRawAccessHelper.h index 0d8f8d6d..a09f7a2f 100644 --- a/datapool/PoolRawAccessHelper.h +++ b/datapool/PoolRawAccessHelper.h @@ -7,9 +7,9 @@ #ifndef FRAMEWORK_DATAPOOL_POOLRAWACCESSHELPER_H_ #define FRAMEWORK_DATAPOOL_POOLRAWACCESSHELPER_H_ -#include -#include -#include +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../datapoolglob/GlobalDataSet.h" +#include "../datapoolglob/PoolRawAccess.h" /** * @brief This helper function simplifies accessing data pool entries diff --git a/datapool/PoolVarList.h b/datapool/PoolVarList.h index 9d6bc461..10c0e074 100644 --- a/datapool/PoolVarList.h +++ b/datapool/PoolVarList.h @@ -1,28 +1,28 @@ -#ifndef POOLVARLIST_H_ -#define POOLVARLIST_H_ - -#include -#include -template -class PoolVarList { -private: - GlobPoolVar variables[n_var]; -public: - PoolVarList( const uint32_t set_id[n_var], DataSetIF* dataSet, PoolVariableIF::ReadWriteMode_t setReadWriteMode ) { - //I really should have a look at the new init list c++ syntax. - if (dataSet == NULL) { - return; - } - for (uint8_t count = 0; count < n_var; count++) { - variables[count].dataPoolId = set_id[count]; - variables[count].readWriteMode = setReadWriteMode; - dataSet->registerVariable(&variables[count]); - } - } - - GlobPoolVar &operator [](int i) { return variables[i]; } -}; - - - -#endif /* POOLVARLIST_H_ */ +#ifndef POOLVARLIST_H_ +#define POOLVARLIST_H_ + +#include "../datapool/PoolVariableIF.h" +#include "../datapoolglob/GlobalPoolVariable.h" +template +class PoolVarList { +private: + GlobPoolVar variables[n_var]; +public: + PoolVarList( const uint32_t set_id[n_var], DataSetIF* dataSet, PoolVariableIF::ReadWriteMode_t setReadWriteMode ) { + //I really should have a look at the new init list c++ syntax. + if (dataSet == NULL) { + return; + } + for (uint8_t count = 0; count < n_var; count++) { + variables[count].dataPoolId = set_id[count]; + variables[count].readWriteMode = setReadWriteMode; + dataSet->registerVariable(&variables[count]); + } + } + + GlobPoolVar &operator [](int i) { return variables[i]; } +}; + + + +#endif /* POOLVARLIST_H_ */ diff --git a/datapool/PoolVariableIF.h b/datapool/PoolVariableIF.h index 30b87839..fc59ccd9 100644 --- a/datapool/PoolVariableIF.h +++ b/datapool/PoolVariableIF.h @@ -1,99 +1,99 @@ -#ifndef FRAMEWORK_DATAPOOL_POOLVARIABLEIF_H_ -#define FRAMEWORK_DATAPOOL_POOLVARIABLEIF_H_ - -#include -#include - -/** - * @brief This interface is used to control data pool - * variable representations. - * @details - * To securely handle data pool variables, all pool entries are locally - * managed by data pool variable access classes, which are called pool - * variables. To ensure a common state of a set of variables needed in a - * function, these local pool variables again are managed by other classes, - * like the DataSet classes. This interface provides unified access to - * local pool variables for such manager classes. - * @author Bastian Baetz - * @ingroup data_pool - */ -class PoolVariableIF : public SerializeIF { - friend class DataSetBase; - friend class GlobDataSet; - friend class LocalDataSet; -public: - static constexpr uint8_t INTERFACE_ID = CLASS_ID::POOL_VARIABLE_IF; - static constexpr ReturnValue_t INVALID_READ_WRITE_MODE = MAKE_RETURN_CODE(0xA0); - - static constexpr bool VALID = 1; - static constexpr bool INVALID = 0; - static constexpr uint32_t NO_PARAMETER = 0xffffffff; - - enum ReadWriteMode_t { - VAR_READ, VAR_WRITE, VAR_READ_WRITE - }; - - /** - * @brief This is an empty virtual destructor, - * as it is proposed for C++ interfaces. - */ - virtual ~PoolVariableIF() {} - /** - * @brief This method returns if the variable is write-only, - * read-write or read-only. - */ - virtual ReadWriteMode_t getReadWriteMode() const = 0; - /** - * @brief This operation shall return the data pool id of the variable. - */ - virtual uint32_t getDataPoolId() const = 0; - /** - * @brief With this call, the valid information of the - * variable is returned. - */ - virtual bool isValid() const = 0; - /** - * @brief With this call, the valid information of the variable is set. - */ - virtual void setValid(bool validity) = 0; - - /** - * @brief The commit call shall write back a newly calculated local - * value to the data pool. - * @details - * It is assumed that these calls are implemented in a thread-safe manner! - */ - virtual ReturnValue_t commit(uint32_t lockTimeout) = 0; - /** - * @brief The read call shall read the value of this parameter from - * the data pool and store the content locally. - * @details - * It is assumbed that these calls are implemented in a thread-safe manner! - */ - virtual ReturnValue_t read(uint32_t lockTimeout) = 0; - -protected: - - /** - * @brief Same as commit with the difference that comitting will be - * performed without a lock - * @return - * This can be used if the lock protection is handled externally - * to avoid the overhead of locking and unlocking consecutively. - * Declared protected to avoid free public usage. - */ - virtual ReturnValue_t readWithoutLock() = 0; - /** - * @brief Same as commit with the difference that comitting will be - * performed without a lock - * @return - * This can be used if the lock protection is handled externally - * to avoid the overhead of locking and unlocking consecutively. - * Declared protected to avoid free public usage. - */ - virtual ReturnValue_t commitWithoutLock() = 0; -}; - -using pool_rwm_t = PoolVariableIF::ReadWriteMode_t; - -#endif /* POOLVARIABLEIF_H_ */ +#ifndef FRAMEWORK_DATAPOOL_POOLVARIABLEIF_H_ +#define FRAMEWORK_DATAPOOL_POOLVARIABLEIF_H_ + +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../serialize/SerializeIF.h" + +/** + * @brief This interface is used to control data pool + * variable representations. + * @details + * To securely handle data pool variables, all pool entries are locally + * managed by data pool variable access classes, which are called pool + * variables. To ensure a common state of a set of variables needed in a + * function, these local pool variables again are managed by other classes, + * like the DataSet classes. This interface provides unified access to + * local pool variables for such manager classes. + * @author Bastian Baetz + * @ingroup data_pool + */ +class PoolVariableIF : public SerializeIF { + friend class DataSetBase; + friend class GlobDataSet; + friend class LocalDataSet; +public: + static constexpr uint8_t INTERFACE_ID = CLASS_ID::POOL_VARIABLE_IF; + static constexpr ReturnValue_t INVALID_READ_WRITE_MODE = MAKE_RETURN_CODE(0xA0); + + static constexpr bool VALID = 1; + static constexpr bool INVALID = 0; + static constexpr uint32_t NO_PARAMETER = 0xffffffff; + + enum ReadWriteMode_t { + VAR_READ, VAR_WRITE, VAR_READ_WRITE + }; + + /** + * @brief This is an empty virtual destructor, + * as it is proposed for C++ interfaces. + */ + virtual ~PoolVariableIF() {} + /** + * @brief This method returns if the variable is write-only, + * read-write or read-only. + */ + virtual ReadWriteMode_t getReadWriteMode() const = 0; + /** + * @brief This operation shall return the data pool id of the variable. + */ + virtual uint32_t getDataPoolId() const = 0; + /** + * @brief With this call, the valid information of the + * variable is returned. + */ + virtual bool isValid() const = 0; + /** + * @brief With this call, the valid information of the variable is set. + */ + virtual void setValid(bool validity) = 0; + + /** + * @brief The commit call shall write back a newly calculated local + * value to the data pool. + * @details + * It is assumed that these calls are implemented in a thread-safe manner! + */ + virtual ReturnValue_t commit(uint32_t lockTimeout) = 0; + /** + * @brief The read call shall read the value of this parameter from + * the data pool and store the content locally. + * @details + * It is assumbed that these calls are implemented in a thread-safe manner! + */ + virtual ReturnValue_t read(uint32_t lockTimeout) = 0; + +protected: + + /** + * @brief Same as commit with the difference that comitting will be + * performed without a lock + * @return + * This can be used if the lock protection is handled externally + * to avoid the overhead of locking and unlocking consecutively. + * Declared protected to avoid free public usage. + */ + virtual ReturnValue_t readWithoutLock() = 0; + /** + * @brief Same as commit with the difference that comitting will be + * performed without a lock + * @return + * This can be used if the lock protection is handled externally + * to avoid the overhead of locking and unlocking consecutively. + * Declared protected to avoid free public usage. + */ + virtual ReturnValue_t commitWithoutLock() = 0; +}; + +using pool_rwm_t = PoolVariableIF::ReadWriteMode_t; + +#endif /* POOLVARIABLEIF_H_ */ diff --git a/datapoolglob/DataPoolAdmin.cpp b/datapoolglob/DataPoolAdmin.cpp index 4d0e5530..669bcc00 100644 --- a/datapoolglob/DataPoolAdmin.cpp +++ b/datapoolglob/DataPoolAdmin.cpp @@ -1,300 +1,300 @@ -#include -#include -#include -#include -#include -#include -#include - -DataPoolAdmin::DataPoolAdmin(object_id_t objectId) : - SystemObject(objectId), storage(NULL), commandQueue(NULL), memoryHelper( - this, NULL), actionHelper(this, NULL) { - commandQueue = QueueFactory::instance()->createMessageQueue(); -} - -DataPoolAdmin::~DataPoolAdmin() { - QueueFactory::instance()->deleteMessageQueue(commandQueue); -} - -ReturnValue_t DataPoolAdmin::performOperation(uint8_t opCode) { - handleCommand(); - return RETURN_OK; -} - -MessageQueueId_t DataPoolAdmin::getCommandQueue() const { - return commandQueue->getId(); -} - -ReturnValue_t DataPoolAdmin::executeAction(ActionId_t actionId, - MessageQueueId_t commandedBy, const uint8_t* data, size_t size) { - if (actionId != SET_VALIDITY) { - return INVALID_ACTION_ID; - } - - if (size != 5) { - return INVALID_PARAMETERS; - } - - uint32_t address = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) - | data[3]; - - uint8_t valid = data[4]; - - uint32_t poolId = glob::dataPool.PIDToDataPoolId(address); - - GlobDataSet mySet; - PoolRawAccess variable(poolId, 0, &mySet, PoolVariableIF::VAR_READ_WRITE); - ReturnValue_t status = mySet.read(); - if (status != RETURN_OK) { - return INVALID_ADDRESS; - } - if (valid != 0) { - variable.setValid(PoolVariableIF::VALID); - } else { - variable.setValid(PoolVariableIF::INVALID); - } - - mySet.commit(); - - return EXECUTION_FINISHED; -} - -ReturnValue_t DataPoolAdmin::getParameter(uint8_t domainId, - uint16_t parameterId, ParameterWrapper* parameterWrapper, - const ParameterWrapper* newValues, uint16_t startAtIndex) { - return HasReturnvaluesIF::RETURN_FAILED; -} - -void DataPoolAdmin::handleCommand() { - CommandMessage command; - ReturnValue_t result = commandQueue->receiveMessage(&command); - if (result != RETURN_OK) { - return; - } - - result = actionHelper.handleActionMessage(&command); - - if (result == HasReturnvaluesIF::RETURN_OK) { - return; - } - - result = handleParameterCommand(&command); - if (result == HasReturnvaluesIF::RETURN_OK) { - return; - } - - result = memoryHelper.handleMemoryCommand(&command); - if (result != RETURN_OK) { - command.setToUnknownCommand(); - commandQueue->reply(&command); - } -} - -ReturnValue_t DataPoolAdmin::handleMemoryLoad(uint32_t address, - const uint8_t* data, size_t size, uint8_t** dataPointer) { - uint32_t poolId = glob::dataPool.PIDToDataPoolId(address); - uint8_t arrayIndex = glob::dataPool.PIDToArrayIndex(address); - GlobDataSet testSet; - PoolRawAccess varToGetSize(poolId, arrayIndex, &testSet, - PoolVariableIF::VAR_READ); - ReturnValue_t status = testSet.read(); - if (status != RETURN_OK) { - return INVALID_ADDRESS; - } - uint8_t typeSize = varToGetSize.getSizeOfType(); - - if (size % typeSize != 0) { - return INVALID_SIZE; - } - - if (size > varToGetSize.getSizeTillEnd()) { - return INVALID_SIZE; - } - const uint8_t* readPosition = data; - - for (; size > 0; size -= typeSize) { - GlobDataSet rawSet; - PoolRawAccess variable(poolId, arrayIndex, &rawSet, - PoolVariableIF::VAR_READ_WRITE); - status = rawSet.read(); - if (status == RETURN_OK) { - status = variable.setEntryFromBigEndian(readPosition, typeSize); - if (status == RETURN_OK) { - status = rawSet.commit(); - } - } - arrayIndex += 1; - readPosition += typeSize; - } - return ACTIVITY_COMPLETED; -} - -ReturnValue_t DataPoolAdmin::handleMemoryDump(uint32_t address, size_t size, - uint8_t** dataPointer, uint8_t* copyHere) { - uint32_t poolId = glob::dataPool.PIDToDataPoolId(address); - uint8_t arrayIndex = glob::dataPool.PIDToArrayIndex(address); - GlobDataSet testSet; - PoolRawAccess varToGetSize(poolId, arrayIndex, &testSet, - PoolVariableIF::VAR_READ); - ReturnValue_t status = testSet.read(); - if (status != RETURN_OK) { - return INVALID_ADDRESS; - } - uint8_t typeSize = varToGetSize.getSizeOfType(); - if (size > varToGetSize.getSizeTillEnd()) { - return INVALID_SIZE; - } - uint8_t* ptrToCopy = copyHere; - for (; size > 0; size -= typeSize) { - GlobDataSet rawSet; - PoolRawAccess variable(poolId, arrayIndex, &rawSet, - PoolVariableIF::VAR_READ); - status = rawSet.read(); - if (status == RETURN_OK) { - size_t temp = 0; - status = variable.getEntryEndianSafe(ptrToCopy, &temp, size); - if (status != RETURN_OK) { - return RETURN_FAILED; - } - } else { - //Error reading parameter. - } - arrayIndex += 1; - ptrToCopy += typeSize; - } - return ACTIVITY_COMPLETED; -} - -ReturnValue_t DataPoolAdmin::initialize() { - ReturnValue_t result = SystemObject::initialize(); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - result = memoryHelper.initialize(commandQueue); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - storage = objectManager->get(objects::IPC_STORE); - if (storage == NULL) { - return HasReturnvaluesIF::RETURN_FAILED; - } - - result = actionHelper.initialize(commandQueue); - - return result; -} - -//mostly identical to ParameterHelper::handleParameterMessage() -ReturnValue_t DataPoolAdmin::handleParameterCommand(CommandMessage* command) { - ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; - switch (command->getCommand()) { - case ParameterMessage::CMD_PARAMETER_DUMP: { - uint8_t domain = HasParametersIF::getDomain( - ParameterMessage::getParameterId(command)); - uint16_t parameterId = HasParametersIF::getMatrixId( - ParameterMessage::getParameterId(command)); - - DataPoolParameterWrapper wrapper; - result = wrapper.set(domain, parameterId); - - if (result == HasReturnvaluesIF::RETURN_OK) { - result = sendParameter(command->getSender(), - ParameterMessage::getParameterId(command), &wrapper); - } - } - break; - case ParameterMessage::CMD_PARAMETER_LOAD: { - - uint8_t domain = HasParametersIF::getDomain( - ParameterMessage::getParameterId(command)); - uint16_t parameterId = HasParametersIF::getMatrixId( - ParameterMessage::getParameterId(command)); - uint8_t index = HasParametersIF::getIndex( - ParameterMessage::getParameterId(command)); - - const uint8_t *storedStream; - size_t storedStreamSize; - result = storage->getData(ParameterMessage::getStoreId(command), - &storedStream, &storedStreamSize); - if (result != HasReturnvaluesIF::RETURN_OK) { - break; - } - - ParameterWrapper streamWrapper; - result = streamWrapper.set(storedStream, storedStreamSize); - if (result != HasReturnvaluesIF::RETURN_OK) { - storage->deleteData(ParameterMessage::getStoreId(command)); - break; - } - - DataPoolParameterWrapper poolWrapper; - result = poolWrapper.set(domain, parameterId); - if (result != HasReturnvaluesIF::RETURN_OK) { - storage->deleteData(ParameterMessage::getStoreId(command)); - break; - } - - result = poolWrapper.copyFrom(&streamWrapper, index); - - storage->deleteData(ParameterMessage::getStoreId(command)); - - if (result == HasReturnvaluesIF::RETURN_OK) { - result = sendParameter(command->getSender(), - ParameterMessage::getParameterId(command), &poolWrapper); - } - } - break; - default: - return HasReturnvaluesIF::RETURN_FAILED; - } - - if (result != HasReturnvaluesIF::RETURN_OK) { - rejectCommand(command->getSender(), result, command->getCommand()); - } - - return HasReturnvaluesIF::RETURN_OK; - -} - -//identical to ParameterHelper::sendParameter() -ReturnValue_t DataPoolAdmin::sendParameter(MessageQueueId_t to, uint32_t id, - const DataPoolParameterWrapper* wrapper) { - size_t serializedSize = wrapper->getSerializedSize(); - - uint8_t *storeElement; - store_address_t address; - - ReturnValue_t result = storage->getFreeElement(&address, serializedSize, - &storeElement); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - size_t storeElementSize = 0; - - result = wrapper->serialize(&storeElement, &storeElementSize, - serializedSize, SerializeIF::Endianness::BIG); - - if (result != HasReturnvaluesIF::RETURN_OK) { - storage->deleteData(address); - return result; - } - - CommandMessage reply; - - ParameterMessage::setParameterDumpReply(&reply, id, address); - - commandQueue->sendMessage(to, &reply); - - return HasReturnvaluesIF::RETURN_OK; -} - -//identical to ParameterHelper::rejectCommand() -void DataPoolAdmin::rejectCommand(MessageQueueId_t to, ReturnValue_t reason, - Command_t initialCommand) { - CommandMessage reply; - reply.setReplyRejected(reason, initialCommand); - commandQueue->sendMessage(to, &reply); -} +#include "../datapoolglob/DataPoolAdmin.h" +#include "../datapoolglob/GlobalDataSet.h" +#include "../datapoolglob/GlobalDataPool.h" +#include "../datapoolglob/PoolRawAccess.h" +#include "../ipc/CommandMessage.h" +#include "../ipc/QueueFactory.h" +#include "../parameters/ParameterMessage.h" + +DataPoolAdmin::DataPoolAdmin(object_id_t objectId) : + SystemObject(objectId), storage(NULL), commandQueue(NULL), memoryHelper( + this, NULL), actionHelper(this, NULL) { + commandQueue = QueueFactory::instance()->createMessageQueue(); +} + +DataPoolAdmin::~DataPoolAdmin() { + QueueFactory::instance()->deleteMessageQueue(commandQueue); +} + +ReturnValue_t DataPoolAdmin::performOperation(uint8_t opCode) { + handleCommand(); + return RETURN_OK; +} + +MessageQueueId_t DataPoolAdmin::getCommandQueue() const { + return commandQueue->getId(); +} + +ReturnValue_t DataPoolAdmin::executeAction(ActionId_t actionId, + MessageQueueId_t commandedBy, const uint8_t* data, size_t size) { + if (actionId != SET_VALIDITY) { + return INVALID_ACTION_ID; + } + + if (size != 5) { + return INVALID_PARAMETERS; + } + + uint32_t address = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) + | data[3]; + + uint8_t valid = data[4]; + + uint32_t poolId = glob::dataPool.PIDToDataPoolId(address); + + GlobDataSet mySet; + PoolRawAccess variable(poolId, 0, &mySet, PoolVariableIF::VAR_READ_WRITE); + ReturnValue_t status = mySet.read(); + if (status != RETURN_OK) { + return INVALID_ADDRESS; + } + if (valid != 0) { + variable.setValid(PoolVariableIF::VALID); + } else { + variable.setValid(PoolVariableIF::INVALID); + } + + mySet.commit(); + + return EXECUTION_FINISHED; +} + +ReturnValue_t DataPoolAdmin::getParameter(uint8_t domainId, + uint16_t parameterId, ParameterWrapper* parameterWrapper, + const ParameterWrapper* newValues, uint16_t startAtIndex) { + return HasReturnvaluesIF::RETURN_FAILED; +} + +void DataPoolAdmin::handleCommand() { + CommandMessage command; + ReturnValue_t result = commandQueue->receiveMessage(&command); + if (result != RETURN_OK) { + return; + } + + result = actionHelper.handleActionMessage(&command); + + if (result == HasReturnvaluesIF::RETURN_OK) { + return; + } + + result = handleParameterCommand(&command); + if (result == HasReturnvaluesIF::RETURN_OK) { + return; + } + + result = memoryHelper.handleMemoryCommand(&command); + if (result != RETURN_OK) { + command.setToUnknownCommand(); + commandQueue->reply(&command); + } +} + +ReturnValue_t DataPoolAdmin::handleMemoryLoad(uint32_t address, + const uint8_t* data, size_t size, uint8_t** dataPointer) { + uint32_t poolId = glob::dataPool.PIDToDataPoolId(address); + uint8_t arrayIndex = glob::dataPool.PIDToArrayIndex(address); + GlobDataSet testSet; + PoolRawAccess varToGetSize(poolId, arrayIndex, &testSet, + PoolVariableIF::VAR_READ); + ReturnValue_t status = testSet.read(); + if (status != RETURN_OK) { + return INVALID_ADDRESS; + } + uint8_t typeSize = varToGetSize.getSizeOfType(); + + if (size % typeSize != 0) { + return INVALID_SIZE; + } + + if (size > varToGetSize.getSizeTillEnd()) { + return INVALID_SIZE; + } + const uint8_t* readPosition = data; + + for (; size > 0; size -= typeSize) { + GlobDataSet rawSet; + PoolRawAccess variable(poolId, arrayIndex, &rawSet, + PoolVariableIF::VAR_READ_WRITE); + status = rawSet.read(); + if (status == RETURN_OK) { + status = variable.setEntryFromBigEndian(readPosition, typeSize); + if (status == RETURN_OK) { + status = rawSet.commit(); + } + } + arrayIndex += 1; + readPosition += typeSize; + } + return ACTIVITY_COMPLETED; +} + +ReturnValue_t DataPoolAdmin::handleMemoryDump(uint32_t address, size_t size, + uint8_t** dataPointer, uint8_t* copyHere) { + uint32_t poolId = glob::dataPool.PIDToDataPoolId(address); + uint8_t arrayIndex = glob::dataPool.PIDToArrayIndex(address); + GlobDataSet testSet; + PoolRawAccess varToGetSize(poolId, arrayIndex, &testSet, + PoolVariableIF::VAR_READ); + ReturnValue_t status = testSet.read(); + if (status != RETURN_OK) { + return INVALID_ADDRESS; + } + uint8_t typeSize = varToGetSize.getSizeOfType(); + if (size > varToGetSize.getSizeTillEnd()) { + return INVALID_SIZE; + } + uint8_t* ptrToCopy = copyHere; + for (; size > 0; size -= typeSize) { + GlobDataSet rawSet; + PoolRawAccess variable(poolId, arrayIndex, &rawSet, + PoolVariableIF::VAR_READ); + status = rawSet.read(); + if (status == RETURN_OK) { + size_t temp = 0; + status = variable.getEntryEndianSafe(ptrToCopy, &temp, size); + if (status != RETURN_OK) { + return RETURN_FAILED; + } + } else { + //Error reading parameter. + } + arrayIndex += 1; + ptrToCopy += typeSize; + } + return ACTIVITY_COMPLETED; +} + +ReturnValue_t DataPoolAdmin::initialize() { + ReturnValue_t result = SystemObject::initialize(); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + result = memoryHelper.initialize(commandQueue); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + storage = objectManager->get(objects::IPC_STORE); + if (storage == NULL) { + return HasReturnvaluesIF::RETURN_FAILED; + } + + result = actionHelper.initialize(commandQueue); + + return result; +} + +//mostly identical to ParameterHelper::handleParameterMessage() +ReturnValue_t DataPoolAdmin::handleParameterCommand(CommandMessage* command) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; + switch (command->getCommand()) { + case ParameterMessage::CMD_PARAMETER_DUMP: { + uint8_t domain = HasParametersIF::getDomain( + ParameterMessage::getParameterId(command)); + uint16_t parameterId = HasParametersIF::getMatrixId( + ParameterMessage::getParameterId(command)); + + DataPoolParameterWrapper wrapper; + result = wrapper.set(domain, parameterId); + + if (result == HasReturnvaluesIF::RETURN_OK) { + result = sendParameter(command->getSender(), + ParameterMessage::getParameterId(command), &wrapper); + } + } + break; + case ParameterMessage::CMD_PARAMETER_LOAD: { + + uint8_t domain = HasParametersIF::getDomain( + ParameterMessage::getParameterId(command)); + uint16_t parameterId = HasParametersIF::getMatrixId( + ParameterMessage::getParameterId(command)); + uint8_t index = HasParametersIF::getIndex( + ParameterMessage::getParameterId(command)); + + const uint8_t *storedStream; + size_t storedStreamSize; + result = storage->getData(ParameterMessage::getStoreId(command), + &storedStream, &storedStreamSize); + if (result != HasReturnvaluesIF::RETURN_OK) { + break; + } + + ParameterWrapper streamWrapper; + result = streamWrapper.set(storedStream, storedStreamSize); + if (result != HasReturnvaluesIF::RETURN_OK) { + storage->deleteData(ParameterMessage::getStoreId(command)); + break; + } + + DataPoolParameterWrapper poolWrapper; + result = poolWrapper.set(domain, parameterId); + if (result != HasReturnvaluesIF::RETURN_OK) { + storage->deleteData(ParameterMessage::getStoreId(command)); + break; + } + + result = poolWrapper.copyFrom(&streamWrapper, index); + + storage->deleteData(ParameterMessage::getStoreId(command)); + + if (result == HasReturnvaluesIF::RETURN_OK) { + result = sendParameter(command->getSender(), + ParameterMessage::getParameterId(command), &poolWrapper); + } + } + break; + default: + return HasReturnvaluesIF::RETURN_FAILED; + } + + if (result != HasReturnvaluesIF::RETURN_OK) { + rejectCommand(command->getSender(), result, command->getCommand()); + } + + return HasReturnvaluesIF::RETURN_OK; + +} + +//identical to ParameterHelper::sendParameter() +ReturnValue_t DataPoolAdmin::sendParameter(MessageQueueId_t to, uint32_t id, + const DataPoolParameterWrapper* wrapper) { + size_t serializedSize = wrapper->getSerializedSize(); + + uint8_t *storeElement; + store_address_t address; + + ReturnValue_t result = storage->getFreeElement(&address, serializedSize, + &storeElement); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + size_t storeElementSize = 0; + + result = wrapper->serialize(&storeElement, &storeElementSize, + serializedSize, SerializeIF::Endianness::BIG); + + if (result != HasReturnvaluesIF::RETURN_OK) { + storage->deleteData(address); + return result; + } + + CommandMessage reply; + + ParameterMessage::setParameterDumpReply(&reply, id, address); + + commandQueue->sendMessage(to, &reply); + + return HasReturnvaluesIF::RETURN_OK; +} + +//identical to ParameterHelper::rejectCommand() +void DataPoolAdmin::rejectCommand(MessageQueueId_t to, ReturnValue_t reason, + Command_t initialCommand) { + CommandMessage reply; + reply.setReplyRejected(reason, initialCommand); + commandQueue->sendMessage(to, &reply); +} diff --git a/datapoolglob/DataPoolAdmin.h b/datapoolglob/DataPoolAdmin.h index 653fdd8e..3d5d4d0c 100644 --- a/datapoolglob/DataPoolAdmin.h +++ b/datapoolglob/DataPoolAdmin.h @@ -1,59 +1,59 @@ -#ifndef DATAPOOLADMIN_H_ -#define DATAPOOLADMIN_H_ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -class DataPoolAdmin: public HasActionsIF, - public ExecutableObjectIF, - public AcceptsMemoryMessagesIF, - public HasReturnvaluesIF, - public ReceivesParameterMessagesIF, - public SystemObject { -public: - static const ActionId_t SET_VALIDITY = 1; - - DataPoolAdmin(object_id_t objectId); - - ~DataPoolAdmin(); - - ReturnValue_t performOperation(uint8_t opCode); - - MessageQueueId_t getCommandQueue() const; - - ReturnValue_t handleMemoryLoad(uint32_t address, const uint8_t* data, - size_t size, uint8_t** dataPointer); - ReturnValue_t handleMemoryDump(uint32_t address, size_t size, - uint8_t** dataPointer, uint8_t* copyHere); - - ReturnValue_t executeAction(ActionId_t actionId, - MessageQueueId_t commandedBy, const uint8_t* data, size_t size); - - //not implemented as ParameterHelper is no used - ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, - ParameterWrapper *parameterWrapper, - const ParameterWrapper *newValues, uint16_t startAtIndex); - - ReturnValue_t initialize(); -private: - StorageManagerIF *storage; - MessageQueueIF* commandQueue; - MemoryHelper memoryHelper; - SimpleActionHelper actionHelper; - void handleCommand(); - ReturnValue_t handleParameterCommand(CommandMessage *command); - ReturnValue_t sendParameter(MessageQueueId_t to, uint32_t id, - const DataPoolParameterWrapper* wrapper); - void rejectCommand(MessageQueueId_t to, ReturnValue_t reason, - Command_t initialCommand); -}; - -#endif /* DATAPOOLADMIN_H_ */ +#ifndef DATAPOOLADMIN_H_ +#define DATAPOOLADMIN_H_ + +#include "../objectmanager/SystemObject.h" +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../tasks/ExecutableObjectIF.h" +#include "../action/HasActionsIF.h" +#include "../ipc/MessageQueueIF.h" +#include "../parameters/ReceivesParameterMessagesIF.h" + +#include "../memory/MemoryHelper.h" +#include "../action/SimpleActionHelper.h" +#include "../datapoolglob/DataPoolParameterWrapper.h" + +class DataPoolAdmin: public HasActionsIF, + public ExecutableObjectIF, + public AcceptsMemoryMessagesIF, + public HasReturnvaluesIF, + public ReceivesParameterMessagesIF, + public SystemObject { +public: + static const ActionId_t SET_VALIDITY = 1; + + DataPoolAdmin(object_id_t objectId); + + ~DataPoolAdmin(); + + ReturnValue_t performOperation(uint8_t opCode); + + MessageQueueId_t getCommandQueue() const; + + ReturnValue_t handleMemoryLoad(uint32_t address, const uint8_t* data, + size_t size, uint8_t** dataPointer); + ReturnValue_t handleMemoryDump(uint32_t address, size_t size, + uint8_t** dataPointer, uint8_t* copyHere); + + ReturnValue_t executeAction(ActionId_t actionId, + MessageQueueId_t commandedBy, const uint8_t* data, size_t size); + + //not implemented as ParameterHelper is no used + ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, + ParameterWrapper *parameterWrapper, + const ParameterWrapper *newValues, uint16_t startAtIndex); + + ReturnValue_t initialize(); +private: + StorageManagerIF *storage; + MessageQueueIF* commandQueue; + MemoryHelper memoryHelper; + SimpleActionHelper actionHelper; + void handleCommand(); + ReturnValue_t handleParameterCommand(CommandMessage *command); + ReturnValue_t sendParameter(MessageQueueId_t to, uint32_t id, + const DataPoolParameterWrapper* wrapper); + void rejectCommand(MessageQueueId_t to, ReturnValue_t reason, + Command_t initialCommand); +}; + +#endif /* DATAPOOLADMIN_H_ */ diff --git a/datapoolglob/DataPoolParameterWrapper.cpp b/datapoolglob/DataPoolParameterWrapper.cpp index a292016e..597cc86b 100644 --- a/datapoolglob/DataPoolParameterWrapper.cpp +++ b/datapoolglob/DataPoolParameterWrapper.cpp @@ -1,179 +1,179 @@ -#include -#include -#include -#include - - -DataPoolParameterWrapper::DataPoolParameterWrapper() : - type(Type::UNKNOWN_TYPE), rows(0), columns(0), poolId( - PoolVariableIF::NO_PARAMETER) { - -} - -DataPoolParameterWrapper::~DataPoolParameterWrapper() { - -} - -ReturnValue_t DataPoolParameterWrapper::set(uint8_t domainId, - uint16_t parameterId) { - poolId = (domainId << 16) + parameterId; - - GlobDataSet mySet; - PoolRawAccess raw(poolId, 0, &mySet, PoolVariableIF::VAR_READ); - ReturnValue_t status = mySet.read(); - if (status != HasReturnvaluesIF::RETURN_OK) { - //should only fail for invalid pool id - return HasParametersIF::INVALID_MATRIX_ID; - } - - type = raw.getType(); - rows = raw.getArraySize(); - columns = 1; - - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t DataPoolParameterWrapper::serialize(uint8_t** buffer, - size_t* size, size_t maxSize, Endianness streamEndianness) const { - ReturnValue_t result; - - result = SerializeAdapter::serialize(&type, buffer, size, maxSize, - streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - result = SerializeAdapter::serialize(&columns, buffer, size, - maxSize, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - result = SerializeAdapter::serialize(&rows, buffer, size, maxSize, - streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - for (uint8_t index = 0; index < rows; index++){ - GlobDataSet mySet; - PoolRawAccess raw(poolId, index, &mySet,PoolVariableIF::VAR_READ); - mySet.read(); - result = raw.serialize(buffer,size,maxSize,streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK){ - return result; - } - } - return HasReturnvaluesIF::RETURN_OK; -} - -//same as ParameterWrapper -size_t DataPoolParameterWrapper::getSerializedSize() const { - size_t serializedSize = 0; - serializedSize += type.getSerializedSize(); - serializedSize += sizeof(rows); - serializedSize += sizeof(columns); - serializedSize += rows * columns * type.getSize(); - - return serializedSize; -} - -ReturnValue_t DataPoolParameterWrapper::deSerialize(const uint8_t** buffer, - size_t* size, Endianness streamEndianness) { - return HasReturnvaluesIF::RETURN_FAILED; -} - -template -ReturnValue_t DataPoolParameterWrapper::deSerializeData(uint8_t startingRow, - uint8_t startingColumn, const void* from, uint8_t fromRows) { - //treat from as a continuous Stream as we copy all of it - const uint8_t *fromAsStream = (const uint8_t *) from; - - ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; - - for (uint8_t fromRow = 0; fromRow < fromRows; fromRow++) { - - GlobDataSet mySet; - PoolRawAccess raw(poolId, startingRow + fromRow, &mySet, - PoolVariableIF::VAR_READ_WRITE); - mySet.read(); - - result = raw.setEntryFromBigEndian(fromAsStream, sizeof(T)); - - fromAsStream += sizeof(T); - - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - mySet.commit(); - } - - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t DataPoolParameterWrapper::copyFrom(const ParameterWrapper* from, - uint16_t startWritingAtIndex) { - if (poolId == PoolVariableIF::NO_PARAMETER) { - return ParameterWrapper::NOT_SET; - } - - if (type != from->type) { - return ParameterWrapper::DATATYPE_MISSMATCH; - } - - //check if from fits into this - uint8_t startingRow = startWritingAtIndex / columns; - uint8_t startingColumn = startWritingAtIndex % columns; - - if ((from->rows > (rows - startingRow)) - || (from->columns > (columns - startingColumn))) { - return ParameterWrapper::TOO_BIG; - } - - ReturnValue_t result; - //copy data - if (from->pointsToStream) { - switch (type) { - case Type::UINT8_T: - result = deSerializeData(startingRow, startingColumn, - from->readonlyData, from->rows); - break; - case Type::INT8_T: - result = deSerializeData(startingRow, startingColumn, - from->readonlyData, from->rows); - break; - case Type::UINT16_T: - result = deSerializeData(startingRow, startingColumn, - from->readonlyData, from->rows); - break; - case Type::INT16_T: - result = deSerializeData(startingRow, startingColumn, - from->readonlyData, from->rows); - break; - case Type::UINT32_T: - result = deSerializeData(startingRow, startingColumn, - from->readonlyData, from->rows); - break; - case Type::INT32_T: - result = deSerializeData(startingRow, startingColumn, - from->readonlyData, from->rows); - break; - case Type::FLOAT: - result = deSerializeData(startingRow, startingColumn, - from->readonlyData, from->rows); - break; - case Type::DOUBLE: - result = deSerializeData(startingRow, startingColumn, - from->readonlyData, from->rows); - break; - default: - result = ParameterWrapper::UNKNOW_DATATYPE; - break; - } - } else { - //not supported - return HasReturnvaluesIF::RETURN_FAILED; - } - - return result; -} +#include "../datapoolglob/GlobalDataSet.h" +#include "../datapoolglob/DataPoolParameterWrapper.h" +#include "../datapoolglob/PoolRawAccess.h" +#include "../parameters/HasParametersIF.h" + + +DataPoolParameterWrapper::DataPoolParameterWrapper() : + type(Type::UNKNOWN_TYPE), rows(0), columns(0), poolId( + PoolVariableIF::NO_PARAMETER) { + +} + +DataPoolParameterWrapper::~DataPoolParameterWrapper() { + +} + +ReturnValue_t DataPoolParameterWrapper::set(uint8_t domainId, + uint16_t parameterId) { + poolId = (domainId << 16) + parameterId; + + GlobDataSet mySet; + PoolRawAccess raw(poolId, 0, &mySet, PoolVariableIF::VAR_READ); + ReturnValue_t status = mySet.read(); + if (status != HasReturnvaluesIF::RETURN_OK) { + //should only fail for invalid pool id + return HasParametersIF::INVALID_MATRIX_ID; + } + + type = raw.getType(); + rows = raw.getArraySize(); + columns = 1; + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t DataPoolParameterWrapper::serialize(uint8_t** buffer, + size_t* size, size_t maxSize, Endianness streamEndianness) const { + ReturnValue_t result; + + result = SerializeAdapter::serialize(&type, buffer, size, maxSize, + streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + result = SerializeAdapter::serialize(&columns, buffer, size, + maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = SerializeAdapter::serialize(&rows, buffer, size, maxSize, + streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + for (uint8_t index = 0; index < rows; index++){ + GlobDataSet mySet; + PoolRawAccess raw(poolId, index, &mySet,PoolVariableIF::VAR_READ); + mySet.read(); + result = raw.serialize(buffer,size,maxSize,streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK){ + return result; + } + } + return HasReturnvaluesIF::RETURN_OK; +} + +//same as ParameterWrapper +size_t DataPoolParameterWrapper::getSerializedSize() const { + size_t serializedSize = 0; + serializedSize += type.getSerializedSize(); + serializedSize += sizeof(rows); + serializedSize += sizeof(columns); + serializedSize += rows * columns * type.getSize(); + + return serializedSize; +} + +ReturnValue_t DataPoolParameterWrapper::deSerialize(const uint8_t** buffer, + size_t* size, Endianness streamEndianness) { + return HasReturnvaluesIF::RETURN_FAILED; +} + +template +ReturnValue_t DataPoolParameterWrapper::deSerializeData(uint8_t startingRow, + uint8_t startingColumn, const void* from, uint8_t fromRows) { + //treat from as a continuous Stream as we copy all of it + const uint8_t *fromAsStream = (const uint8_t *) from; + + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + + for (uint8_t fromRow = 0; fromRow < fromRows; fromRow++) { + + GlobDataSet mySet; + PoolRawAccess raw(poolId, startingRow + fromRow, &mySet, + PoolVariableIF::VAR_READ_WRITE); + mySet.read(); + + result = raw.setEntryFromBigEndian(fromAsStream, sizeof(T)); + + fromAsStream += sizeof(T); + + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + mySet.commit(); + } + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t DataPoolParameterWrapper::copyFrom(const ParameterWrapper* from, + uint16_t startWritingAtIndex) { + if (poolId == PoolVariableIF::NO_PARAMETER) { + return ParameterWrapper::NOT_SET; + } + + if (type != from->type) { + return ParameterWrapper::DATATYPE_MISSMATCH; + } + + //check if from fits into this + uint8_t startingRow = startWritingAtIndex / columns; + uint8_t startingColumn = startWritingAtIndex % columns; + + if ((from->rows > (rows - startingRow)) + || (from->columns > (columns - startingColumn))) { + return ParameterWrapper::TOO_BIG; + } + + ReturnValue_t result; + //copy data + if (from->pointsToStream) { + switch (type) { + case Type::UINT8_T: + result = deSerializeData(startingRow, startingColumn, + from->readonlyData, from->rows); + break; + case Type::INT8_T: + result = deSerializeData(startingRow, startingColumn, + from->readonlyData, from->rows); + break; + case Type::UINT16_T: + result = deSerializeData(startingRow, startingColumn, + from->readonlyData, from->rows); + break; + case Type::INT16_T: + result = deSerializeData(startingRow, startingColumn, + from->readonlyData, from->rows); + break; + case Type::UINT32_T: + result = deSerializeData(startingRow, startingColumn, + from->readonlyData, from->rows); + break; + case Type::INT32_T: + result = deSerializeData(startingRow, startingColumn, + from->readonlyData, from->rows); + break; + case Type::FLOAT: + result = deSerializeData(startingRow, startingColumn, + from->readonlyData, from->rows); + break; + case Type::DOUBLE: + result = deSerializeData(startingRow, startingColumn, + from->readonlyData, from->rows); + break; + default: + result = ParameterWrapper::UNKNOW_DATATYPE; + break; + } + } else { + //not supported + return HasReturnvaluesIF::RETURN_FAILED; + } + + return result; +} diff --git a/datapoolglob/DataPoolParameterWrapper.h b/datapoolglob/DataPoolParameterWrapper.h index a3dbdc04..0c5c65ea 100644 --- a/datapoolglob/DataPoolParameterWrapper.h +++ b/datapoolglob/DataPoolParameterWrapper.h @@ -1,38 +1,38 @@ -#ifndef DATAPOOLPARAMETERWRAPPER_H_ -#define DATAPOOLPARAMETERWRAPPER_H_ - -#include -#include - -class DataPoolParameterWrapper: public SerializeIF { -public: - DataPoolParameterWrapper(); - virtual ~DataPoolParameterWrapper(); - - ReturnValue_t set(uint8_t domainId, uint16_t parameterId); - - virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) const override; - - virtual size_t getSerializedSize() const override; - - virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - Endianness streamEndianness) override; - - ReturnValue_t copyFrom(const ParameterWrapper *from, - uint16_t startWritingAtIndex); - -private: - Type type; - uint8_t rows; - uint8_t columns; - - uint32_t poolId; - - template - ReturnValue_t deSerializeData(uint8_t startingRow, uint8_t startingColumn, - const void *from, uint8_t fromRows); - -}; - -#endif /* DATAPOOLPARAMETERWRAPPER_H_ */ +#ifndef DATAPOOLPARAMETERWRAPPER_H_ +#define DATAPOOLPARAMETERWRAPPER_H_ + +#include "../globalfunctions/Type.h" +#include "../parameters/ParameterWrapper.h" + +class DataPoolParameterWrapper: public SerializeIF { +public: + DataPoolParameterWrapper(); + virtual ~DataPoolParameterWrapper(); + + ReturnValue_t set(uint8_t domainId, uint16_t parameterId); + + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + size_t maxSize, Endianness streamEndianness) const override; + + virtual size_t getSerializedSize() const override; + + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + Endianness streamEndianness) override; + + ReturnValue_t copyFrom(const ParameterWrapper *from, + uint16_t startWritingAtIndex); + +private: + Type type; + uint8_t rows; + uint8_t columns; + + uint32_t poolId; + + template + ReturnValue_t deSerializeData(uint8_t startingRow, uint8_t startingColumn, + const void *from, uint8_t fromRows); + +}; + +#endif /* DATAPOOLPARAMETERWRAPPER_H_ */ diff --git a/datapoolglob/GlobalDataPool.cpp b/datapoolglob/GlobalDataPool.cpp index 9dedb4b8..aa6831f8 100644 --- a/datapoolglob/GlobalDataPool.cpp +++ b/datapoolglob/GlobalDataPool.cpp @@ -1,133 +1,133 @@ -#include -#include -#include - -GlobalDataPool::GlobalDataPool( - void(*initFunction)(GlobPoolMap* pool_map)) { - mutex = MutexFactory::instance()->createMutex(); - if (initFunction != NULL ) { - initFunction( &this->globDataPool ); - } -} - -GlobalDataPool::~GlobalDataPool() { - MutexFactory::instance()->deleteMutex(mutex); - for(GlobPoolMapIter it = this->globDataPool.begin(); - it != this->globDataPool.end(); ++it ) - { - delete it->second; - } -} - -// The function checks PID, type and array length before returning a copy of -// the PoolEntry. In failure case, it returns a temp-Entry with size 0 and NULL-ptr. -template PoolEntry* GlobalDataPool::getData( uint32_t data_pool_id, - uint8_t sizeOrPosition ) { - GlobPoolMapIter it = this->globDataPool.find( data_pool_id ); - if ( it != this->globDataPool.end() ) { - PoolEntry* entry = dynamic_cast< PoolEntry* >( it->second ); - if (entry != nullptr ) { - if ( sizeOrPosition <= entry->length ) { - return entry; - } - } - } - return nullptr; -} - -PoolEntryIF* GlobalDataPool::getRawData( uint32_t data_pool_id ) { - GlobPoolMapIter it = this->globDataPool.find( data_pool_id ); - if ( it != this->globDataPool.end() ) { - return it->second; - } else { - return nullptr; - } -} - -ReturnValue_t GlobalDataPool::unlockDataPool() { - ReturnValue_t status = mutex->unlockMutex(); - if(status != RETURN_OK) { - sif::error << "DataPool::DataPool: unlock of mutex failed with" - " error code: " << status << std::endl; - } - return status; -} - -ReturnValue_t GlobalDataPool::lockDataPool(uint32_t timeoutMs) { - ReturnValue_t status = mutex->lockMutex(MutexIF::TimeoutType::WAITING, - timeoutMs); - if(status != RETURN_OK) { - sif::error << "DataPool::DataPool: lock of mutex failed " - "with error code: " << status << std::endl; - } - return status; -} - -void GlobalDataPool::print() { - sif::debug << "DataPool contains: " << std::endl; - std::map::iterator dataPoolIt; - dataPoolIt = this->globDataPool.begin(); - while( dataPoolIt != this->globDataPool.end() ) { - sif::debug << std::hex << dataPoolIt->first << std::dec << " |"; - dataPoolIt->second->print(); - dataPoolIt++; - } -} - -uint32_t GlobalDataPool::PIDToDataPoolId(uint32_t parameter_id) { - return (parameter_id >> 8) & 0x00FFFFFF; -} - -uint8_t GlobalDataPool::PIDToArrayIndex(uint32_t parameter_id) { - return (parameter_id & 0x000000FF); -} - -uint32_t GlobalDataPool::poolIdAndPositionToPid(uint32_t poolId, uint8_t index) { - return (poolId << 8) + index; -} - - -//SHOULDDO: Do we need a mutex lock here... I don't think so, -//as we only check static const values of elements in a list that do not change. -//there is no guarantee in the standard, but it seems to me that the implementation is safe -UM -ReturnValue_t GlobalDataPool::getType(uint32_t parameter_id, Type* type) { - GlobPoolMapIter it = this->globDataPool.find( PIDToDataPoolId(parameter_id)); - if ( it != this->globDataPool.end() ) { - *type = it->second->getType(); - return RETURN_OK; - } else { - *type = Type::UNKNOWN_TYPE; - return RETURN_FAILED; - } -} - -bool GlobalDataPool::exists(uint32_t parameterId) { - uint32_t poolId = PIDToDataPoolId(parameterId); - uint32_t index = PIDToArrayIndex(parameterId); - GlobPoolMapIter it = this->globDataPool.find( poolId ); - if (it != globDataPool.end()) { - if (it->second->getSize() >= index) { - return true; - } - } - return false; -} - -template PoolEntry* GlobalDataPool::getData( - uint32_t data_pool_id, uint8_t size ); -template PoolEntry* GlobalDataPool::getData( - uint32_t data_pool_id, uint8_t size ); -template PoolEntry* GlobalDataPool::getData( - uint32_t data_pool_id, uint8_t size ); -template PoolEntry* GlobalDataPool::getData( - uint32_t data_pool_id, uint8_t size); -template PoolEntry* GlobalDataPool::getData( - uint32_t data_pool_id, uint8_t size ); -template PoolEntry* GlobalDataPool::getData( - uint32_t data_pool_id, uint8_t size ); -template PoolEntry* GlobalDataPool::getData( - uint32_t data_pool_id, uint8_t size ); -template PoolEntry* GlobalDataPool::getData( - uint32_t data_pool_id, uint8_t size ); -template PoolEntry* GlobalDataPool::getData( - uint32_t data_pool_id, uint8_t size); +#include "../datapoolglob/GlobalDataPool.h" +#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../ipc/MutexFactory.h" + +GlobalDataPool::GlobalDataPool( + void(*initFunction)(GlobPoolMap* pool_map)) { + mutex = MutexFactory::instance()->createMutex(); + if (initFunction != NULL ) { + initFunction( &this->globDataPool ); + } +} + +GlobalDataPool::~GlobalDataPool() { + MutexFactory::instance()->deleteMutex(mutex); + for(GlobPoolMapIter it = this->globDataPool.begin(); + it != this->globDataPool.end(); ++it ) + { + delete it->second; + } +} + +// The function checks PID, type and array length before returning a copy of +// the PoolEntry. In failure case, it returns a temp-Entry with size 0 and NULL-ptr. +template PoolEntry* GlobalDataPool::getData( uint32_t data_pool_id, + uint8_t sizeOrPosition ) { + GlobPoolMapIter it = this->globDataPool.find( data_pool_id ); + if ( it != this->globDataPool.end() ) { + PoolEntry* entry = dynamic_cast< PoolEntry* >( it->second ); + if (entry != nullptr ) { + if ( sizeOrPosition <= entry->length ) { + return entry; + } + } + } + return nullptr; +} + +PoolEntryIF* GlobalDataPool::getRawData( uint32_t data_pool_id ) { + GlobPoolMapIter it = this->globDataPool.find( data_pool_id ); + if ( it != this->globDataPool.end() ) { + return it->second; + } else { + return nullptr; + } +} + +ReturnValue_t GlobalDataPool::unlockDataPool() { + ReturnValue_t status = mutex->unlockMutex(); + if(status != RETURN_OK) { + sif::error << "DataPool::DataPool: unlock of mutex failed with" + " error code: " << status << std::endl; + } + return status; +} + +ReturnValue_t GlobalDataPool::lockDataPool(uint32_t timeoutMs) { + ReturnValue_t status = mutex->lockMutex(MutexIF::TimeoutType::WAITING, + timeoutMs); + if(status != RETURN_OK) { + sif::error << "DataPool::DataPool: lock of mutex failed " + "with error code: " << status << std::endl; + } + return status; +} + +void GlobalDataPool::print() { + sif::debug << "DataPool contains: " << std::endl; + std::map::iterator dataPoolIt; + dataPoolIt = this->globDataPool.begin(); + while( dataPoolIt != this->globDataPool.end() ) { + sif::debug << std::hex << dataPoolIt->first << std::dec << " |"; + dataPoolIt->second->print(); + dataPoolIt++; + } +} + +uint32_t GlobalDataPool::PIDToDataPoolId(uint32_t parameter_id) { + return (parameter_id >> 8) & 0x00FFFFFF; +} + +uint8_t GlobalDataPool::PIDToArrayIndex(uint32_t parameter_id) { + return (parameter_id & 0x000000FF); +} + +uint32_t GlobalDataPool::poolIdAndPositionToPid(uint32_t poolId, uint8_t index) { + return (poolId << 8) + index; +} + + +//SHOULDDO: Do we need a mutex lock here... I don't think so, +//as we only check static const values of elements in a list that do not change. +//there is no guarantee in the standard, but it seems to me that the implementation is safe -UM +ReturnValue_t GlobalDataPool::getType(uint32_t parameter_id, Type* type) { + GlobPoolMapIter it = this->globDataPool.find( PIDToDataPoolId(parameter_id)); + if ( it != this->globDataPool.end() ) { + *type = it->second->getType(); + return RETURN_OK; + } else { + *type = Type::UNKNOWN_TYPE; + return RETURN_FAILED; + } +} + +bool GlobalDataPool::exists(uint32_t parameterId) { + uint32_t poolId = PIDToDataPoolId(parameterId); + uint32_t index = PIDToArrayIndex(parameterId); + GlobPoolMapIter it = this->globDataPool.find( poolId ); + if (it != globDataPool.end()) { + if (it->second->getSize() >= index) { + return true; + } + } + return false; +} + +template PoolEntry* GlobalDataPool::getData( + uint32_t data_pool_id, uint8_t size ); +template PoolEntry* GlobalDataPool::getData( + uint32_t data_pool_id, uint8_t size ); +template PoolEntry* GlobalDataPool::getData( + uint32_t data_pool_id, uint8_t size ); +template PoolEntry* GlobalDataPool::getData( + uint32_t data_pool_id, uint8_t size); +template PoolEntry* GlobalDataPool::getData( + uint32_t data_pool_id, uint8_t size ); +template PoolEntry* GlobalDataPool::getData( + uint32_t data_pool_id, uint8_t size ); +template PoolEntry* GlobalDataPool::getData( + uint32_t data_pool_id, uint8_t size ); +template PoolEntry* GlobalDataPool::getData( + uint32_t data_pool_id, uint8_t size ); +template PoolEntry* GlobalDataPool::getData( + uint32_t data_pool_id, uint8_t size); diff --git a/datapoolglob/GlobalDataPool.h b/datapoolglob/GlobalDataPool.h index b9c1436f..37a4057b 100644 --- a/datapoolglob/GlobalDataPool.h +++ b/datapoolglob/GlobalDataPool.h @@ -1,149 +1,149 @@ -#ifndef GLOBALDATAPOOL_H_ -#define GLOBALDATAPOOL_H_ - -#include -#include -#include -#include - -/** - * @defgroup data_pool Global data pool - * This is the group, where all classes associated with global - * data pool handling belong to. - * This includes classes to access Data Pool variables. - */ - -/** - * Typedefs for the global pool representations - */ -using GlobPoolMap = std::map; -using GlobPoolMapIter = GlobPoolMap::iterator; - -/** - * @brief This class represents the OBSW global data-pool. - * - * @details - * All variables are registered and space is allocated in an initialization - * function, which is passed do the constructor. Space for the variables is - * allocated on the heap (with a new call). - * - * The data is found by a data pool id, which uniquely represents a variable. - * Data pool variables should be used with a blackboard logic in mind, - * which means read data is valid (if flagged so), - * but not necessarily up-to-date. - * - * Variables are either single values or arrays. - * @author Bastian Baetz - * @ingroup data_pool - */ -class GlobalDataPool : public HasReturnvaluesIF { -private: - /** - * @brief This is the actual data pool itself. - * @details It is represented by a map with the data pool id as index - * and a pointer to a single PoolEntry as value. - */ - GlobPoolMap globDataPool; - - /** - * @brief The mutex is created in the constructor and makes - * access mutual exclusive. - * @details Locking and unlocking the pool is only done by the DataSet class. - */ - MutexIF* mutex; -public: - /** - * @brief In the classes constructor, - * the passed initialization function is called. - * @details - * To enable filling the pool, a pointer to the map is passed, - * allowing direct access to the pool's content. - * On runtime, adding or removing variables is forbidden. - */ - GlobalDataPool( void ( *initFunction )( GlobPoolMap* pool_map ) ); - - /** - * @brief The destructor iterates through the data_pool map and - * calls all entries destructors to clean up the heap. - */ - ~GlobalDataPool(); - - /** - * @brief This is the default call to access the pool. - * @details - * A pointer to the PoolEntry object is returned. - * The call checks data pool id, type and array size. - * Returns NULL in case of failure. - * @param data_pool_id The data pool id to search. - * @param sizeOrPosition The array size (not byte size!) of the pool entry, - * or the position the user wants to read. - * If smaller than the entry size, everything's ok. - */ - template PoolEntry* getData( uint32_t data_pool_id, - uint8_t sizeOrPosition ); - - /** - * @brief An alternative call to get a data pool entry in case the type is not implicitly known - * (i.e. in Housekeeping Telemetry). - * @details It returns a basic interface and does NOT perform - * a size check. The caller has to assure he does not copy too much data. - * Returns NULL in case the entry is not found. - * @param data_pool_id The data pool id to search. - */ - PoolEntryIF* getRawData( uint32_t data_pool_id ); - /** - * @brief This is a small helper function to facilitate locking the global data pool. - * @details It fetches the pool's mutex id and tries to acquire the mutex. - */ - ReturnValue_t lockDataPool(uint32_t timeoutMs = MutexIF::BLOCKING); - /** - * @brief This is a small helper function to facilitate unlocking the global data pool. - * @details It fetches the pool's mutex id and tries to free the mutex. - */ - ReturnValue_t unlockDataPool(); - /** - * @brief The print call is a simple debug method. - * @details It prints the current content of the data pool. - * It iterates through the data_pool map and calls each entry's print() method. - */ - void print(); - /** - * Extracts the data pool id from a SCOS 2000 PID. - * @param parameter_id The passed Parameter ID. - * @return The data pool id as used within the OBSW. - */ - static uint32_t PIDToDataPoolId( uint32_t parameter_id ); - /** - * Extracts an array index out of a SCOS 2000 PID. - * @param parameter_id The passed Parameter ID. - * @return The index of the corresponding data pool entry. - */ - static uint8_t PIDToArrayIndex( uint32_t parameter_id ); - /** - * Retransforms a data pool id and an array index to a SCOS 2000 PID. - */ - static uint32_t poolIdAndPositionToPid( uint32_t poolId, uint8_t index ); - - /** - * Method to return the type of a pool variable. - * @param parameter_id A parameterID (not pool id) of a DP member. - * @param type Returns the type or TYPE::UNKNOWN_TYPE - * @return RETURN_OK if parameter exists, RETURN_FAILED else. - */ - ReturnValue_t getType( uint32_t parameter_id, Type* type ); - - /** - * Method to check if a PID exists. Does not lock, as there's no - * possibility to alter the list that is checked during run-time. - * @param parameterId The PID (not pool id!) of a parameter. - * @return true if exists, false else. - */ - bool exists(uint32_t parameterId); -}; - -//We assume someone globally instantiates a DataPool. -namespace glob { -extern GlobalDataPool dataPool; -} - -#endif /* DATAPOOL_H_ */ +#ifndef GLOBALDATAPOOL_H_ +#define GLOBALDATAPOOL_H_ + +#include "../datapool/PoolEntry.h" +#include "../globalfunctions/Type.h" +#include "../ipc/MutexIF.h" +#include + +/** + * @defgroup data_pool Global data pool + * This is the group, where all classes associated with global + * data pool handling belong to. + * This includes classes to access Data Pool variables. + */ + +/** + * Typedefs for the global pool representations + */ +using GlobPoolMap = std::map; +using GlobPoolMapIter = GlobPoolMap::iterator; + +/** + * @brief This class represents the OBSW global data-pool. + * + * @details + * All variables are registered and space is allocated in an initialization + * function, which is passed do the constructor. Space for the variables is + * allocated on the heap (with a new call). + * + * The data is found by a data pool id, which uniquely represents a variable. + * Data pool variables should be used with a blackboard logic in mind, + * which means read data is valid (if flagged so), + * but not necessarily up-to-date. + * + * Variables are either single values or arrays. + * @author Bastian Baetz + * @ingroup data_pool + */ +class GlobalDataPool : public HasReturnvaluesIF { +private: + /** + * @brief This is the actual data pool itself. + * @details It is represented by a map with the data pool id as index + * and a pointer to a single PoolEntry as value. + */ + GlobPoolMap globDataPool; + + /** + * @brief The mutex is created in the constructor and makes + * access mutual exclusive. + * @details Locking and unlocking the pool is only done by the DataSet class. + */ + MutexIF* mutex; +public: + /** + * @brief In the classes constructor, + * the passed initialization function is called. + * @details + * To enable filling the pool, a pointer to the map is passed, + * allowing direct access to the pool's content. + * On runtime, adding or removing variables is forbidden. + */ + GlobalDataPool( void ( *initFunction )( GlobPoolMap* pool_map ) ); + + /** + * @brief The destructor iterates through the data_pool map and + * calls all entries destructors to clean up the heap. + */ + ~GlobalDataPool(); + + /** + * @brief This is the default call to access the pool. + * @details + * A pointer to the PoolEntry object is returned. + * The call checks data pool id, type and array size. + * Returns NULL in case of failure. + * @param data_pool_id The data pool id to search. + * @param sizeOrPosition The array size (not byte size!) of the pool entry, + * or the position the user wants to read. + * If smaller than the entry size, everything's ok. + */ + template PoolEntry* getData( uint32_t data_pool_id, + uint8_t sizeOrPosition ); + + /** + * @brief An alternative call to get a data pool entry in case the type is not implicitly known + * (i.e. in Housekeeping Telemetry). + * @details It returns a basic interface and does NOT perform + * a size check. The caller has to assure he does not copy too much data. + * Returns NULL in case the entry is not found. + * @param data_pool_id The data pool id to search. + */ + PoolEntryIF* getRawData( uint32_t data_pool_id ); + /** + * @brief This is a small helper function to facilitate locking the global data pool. + * @details It fetches the pool's mutex id and tries to acquire the mutex. + */ + ReturnValue_t lockDataPool(uint32_t timeoutMs = MutexIF::BLOCKING); + /** + * @brief This is a small helper function to facilitate unlocking the global data pool. + * @details It fetches the pool's mutex id and tries to free the mutex. + */ + ReturnValue_t unlockDataPool(); + /** + * @brief The print call is a simple debug method. + * @details It prints the current content of the data pool. + * It iterates through the data_pool map and calls each entry's print() method. + */ + void print(); + /** + * Extracts the data pool id from a SCOS 2000 PID. + * @param parameter_id The passed Parameter ID. + * @return The data pool id as used within the OBSW. + */ + static uint32_t PIDToDataPoolId( uint32_t parameter_id ); + /** + * Extracts an array index out of a SCOS 2000 PID. + * @param parameter_id The passed Parameter ID. + * @return The index of the corresponding data pool entry. + */ + static uint8_t PIDToArrayIndex( uint32_t parameter_id ); + /** + * Retransforms a data pool id and an array index to a SCOS 2000 PID. + */ + static uint32_t poolIdAndPositionToPid( uint32_t poolId, uint8_t index ); + + /** + * Method to return the type of a pool variable. + * @param parameter_id A parameterID (not pool id) of a DP member. + * @param type Returns the type or TYPE::UNKNOWN_TYPE + * @return RETURN_OK if parameter exists, RETURN_FAILED else. + */ + ReturnValue_t getType( uint32_t parameter_id, Type* type ); + + /** + * Method to check if a PID exists. Does not lock, as there's no + * possibility to alter the list that is checked during run-time. + * @param parameterId The PID (not pool id!) of a parameter. + * @return true if exists, false else. + */ + bool exists(uint32_t parameterId); +}; + +//We assume someone globally instantiates a DataPool. +namespace glob { +extern GlobalDataPool dataPool; +} + +#endif /* DATAPOOL_H_ */ diff --git a/datapoolglob/GlobalDataSet.cpp b/datapoolglob/GlobalDataSet.cpp index 883f6157..00124fb0 100644 --- a/datapoolglob/GlobalDataSet.cpp +++ b/datapoolglob/GlobalDataSet.cpp @@ -1,44 +1,44 @@ -#include -#include -#include - -GlobDataSet::GlobDataSet(): DataSetBase( - reinterpret_cast(®isteredVariables), - DATA_SET_MAX_SIZE) {} - -// Don't do anything with your variables, they are dead already! -// (Destructor is already called) -GlobDataSet::~GlobDataSet() {} - -ReturnValue_t GlobDataSet::commit(bool valid, uint32_t lockTimeout) { - setEntriesValid(valid); - setSetValid(valid); - return commit(lockTimeout); -} - -ReturnValue_t GlobDataSet::commit(uint32_t lockTimeout) { - return DataSetBase::commit(lockTimeout); -} - -ReturnValue_t GlobDataSet::unlockDataPool() { - return glob::dataPool.unlockDataPool(); -} - -ReturnValue_t GlobDataSet::lockDataPool(uint32_t timeoutMs) { - return glob::dataPool.lockDataPool(timeoutMs); -} - -void GlobDataSet::setEntriesValid(bool valid) { - for (uint16_t count = 0; count < fillCount; count++) { - if (registeredVariables[count]->getReadWriteMode() - != PoolVariableIF::VAR_READ) { - registeredVariables[count]->setValid(valid); - } - } -} - -void GlobDataSet::setSetValid(bool valid) { - this->valid = valid; -} - - +#include "../datapoolglob/GlobalDataPool.h" +#include "../datapoolglob/GlobalDataSet.h" +#include "../serviceinterface/ServiceInterfaceStream.h" + +GlobDataSet::GlobDataSet(): DataSetBase( + reinterpret_cast(®isteredVariables), + DATA_SET_MAX_SIZE) {} + +// Don't do anything with your variables, they are dead already! +// (Destructor is already called) +GlobDataSet::~GlobDataSet() {} + +ReturnValue_t GlobDataSet::commit(bool valid, uint32_t lockTimeout) { + setEntriesValid(valid); + setSetValid(valid); + return commit(lockTimeout); +} + +ReturnValue_t GlobDataSet::commit(uint32_t lockTimeout) { + return DataSetBase::commit(lockTimeout); +} + +ReturnValue_t GlobDataSet::unlockDataPool() { + return glob::dataPool.unlockDataPool(); +} + +ReturnValue_t GlobDataSet::lockDataPool(uint32_t timeoutMs) { + return glob::dataPool.lockDataPool(timeoutMs); +} + +void GlobDataSet::setEntriesValid(bool valid) { + for (uint16_t count = 0; count < fillCount; count++) { + if (registeredVariables[count]->getReadWriteMode() + != PoolVariableIF::VAR_READ) { + registeredVariables[count]->setValid(valid); + } + } +} + +void GlobDataSet::setSetValid(bool valid) { + this->valid = valid; +} + + diff --git a/datapoolglob/GlobalDataSet.h b/datapoolglob/GlobalDataSet.h index d237cc1b..019595ce 100644 --- a/datapoolglob/GlobalDataSet.h +++ b/datapoolglob/GlobalDataSet.h @@ -1,96 +1,96 @@ -#ifndef FRAMEWORK_DATAPOOLGLOB_DATASET_H_ -#define FRAMEWORK_DATAPOOLGLOB_DATASET_H_ - -#include - -/** - * @brief The DataSet class manages a set of locally checked out variables - * for the global data pool. - * @details - * This class uses the read-commit() semantic provided by the DataSetBase class. - * It extends the base class by using the global data pool, - * having a valid state and implementing lock und unlock calls for the global - * datapool. - * - * For more information on how this class works, see the DataSetBase - * documentation. - * @author Bastian Baetz - * @ingroup data_pool - */ -class GlobDataSet: public DataSetBase { -public: - - /** - * @brief Creates an empty GlobDataSet. Use registerVariable or - * supply a pointer to this dataset to PoolVariable - * initializations to register pool variables. - */ - GlobDataSet(); - - /** - * @brief The destructor automatically manages writing the valid - * information of variables. - * @details - * In case the data set was read out, but not committed(indicated by state), - * the destructor parses all variables that are still registered to the set. - * For each, the valid flag in the data pool is set to "invalid". - */ - ~GlobDataSet(); - - /** - * Variant of method above which sets validity of all elements of the set. - * @param valid Validity information from PoolVariableIF. - * @return - @c RETURN_OK if all variables were read successfully. - * - @c COMMITING_WITHOUT_READING if set was not read yet and - * contains non write-only variables - */ - ReturnValue_t commit(bool valid, uint32_t lockTimeout = MutexIF::BLOCKING); - ReturnValue_t commit(uint32_t lockTimeout = MutexIF::BLOCKING) override; - - /** - * Set all entries - * @param valid - */ - void setSetValid(bool valid); - - /** - * Set the valid information of all variables contained in the set which - * are not read-only - * - * @param valid Validity information from PoolVariableIF. - */ - void setEntriesValid(bool valid); - - //!< This definition sets the maximum number of variables to - //! register in one DataSet. - static const uint8_t DATA_SET_MAX_SIZE = 63; - -private: - /** - * If the valid state of a dataset is always relevant to the whole - * data set we can use this flag. - */ - bool valid = false; - - /** - * @brief This is a small helper function to facilitate locking - * the global data pool. - * @details - * It makes use of the lockDataPool method offered by the DataPool class. - */ - ReturnValue_t lockDataPool(uint32_t timeoutMs) override; - /** - * @brief This is a small helper function to facilitate - * unlocking the global data pool - * @details - * It makes use of the freeDataPoolLock method offered by the DataPool class. - */ - ReturnValue_t unlockDataPool() override; - - void handleAlreadyReadDatasetCommit(); - ReturnValue_t handleUnreadDatasetCommit(); - - PoolVariableIF* registeredVariables[DATA_SET_MAX_SIZE]; -}; - -#endif /* FRAMEWORK_DATAPOOLGLOB_DATASET_H_ */ +#ifndef FRAMEWORK_DATAPOOLGLOB_DATASET_H_ +#define FRAMEWORK_DATAPOOLGLOB_DATASET_H_ + +#include "../datapool/DataSetBase.h" + +/** + * @brief The DataSet class manages a set of locally checked out variables + * for the global data pool. + * @details + * This class uses the read-commit() semantic provided by the DataSetBase class. + * It extends the base class by using the global data pool, + * having a valid state and implementing lock und unlock calls for the global + * datapool. + * + * For more information on how this class works, see the DataSetBase + * documentation. + * @author Bastian Baetz + * @ingroup data_pool + */ +class GlobDataSet: public DataSetBase { +public: + + /** + * @brief Creates an empty GlobDataSet. Use registerVariable or + * supply a pointer to this dataset to PoolVariable + * initializations to register pool variables. + */ + GlobDataSet(); + + /** + * @brief The destructor automatically manages writing the valid + * information of variables. + * @details + * In case the data set was read out, but not committed(indicated by state), + * the destructor parses all variables that are still registered to the set. + * For each, the valid flag in the data pool is set to "invalid". + */ + ~GlobDataSet(); + + /** + * Variant of method above which sets validity of all elements of the set. + * @param valid Validity information from PoolVariableIF. + * @return - @c RETURN_OK if all variables were read successfully. + * - @c COMMITING_WITHOUT_READING if set was not read yet and + * contains non write-only variables + */ + ReturnValue_t commit(bool valid, uint32_t lockTimeout = MutexIF::BLOCKING); + ReturnValue_t commit(uint32_t lockTimeout = MutexIF::BLOCKING) override; + + /** + * Set all entries + * @param valid + */ + void setSetValid(bool valid); + + /** + * Set the valid information of all variables contained in the set which + * are not read-only + * + * @param valid Validity information from PoolVariableIF. + */ + void setEntriesValid(bool valid); + + //!< This definition sets the maximum number of variables to + //! register in one DataSet. + static const uint8_t DATA_SET_MAX_SIZE = 63; + +private: + /** + * If the valid state of a dataset is always relevant to the whole + * data set we can use this flag. + */ + bool valid = false; + + /** + * @brief This is a small helper function to facilitate locking + * the global data pool. + * @details + * It makes use of the lockDataPool method offered by the DataPool class. + */ + ReturnValue_t lockDataPool(uint32_t timeoutMs) override; + /** + * @brief This is a small helper function to facilitate + * unlocking the global data pool + * @details + * It makes use of the freeDataPoolLock method offered by the DataPool class. + */ + ReturnValue_t unlockDataPool() override; + + void handleAlreadyReadDatasetCommit(); + ReturnValue_t handleUnreadDatasetCommit(); + + PoolVariableIF* registeredVariables[DATA_SET_MAX_SIZE]; +}; + +#endif /* FRAMEWORK_DATAPOOLGLOB_DATASET_H_ */ diff --git a/datapoolglob/GlobalPoolVariable.h b/datapoolglob/GlobalPoolVariable.h index b4aa6c4c..f5fc49f8 100644 --- a/datapoolglob/GlobalPoolVariable.h +++ b/datapoolglob/GlobalPoolVariable.h @@ -1,213 +1,213 @@ -#ifndef GLOBALPOOLVARIABLE_H_ -#define GLOBALPOOLVARIABLE_H_ - -#include -#include -#include -#include -#include -#include - -template class PoolVarList; - - -/** - * @brief This is the access class for non-array data pool entries. - * - * @details - * To ensure safe usage of the data pool, operation is not done directly - * on the data pool entries, but on local copies. This class provides simple - * type-safe access to single data pool entries (i.e. entries with length = 1). - * The class can be instantiated as read-write and read only. - * It provides a commit-and-roll-back semantic, which means that the - * variable's value in the data pool is not changed until the - * commit call is executed. - * @tparam T The template parameter sets the type of the variable. - * Currently, all plain data types are supported, but in principle - * any type is possible. - * @ingroup data_pool - */ -template -class GlobPoolVar: public PoolVariableIF { - template friend class PoolVarList; - static_assert(not std::is_same::value, - "Do not use boolean for the PoolEntry type, use uint8_t instead!" - "There is no boolean type in CCSDS."); -public: - /** - * @brief In the constructor, the variable can register itself in a - * DataSet (if nullptr is not passed). - * @details - * It DOES NOT fetch the current value from the data pool, but - * sets the value attribute to default (0). - * The value is fetched within the read() operation. - * @param set_id This is the id in the global data pool - * this instance of the access class corresponds to. - * @param dataSet The data set in which the variable shall register - * itself. If NULL, the variable is not registered. - * @param setWritable If this flag is set to true, changes in the value - * attribute can be written back to the data pool, otherwise not. - */ - GlobPoolVar(uint32_t set_id, DataSetIF* dataSet, - ReadWriteMode_t setReadWriteMode); - - /** - * @brief This is the local copy of the data pool entry. - * @details The user can work on this attribute - * just like he would on a simple local variable. - */ - T value = 0; - - /** - * @brief Copy ctor to copy classes containing Pool Variables. - * (Robin): This only copies member variables, which is done - * by the default copy ctor. maybe we can ommit this ctor? - */ - GlobPoolVar(const GlobPoolVar& rhs); - - /** - * @brief The classes destructor is empty. - * @details If commit() was not called, the local value is - * discarded and not written back to the data pool. - */ - ~GlobPoolVar() {} - - /** - * @brief This is a call to read the value from the global data pool. - * @details - * When executed, this operation tries to fetch the pool entry with matching - * data pool id from the global data pool and copies the value and the valid - * information to its local attributes. In case of a failure (wrong type or - * pool id not found), the variable is set to zero and invalid. - * The read call is protected with a lock. - * It is recommended to use DataSets to read and commit multiple variables - * at once to avoid the overhead of unnecessary lock und unlock operations. - */ - ReturnValue_t read(uint32_t lockTimeout) override; - /** - * @brief The commit call writes back the variable's value to the data pool. - * @details - * It checks type and size, as well as if the variable is writable. If so, - * the value is copied and the valid flag is automatically set to "valid". - * The operation does NOT provide any mutual exclusive protection by itself. - * The commit call is protected with a lock. - * It is recommended to use DataSets to read and commit multiple variables - * at once to avoid the overhead of unnecessary lock und unlock operations. - */ - ReturnValue_t commit(uint32_t lockTimeout) override; - -protected: - /** - * @brief Like #read, but without a lock protection of the global pool. - * @details - * The operation does NOT provide any mutual exclusive protection by itself. - * This can be used if the lock is handled externally to avoid the overhead - * of consecutive lock und unlock operations. - * Declared protected to discourage free public usage. - */ - ReturnValue_t readWithoutLock() override; - /** - * @brief Like #commit, but without a lock protection of the global pool. - * @details - * The operation does NOT provide any mutual exclusive protection by itself. - * This can be used if the lock is handled externally to avoid the overhead - * of consecutive lock und unlock operations. - * Declared protected to discourage free public usage. - */ - ReturnValue_t commitWithoutLock() override; - /** - * @brief To access the correct data pool entry on read and commit calls, - * the data pool is stored. - */ - uint32_t dataPoolId; - - /** - * @brief The valid information as it was stored in the data pool is - * copied to this attribute. - */ - uint8_t valid; - - /** - * @brief The information whether the class is read-write or read-only - * is stored here. - */ - pool_rwm_t readWriteMode; - - /** - * Empty ctor for List initialization - */ - GlobPoolVar(); -public: - /** - * \brief This operation returns the data pool id of the variable. - */ - uint32_t getDataPoolId() const override; - - /** - * This method returns if the variable is write-only, read-write or read-only. - */ - ReadWriteMode_t getReadWriteMode() const override; - /** - * This operation sets the data pool id of the variable. - * The method is necessary to set id's of data pool member variables with bad initialization. - */ - void setDataPoolId(uint32_t poolId); - - /** - * \brief With this call, the valid information of the variable is returned. - */ - bool isValid() const override; - - uint8_t getValid(); - - void setValid(bool valid) override; - - operator T() { - return value; - } - - operator T() const { - return value; - } - - GlobPoolVar &operator=(T newValue) { - value = newValue; - return *this; - } - - GlobPoolVar &operator=(GlobPoolVar newPoolVariable) { - value = newPoolVariable.value; - return *this; - } - - virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, - const size_t max_size, - SerializeIF::Endianness streamEndianness) const override { - return SerializeAdapter::serialize(&value, buffer, size, max_size, - streamEndianness); - } - - virtual size_t getSerializedSize() const { - return SerializeAdapter::getSerializedSize(&value); - } - - virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - SerializeIF::Endianness streamEndianness) { - return SerializeAdapter::deSerialize(&value, buffer, size, - streamEndianness); - } -}; - -#include - -typedef GlobPoolVar gp_bool_t; -typedef GlobPoolVar gp_uint8_t; -typedef GlobPoolVar gp_uint16_t; -typedef GlobPoolVar gp_uint32_t; -typedef GlobPoolVar gp_int8_t; -typedef GlobPoolVar gp_int16_t; -typedef GlobPoolVar gp_int32_t; -typedef GlobPoolVar gp_float_t; -typedef GlobPoolVar gp_double_t; - -#endif /* POOLVARIABLE_H_ */ +#ifndef GLOBALPOOLVARIABLE_H_ +#define GLOBALPOOLVARIABLE_H_ + +#include "../datapool/DataSetIF.h" +#include "../datapoolglob/GlobalDataPool.h" +#include "../datapool/PoolVariableIF.h" +#include "../datapool/PoolEntry.h" +#include "../serialize/SerializeAdapter.h" +#include "../serviceinterface/ServiceInterfaceStream.h" + +template class PoolVarList; + + +/** + * @brief This is the access class for non-array data pool entries. + * + * @details + * To ensure safe usage of the data pool, operation is not done directly + * on the data pool entries, but on local copies. This class provides simple + * type-safe access to single data pool entries (i.e. entries with length = 1). + * The class can be instantiated as read-write and read only. + * It provides a commit-and-roll-back semantic, which means that the + * variable's value in the data pool is not changed until the + * commit call is executed. + * @tparam T The template parameter sets the type of the variable. + * Currently, all plain data types are supported, but in principle + * any type is possible. + * @ingroup data_pool + */ +template +class GlobPoolVar: public PoolVariableIF { + template friend class PoolVarList; + static_assert(not std::is_same::value, + "Do not use boolean for the PoolEntry type, use uint8_t instead!" + "There is no boolean type in CCSDS."); +public: + /** + * @brief In the constructor, the variable can register itself in a + * DataSet (if nullptr is not passed). + * @details + * It DOES NOT fetch the current value from the data pool, but + * sets the value attribute to default (0). + * The value is fetched within the read() operation. + * @param set_id This is the id in the global data pool + * this instance of the access class corresponds to. + * @param dataSet The data set in which the variable shall register + * itself. If NULL, the variable is not registered. + * @param setWritable If this flag is set to true, changes in the value + * attribute can be written back to the data pool, otherwise not. + */ + GlobPoolVar(uint32_t set_id, DataSetIF* dataSet, + ReadWriteMode_t setReadWriteMode); + + /** + * @brief This is the local copy of the data pool entry. + * @details The user can work on this attribute + * just like he would on a simple local variable. + */ + T value = 0; + + /** + * @brief Copy ctor to copy classes containing Pool Variables. + * (Robin): This only copies member variables, which is done + * by the default copy ctor. maybe we can ommit this ctor? + */ + GlobPoolVar(const GlobPoolVar& rhs); + + /** + * @brief The classes destructor is empty. + * @details If commit() was not called, the local value is + * discarded and not written back to the data pool. + */ + ~GlobPoolVar() {} + + /** + * @brief This is a call to read the value from the global data pool. + * @details + * When executed, this operation tries to fetch the pool entry with matching + * data pool id from the global data pool and copies the value and the valid + * information to its local attributes. In case of a failure (wrong type or + * pool id not found), the variable is set to zero and invalid. + * The read call is protected with a lock. + * It is recommended to use DataSets to read and commit multiple variables + * at once to avoid the overhead of unnecessary lock und unlock operations. + */ + ReturnValue_t read(uint32_t lockTimeout) override; + /** + * @brief The commit call writes back the variable's value to the data pool. + * @details + * It checks type and size, as well as if the variable is writable. If so, + * the value is copied and the valid flag is automatically set to "valid". + * The operation does NOT provide any mutual exclusive protection by itself. + * The commit call is protected with a lock. + * It is recommended to use DataSets to read and commit multiple variables + * at once to avoid the overhead of unnecessary lock und unlock operations. + */ + ReturnValue_t commit(uint32_t lockTimeout) override; + +protected: + /** + * @brief Like #read, but without a lock protection of the global pool. + * @details + * The operation does NOT provide any mutual exclusive protection by itself. + * This can be used if the lock is handled externally to avoid the overhead + * of consecutive lock und unlock operations. + * Declared protected to discourage free public usage. + */ + ReturnValue_t readWithoutLock() override; + /** + * @brief Like #commit, but without a lock protection of the global pool. + * @details + * The operation does NOT provide any mutual exclusive protection by itself. + * This can be used if the lock is handled externally to avoid the overhead + * of consecutive lock und unlock operations. + * Declared protected to discourage free public usage. + */ + ReturnValue_t commitWithoutLock() override; + /** + * @brief To access the correct data pool entry on read and commit calls, + * the data pool is stored. + */ + uint32_t dataPoolId; + + /** + * @brief The valid information as it was stored in the data pool is + * copied to this attribute. + */ + uint8_t valid; + + /** + * @brief The information whether the class is read-write or read-only + * is stored here. + */ + pool_rwm_t readWriteMode; + + /** + * Empty ctor for List initialization + */ + GlobPoolVar(); +public: + /** + * \brief This operation returns the data pool id of the variable. + */ + uint32_t getDataPoolId() const override; + + /** + * This method returns if the variable is write-only, read-write or read-only. + */ + ReadWriteMode_t getReadWriteMode() const override; + /** + * This operation sets the data pool id of the variable. + * The method is necessary to set id's of data pool member variables with bad initialization. + */ + void setDataPoolId(uint32_t poolId); + + /** + * \brief With this call, the valid information of the variable is returned. + */ + bool isValid() const override; + + uint8_t getValid(); + + void setValid(bool valid) override; + + operator T() { + return value; + } + + operator T() const { + return value; + } + + GlobPoolVar &operator=(T newValue) { + value = newValue; + return *this; + } + + GlobPoolVar &operator=(GlobPoolVar newPoolVariable) { + value = newPoolVariable.value; + return *this; + } + + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, + SerializeIF::Endianness streamEndianness) const override { + return SerializeAdapter::serialize(&value, buffer, size, max_size, + streamEndianness); + } + + virtual size_t getSerializedSize() const { + return SerializeAdapter::getSerializedSize(&value); + } + + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + SerializeIF::Endianness streamEndianness) { + return SerializeAdapter::deSerialize(&value, buffer, size, + streamEndianness); + } +}; + +#include "../datapoolglob/GlobalPoolVariable.tpp" + +typedef GlobPoolVar gp_bool_t; +typedef GlobPoolVar gp_uint8_t; +typedef GlobPoolVar gp_uint16_t; +typedef GlobPoolVar gp_uint32_t; +typedef GlobPoolVar gp_int8_t; +typedef GlobPoolVar gp_int16_t; +typedef GlobPoolVar gp_int32_t; +typedef GlobPoolVar gp_float_t; +typedef GlobPoolVar gp_double_t; + +#endif /* POOLVARIABLE_H_ */ diff --git a/datapoolglob/GlobalPoolVector.h b/datapoolglob/GlobalPoolVector.h index 0e03f77d..eb40d1f1 100644 --- a/datapoolglob/GlobalPoolVector.h +++ b/datapoolglob/GlobalPoolVector.h @@ -1,185 +1,185 @@ -#ifndef GLOBALPOOLVECTOR_H_ -#define GLOBALPOOLVECTOR_H_ - -#include -#include -#include -#include -#include - -/** - * @brief This is the access class for array-type data pool entries. - * - * @details - * To ensure safe usage of the data pool, operation is not done directly on the - * data pool entries, but on local copies. This class provides simple type- - * and length-safe access to vector-style data pool entries (i.e. entries with - * length > 1). The class can be instantiated as read-write and read only. - * - * It provides a commit-and-roll-back semantic, which means that no array - * entry in the data pool is changed until the commit call is executed. - * There are two template parameters: - * @tparam T - * This template parameter specifies the data type of an array entry. Currently, - * all plain data types are supported, but in principle any type is possible. - * @tparam vector_size - * This template parameter specifies the vector size of this entry. Using a - * template parameter for this is not perfect, but avoids - * dynamic memory allocation. - * @ingroup data_pool - */ -template -class GlobPoolVector: public PoolVariableIF { -public: - /** - * @brief In the constructor, the variable can register itself in a - * DataSet (if no nullptr is passed). - * @details - * It DOES NOT fetch the current value from the data pool, but sets the - * value attribute to default (0). The value is fetched within the - * read() operation. - * @param set_id - * This is the id in the global data pool this instance of the access - * class corresponds to. - * @param dataSet - * The data set in which the variable shall register itself. If nullptr, - * the variable is not registered. - * @param setWritable - * If this flag is set to true, changes in the value attribute can be - * written back to the data pool, otherwise not. - */ - GlobPoolVector(uint32_t set_id, DataSetIF* set, - ReadWriteMode_t setReadWriteMode); - - /** - * @brief This is the local copy of the data pool entry. - * @details The user can work on this attribute - * just like he would on a local array of this type. - */ - T value[vectorSize]; - /** - * @brief The classes destructor is empty. - * @details If commit() was not called, the local value is - * discarded and not written back to the data pool. - */ - ~GlobPoolVector() {}; - /** - * @brief The operation returns the number of array entries - * in this variable. - */ - uint8_t getSize() { - return vectorSize; - } - /** - * @brief This operation returns the data pool id of the variable. - */ - uint32_t getDataPoolId() const { - return dataPoolId; - } - /** - * @brief This operation sets the data pool id of the variable. - * @details - * The method is necessary to set id's of data pool member variables - * with bad initialization. - */ - void setDataPoolId(uint32_t poolId) { - dataPoolId = poolId; - } - /** - * This method returns if the variable is write-only, read-write or read-only. - */ - ReadWriteMode_t getReadWriteMode() const { - return readWriteMode; - } - - - /** - * @brief With this call, the valid information of the variable is returned. - */ - bool isValid() const { - if (valid != INVALID) - return true; - else - return false; - } - void setValid(bool valid) {this->valid = valid;} - uint8_t getValid() {return valid;} - - T &operator [](int i) {return value[i];} - const T &operator [](int i) const {return value[i];} - - virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, - size_t max_size, Endianness streamEndianness) const override; - virtual size_t getSerializedSize() const override; - virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - Endianness streamEndianness) override; - - /** - * @brief This is a call to read the array's values - * from the global data pool. - * @details - * When executed, this operation tries to fetch the pool entry with matching - * data pool id from the global data pool and copies all array values - * and the valid information to its local attributes. - * In case of a failure (wrong type, size or pool id not found), the - * variable is set to zero and invalid. - * The read call is protected by a lock of the global data pool. - * It is recommended to use DataSets to read and commit multiple variables - * at once to avoid the overhead of unnecessary lock und unlock operations. - */ - ReturnValue_t read(uint32_t lockTimeout = MutexIF::BLOCKING) override; - /** - * @brief The commit call copies the array values back to the data pool. - * @details - * It checks type and size, as well as if the variable is writable. If so, - * the value is copied and the valid flag is automatically set to "valid". - * The commit call is protected by a lock of the global data pool. - * It is recommended to use DataSets to read and commit multiple variables - * at once to avoid the overhead of unnecessary lock und unlock operations. - */ - ReturnValue_t commit(uint32_t lockTimeout = MutexIF::BLOCKING) override; - -protected: - /** - * @brief Like #read, but without a lock protection of the global pool. - * @details - * The operation does NOT provide any mutual exclusive protection by itself. - * This can be used if the lock is handled externally to avoid the overhead - * of consecutive lock und unlock operations. - * Declared protected to discourage free public usage. - */ - ReturnValue_t readWithoutLock() override; - /** - * @brief Like #commit, but without a lock protection of the global pool. - * @details - * The operation does NOT provide any mutual exclusive protection by itself. - * This can be used if the lock is handled externally to avoid the overhead - * of consecutive lock und unlock operations. - * Declared protected to discourage free public usage. - */ - ReturnValue_t commitWithoutLock() override; - -private: - /** - * @brief To access the correct data pool entry on read and commit calls, - * the data pool id is stored. - */ - uint32_t dataPoolId; - /** - * @brief The valid information as it was stored in the data pool - * is copied to this attribute. - */ - uint8_t valid; - /** - * @brief The information whether the class is read-write or - * read-only is stored here. - */ - ReadWriteMode_t readWriteMode; -}; - -#include - -template -using gp_vec_t = GlobPoolVector; - -#endif /* POOLVECTOR_H_ */ +#ifndef GLOBALPOOLVECTOR_H_ +#define GLOBALPOOLVECTOR_H_ + +#include "../datapool/DataSetIF.h" +#include "../datapool/PoolEntry.h" +#include "../datapool/PoolVariableIF.h" +#include "../serialize/SerializeAdapter.h" +#include "../serviceinterface/ServiceInterfaceStream.h" + +/** + * @brief This is the access class for array-type data pool entries. + * + * @details + * To ensure safe usage of the data pool, operation is not done directly on the + * data pool entries, but on local copies. This class provides simple type- + * and length-safe access to vector-style data pool entries (i.e. entries with + * length > 1). The class can be instantiated as read-write and read only. + * + * It provides a commit-and-roll-back semantic, which means that no array + * entry in the data pool is changed until the commit call is executed. + * There are two template parameters: + * @tparam T + * This template parameter specifies the data type of an array entry. Currently, + * all plain data types are supported, but in principle any type is possible. + * @tparam vector_size + * This template parameter specifies the vector size of this entry. Using a + * template parameter for this is not perfect, but avoids + * dynamic memory allocation. + * @ingroup data_pool + */ +template +class GlobPoolVector: public PoolVariableIF { +public: + /** + * @brief In the constructor, the variable can register itself in a + * DataSet (if no nullptr is passed). + * @details + * It DOES NOT fetch the current value from the data pool, but sets the + * value attribute to default (0). The value is fetched within the + * read() operation. + * @param set_id + * This is the id in the global data pool this instance of the access + * class corresponds to. + * @param dataSet + * The data set in which the variable shall register itself. If nullptr, + * the variable is not registered. + * @param setWritable + * If this flag is set to true, changes in the value attribute can be + * written back to the data pool, otherwise not. + */ + GlobPoolVector(uint32_t set_id, DataSetIF* set, + ReadWriteMode_t setReadWriteMode); + + /** + * @brief This is the local copy of the data pool entry. + * @details The user can work on this attribute + * just like he would on a local array of this type. + */ + T value[vectorSize]; + /** + * @brief The classes destructor is empty. + * @details If commit() was not called, the local value is + * discarded and not written back to the data pool. + */ + ~GlobPoolVector() {}; + /** + * @brief The operation returns the number of array entries + * in this variable. + */ + uint8_t getSize() { + return vectorSize; + } + /** + * @brief This operation returns the data pool id of the variable. + */ + uint32_t getDataPoolId() const { + return dataPoolId; + } + /** + * @brief This operation sets the data pool id of the variable. + * @details + * The method is necessary to set id's of data pool member variables + * with bad initialization. + */ + void setDataPoolId(uint32_t poolId) { + dataPoolId = poolId; + } + /** + * This method returns if the variable is write-only, read-write or read-only. + */ + ReadWriteMode_t getReadWriteMode() const { + return readWriteMode; + } + + + /** + * @brief With this call, the valid information of the variable is returned. + */ + bool isValid() const { + if (valid != INVALID) + return true; + else + return false; + } + void setValid(bool valid) {this->valid = valid;} + uint8_t getValid() {return valid;} + + T &operator [](int i) {return value[i];} + const T &operator [](int i) const {return value[i];} + + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + size_t max_size, Endianness streamEndianness) const override; + virtual size_t getSerializedSize() const override; + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + Endianness streamEndianness) override; + + /** + * @brief This is a call to read the array's values + * from the global data pool. + * @details + * When executed, this operation tries to fetch the pool entry with matching + * data pool id from the global data pool and copies all array values + * and the valid information to its local attributes. + * In case of a failure (wrong type, size or pool id not found), the + * variable is set to zero and invalid. + * The read call is protected by a lock of the global data pool. + * It is recommended to use DataSets to read and commit multiple variables + * at once to avoid the overhead of unnecessary lock und unlock operations. + */ + ReturnValue_t read(uint32_t lockTimeout = MutexIF::BLOCKING) override; + /** + * @brief The commit call copies the array values back to the data pool. + * @details + * It checks type and size, as well as if the variable is writable. If so, + * the value is copied and the valid flag is automatically set to "valid". + * The commit call is protected by a lock of the global data pool. + * It is recommended to use DataSets to read and commit multiple variables + * at once to avoid the overhead of unnecessary lock und unlock operations. + */ + ReturnValue_t commit(uint32_t lockTimeout = MutexIF::BLOCKING) override; + +protected: + /** + * @brief Like #read, but without a lock protection of the global pool. + * @details + * The operation does NOT provide any mutual exclusive protection by itself. + * This can be used if the lock is handled externally to avoid the overhead + * of consecutive lock und unlock operations. + * Declared protected to discourage free public usage. + */ + ReturnValue_t readWithoutLock() override; + /** + * @brief Like #commit, but without a lock protection of the global pool. + * @details + * The operation does NOT provide any mutual exclusive protection by itself. + * This can be used if the lock is handled externally to avoid the overhead + * of consecutive lock und unlock operations. + * Declared protected to discourage free public usage. + */ + ReturnValue_t commitWithoutLock() override; + +private: + /** + * @brief To access the correct data pool entry on read and commit calls, + * the data pool id is stored. + */ + uint32_t dataPoolId; + /** + * @brief The valid information as it was stored in the data pool + * is copied to this attribute. + */ + uint8_t valid; + /** + * @brief The information whether the class is read-write or + * read-only is stored here. + */ + ReadWriteMode_t readWriteMode; +}; + +#include "../datapoolglob/GlobalPoolVector.tpp" + +template +using gp_vec_t = GlobPoolVector; + +#endif /* POOLVECTOR_H_ */ diff --git a/datapoolglob/PIDReader.h b/datapoolglob/PIDReader.h index a1116040..7d12a0fd 100644 --- a/datapoolglob/PIDReader.h +++ b/datapoolglob/PIDReader.h @@ -1,164 +1,164 @@ -#ifndef PIDREADER_H_ -#define PIDREADER_H_ -#include -#include -#include -#include -#include -#include - -template class PIDReaderList; - -template -class PIDReader: public PoolVariableIF { - template friend class PIDReaderList; -protected: - uint32_t parameterId; - uint8_t valid; - ReturnValue_t readWithoutLock() { - uint8_t arrayIndex = GlobalDataPool::PIDToArrayIndex(parameterId); - PoolEntry *read_out = glob::dataPool.getData( - GlobalDataPool::PIDToDataPoolId(parameterId), arrayIndex); - if (read_out != NULL) { - valid = read_out->valid; - value = read_out->address[arrayIndex]; - return HasReturnvaluesIF::RETURN_OK; - } else { - value = 0; - valid = false; - sif::error << "PIDReader: read of PID 0x" << std::hex << parameterId - << std::dec << " failed." << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - } - /** - * Never commit, is read-only. - * Reason is the possibility to access a single DP vector element, but if we commit, - * we set validity of the whole vector. - */ - ReturnValue_t commit(uint32_t lockTimeout) override { - return HasReturnvaluesIF::RETURN_FAILED; - } - ReturnValue_t commitWithoutLock() override { - return HasReturnvaluesIF::RETURN_FAILED; - } - - /** - * Empty ctor for List initialization - */ - PIDReader() : - parameterId(PoolVariableIF::NO_PARAMETER), valid( - PoolVariableIF::INVALID), value(0) { - - } -public: - /** - * \brief This is the local copy of the data pool entry. - */ - T value; - /** - * \brief In the constructor, the variable can register itself in a DataSet (if not NULL is - * passed). - * \details It DOES NOT fetch the current value from the data pool, but sets the value - * attribute to default (0). The value is fetched within the read() operation. - * \param set_id This is the id in the global data pool this instance of the access class - * corresponds to. - * \param dataSet The data set in which the variable shall register itself. If NULL, - * the variable is not registered. - * \param setWritable If this flag is set to true, changes in the value attribute can be - * written back to the data pool, otherwise not. - */ - PIDReader(uint32_t setParameterId, DataSetIF *dataSet) : - parameterId(setParameterId), valid(PoolVariableIF::INVALID), value( - 0) { - if (dataSet != NULL) { - dataSet->registerVariable(this); - } - } - - ReturnValue_t read(uint32_t lockTimeout) override { - ReturnValue_t result = glob::dataPool.lockDataPool(); - if(result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - result = readWithoutLock(); - ReturnValue_t unlockResult = glob::dataPool.unlockDataPool(); - if(unlockResult != HasReturnvaluesIF::RETURN_OK) { - sif::error << "PIDReader::read: Could not unlock data pool!" - << std::endl; - } - return result; - } - /** - * Copy ctor to copy classes containing Pool Variables. - */ - PIDReader(const PIDReader &rhs) : - parameterId(rhs.parameterId), valid(rhs.valid), value(rhs.value) { - } - - /** - * \brief The classes destructor is empty. - */ - ~PIDReader() { - - } - /** - * \brief This operation returns the data pool id of the variable. - */ - uint32_t getDataPoolId() const { - return GlobalDataPool::PIDToDataPoolId(parameterId); - } - uint32_t getParameterId() const { - return parameterId; - } - /** - * This method returns if the variable is write-only, read-write or read-only. - */ - ReadWriteMode_t getReadWriteMode() const { - return VAR_READ; - } - /** - * \brief With this call, the valid information of the variable is returned. - */ - bool isValid() const { - if (valid) - return true; - else - return false; - } - - uint8_t getValid() { - return valid; - } - - void setValid(bool valid) { - this->valid = valid; - } - - operator T() { - return value; - } - - PIDReader& operator=(T newValue) { - value = newValue; - return *this; - } - - virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size, - size_t maxSize, Endianness streamEndianness) const override { - return SerializeAdapter::serialize(&value, buffer, size, maxSize, - streamEndianness); - } - - virtual size_t getSerializedSize() const override { - return SerializeAdapter::getSerializedSize(&value); - } - - virtual ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, - Endianness streamEndianness) override { - return SerializeAdapter::deSerialize(&value, buffer, size, - streamEndianness); - } -}; - -#endif /* PIDREADER_H_ */ +#ifndef PIDREADER_H_ +#define PIDREADER_H_ +#include "../datapool/DataSetIF.h" +#include "../datapoolglob/GlobalDataPool.h" +#include "../datapool/PoolEntry.h" +#include "../datapool/PoolVariableIF.h" +#include "../serialize/SerializeAdapter.h" +#include "../serviceinterface/ServiceInterfaceStream.h" + +template class PIDReaderList; + +template +class PIDReader: public PoolVariableIF { + template friend class PIDReaderList; +protected: + uint32_t parameterId; + uint8_t valid; + ReturnValue_t readWithoutLock() { + uint8_t arrayIndex = GlobalDataPool::PIDToArrayIndex(parameterId); + PoolEntry *read_out = glob::dataPool.getData( + GlobalDataPool::PIDToDataPoolId(parameterId), arrayIndex); + if (read_out != NULL) { + valid = read_out->valid; + value = read_out->address[arrayIndex]; + return HasReturnvaluesIF::RETURN_OK; + } else { + value = 0; + valid = false; + sif::error << "PIDReader: read of PID 0x" << std::hex << parameterId + << std::dec << " failed." << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + } + /** + * Never commit, is read-only. + * Reason is the possibility to access a single DP vector element, but if we commit, + * we set validity of the whole vector. + */ + ReturnValue_t commit(uint32_t lockTimeout) override { + return HasReturnvaluesIF::RETURN_FAILED; + } + ReturnValue_t commitWithoutLock() override { + return HasReturnvaluesIF::RETURN_FAILED; + } + + /** + * Empty ctor for List initialization + */ + PIDReader() : + parameterId(PoolVariableIF::NO_PARAMETER), valid( + PoolVariableIF::INVALID), value(0) { + + } +public: + /** + * \brief This is the local copy of the data pool entry. + */ + T value; + /** + * \brief In the constructor, the variable can register itself in a DataSet (if not NULL is + * passed). + * \details It DOES NOT fetch the current value from the data pool, but sets the value + * attribute to default (0). The value is fetched within the read() operation. + * \param set_id This is the id in the global data pool this instance of the access class + * corresponds to. + * \param dataSet The data set in which the variable shall register itself. If NULL, + * the variable is not registered. + * \param setWritable If this flag is set to true, changes in the value attribute can be + * written back to the data pool, otherwise not. + */ + PIDReader(uint32_t setParameterId, DataSetIF *dataSet) : + parameterId(setParameterId), valid(PoolVariableIF::INVALID), value( + 0) { + if (dataSet != NULL) { + dataSet->registerVariable(this); + } + } + + ReturnValue_t read(uint32_t lockTimeout) override { + ReturnValue_t result = glob::dataPool.lockDataPool(); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = readWithoutLock(); + ReturnValue_t unlockResult = glob::dataPool.unlockDataPool(); + if(unlockResult != HasReturnvaluesIF::RETURN_OK) { + sif::error << "PIDReader::read: Could not unlock data pool!" + << std::endl; + } + return result; + } + /** + * Copy ctor to copy classes containing Pool Variables. + */ + PIDReader(const PIDReader &rhs) : + parameterId(rhs.parameterId), valid(rhs.valid), value(rhs.value) { + } + + /** + * \brief The classes destructor is empty. + */ + ~PIDReader() { + + } + /** + * \brief This operation returns the data pool id of the variable. + */ + uint32_t getDataPoolId() const { + return GlobalDataPool::PIDToDataPoolId(parameterId); + } + uint32_t getParameterId() const { + return parameterId; + } + /** + * This method returns if the variable is write-only, read-write or read-only. + */ + ReadWriteMode_t getReadWriteMode() const { + return VAR_READ; + } + /** + * \brief With this call, the valid information of the variable is returned. + */ + bool isValid() const { + if (valid) + return true; + else + return false; + } + + uint8_t getValid() { + return valid; + } + + void setValid(bool valid) { + this->valid = valid; + } + + operator T() { + return value; + } + + PIDReader& operator=(T newValue) { + value = newValue; + return *this; + } + + virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size, + size_t maxSize, Endianness streamEndianness) const override { + return SerializeAdapter::serialize(&value, buffer, size, maxSize, + streamEndianness); + } + + virtual size_t getSerializedSize() const override { + return SerializeAdapter::getSerializedSize(&value); + } + + virtual ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) override { + return SerializeAdapter::deSerialize(&value, buffer, size, + streamEndianness); + } +}; + +#endif /* PIDREADER_H_ */ diff --git a/datapoolglob/PIDReaderList.h b/datapoolglob/PIDReaderList.h index 0b838508..b167feaa 100644 --- a/datapoolglob/PIDReaderList.h +++ b/datapoolglob/PIDReaderList.h @@ -1,27 +1,27 @@ -#ifndef FRAMEWORK_DATAPOOLGLOB_PIDREADERLIST_H_ -#define FRAMEWORK_DATAPOOLGLOB_PIDREADERLIST_H_ - -#include -#include -template -class PIDReaderList { -private: - PIDReader variables[n_var]; -public: - PIDReaderList( const uint32_t setPid[n_var], DataSetIF* dataSet) { - //I really should have a look at the new init list c++ syntax. - if (dataSet == NULL) { - return; - } - for (uint8_t count = 0; count < n_var; count++) { - variables[count].parameterId = setPid[count]; - dataSet->registerVariable(&variables[count]); - } - } - - PIDReader &operator [](int i) { return variables[i]; } -}; - - - -#endif /* FRAMEWORK_DATAPOOLGLOB_PIDREADERLIST_H_ */ +#ifndef FRAMEWORK_DATAPOOLGLOB_PIDREADERLIST_H_ +#define FRAMEWORK_DATAPOOLGLOB_PIDREADERLIST_H_ + +#include "../datapool/PoolVariableIF.h" +#include "../datapoolglob/PIDReader.h" +template +class PIDReaderList { +private: + PIDReader variables[n_var]; +public: + PIDReaderList( const uint32_t setPid[n_var], DataSetIF* dataSet) { + //I really should have a look at the new init list c++ syntax. + if (dataSet == NULL) { + return; + } + for (uint8_t count = 0; count < n_var; count++) { + variables[count].parameterId = setPid[count]; + dataSet->registerVariable(&variables[count]); + } + } + + PIDReader &operator [](int i) { return variables[i]; } +}; + + + +#endif /* FRAMEWORK_DATAPOOLGLOB_PIDREADERLIST_H_ */ diff --git a/datapoolglob/PoolRawAccess.cpp b/datapoolglob/PoolRawAccess.cpp index 783418cc..09093cd6 100644 --- a/datapoolglob/PoolRawAccess.cpp +++ b/datapoolglob/PoolRawAccess.cpp @@ -1,239 +1,239 @@ -#include -#include -#include -#include - -#include - -PoolRawAccess::PoolRawAccess(uint32_t set_id, uint8_t setArrayEntry, - DataSetIF* dataSet, ReadWriteMode_t setReadWriteMode) : - dataPoolId(set_id), arrayEntry(setArrayEntry), valid(false), - type(Type::UNKNOWN_TYPE), typeSize(0), arraySize(0), sizeTillEnd(0), - readWriteMode(setReadWriteMode) { - memset(value, 0, sizeof(value)); - if (dataSet != nullptr) { - dataSet->registerVariable(this); - } -} - -PoolRawAccess::~PoolRawAccess() {} - -ReturnValue_t PoolRawAccess::read(uint32_t lockTimeout) { - ReturnValue_t result = glob::dataPool.lockDataPool(lockTimeout); - if(result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - result = readWithoutLock(); - ReturnValue_t unlockResult = glob::dataPool.unlockDataPool(); - if(unlockResult != HasReturnvaluesIF::RETURN_OK) { - sif::error << "GlobPoolVar::read: Could not unlock global data pool" - << std::endl; - } - return result; -} - -ReturnValue_t PoolRawAccess::readWithoutLock() { - ReturnValue_t result = RETURN_FAILED; - PoolEntryIF* readOut = glob::dataPool.getRawData(dataPoolId); - if (readOut != nullptr) { - result = handleReadOut(readOut); - if(result == RETURN_OK) { - return result; - } - } else { - result = READ_ENTRY_NON_EXISTENT; - } - handleReadError(result); - return result; -} - -ReturnValue_t PoolRawAccess::handleReadOut(PoolEntryIF* readOut) { - ReturnValue_t result = RETURN_FAILED; - valid = readOut->getValid(); - if (readOut->getSize() > arrayEntry) { - arraySize = readOut->getSize(); - typeSize = readOut->getByteSize() / readOut->getSize(); - type = readOut->getType(); - if (typeSize <= sizeof(value)) { - uint16_t arrayPosition = arrayEntry * typeSize; - sizeTillEnd = readOut->getByteSize() - arrayPosition; - uint8_t* ptr = &((uint8_t*) readOut->getRawData())[arrayPosition]; - memcpy(value, ptr, typeSize); - return RETURN_OK; - } else { - result = READ_TYPE_TOO_LARGE; - } - } else { - //debug << "PoolRawAccess: Size: " << (int)read_out->getSize() << std::endl; - result = READ_INDEX_TOO_LARGE; - } - return result; -} - -void PoolRawAccess::handleReadError(ReturnValue_t result) { - sif::error << "PoolRawAccess: read of DP Variable 0x" << std::hex << dataPoolId - << std::dec << " failed, "; - if(result == READ_TYPE_TOO_LARGE) { - sif::error << "type too large." << std::endl; - } - else if(result == READ_INDEX_TOO_LARGE) { - sif::error << "index too large." << std::endl; - } - else if(result == READ_ENTRY_NON_EXISTENT) { - sif::error << "entry does not exist." << std::endl; - } - - valid = INVALID; - typeSize = 0; - sizeTillEnd = 0; - memset(value, 0, sizeof(value)); -} - -ReturnValue_t PoolRawAccess::commit(uint32_t lockTimeout) { - ReturnValue_t result = glob::dataPool.lockDataPool(lockTimeout); - if(result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - result = commitWithoutLock(); - ReturnValue_t unlockResult = glob::dataPool.unlockDataPool(); - if(unlockResult != HasReturnvaluesIF::RETURN_OK) { - sif::error << "GlobPoolVar::read: Could not unlock global data pool" - << std::endl; - } - return result; -} - -ReturnValue_t PoolRawAccess::commitWithoutLock() { - PoolEntryIF* write_back = glob::dataPool.getRawData(dataPoolId); - if ((write_back != NULL) && (readWriteMode != VAR_READ)) { - write_back->setValid(valid); - uint8_t array_position = arrayEntry * typeSize; - uint8_t* ptr = &((uint8_t*) write_back->getRawData())[array_position]; - memcpy(ptr, value, typeSize); - return HasReturnvaluesIF::RETURN_OK; - } else { - return HasReturnvaluesIF::RETURN_FAILED; - } -} - -uint8_t* PoolRawAccess::getEntry() { - return value; -} - -ReturnValue_t PoolRawAccess::getEntryEndianSafe(uint8_t* buffer, - size_t* writtenBytes, size_t max_size) { - uint8_t* data_ptr = getEntry(); - // debug << "PoolRawAccess::getEntry: Array position: " << - // index * size_of_type << " Size of T: " << (int)size_of_type << - // " ByteSize: " << byte_size << " Position: " << *size << std::endl; - if (typeSize == 0) - return DATA_POOL_ACCESS_FAILED; - if (typeSize > max_size) - return INCORRECT_SIZE; - EndianConverter::convertBigEndian(buffer, data_ptr, typeSize); - *writtenBytes = typeSize; - return HasReturnvaluesIF::RETURN_OK; -} - - -ReturnValue_t PoolRawAccess::serialize(uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) const { - if (typeSize + *size <= maxSize) { - switch(streamEndianness) { - case(Endianness::BIG): - EndianConverter::convertBigEndian(*buffer, value, typeSize); - break; - case(Endianness::LITTLE): - EndianConverter::convertLittleEndian(*buffer, value, typeSize); - break; - case(Endianness::MACHINE): - default: - memcpy(*buffer, value, typeSize); - break; - } - *size += typeSize; - (*buffer) += typeSize; - return HasReturnvaluesIF::RETURN_OK; - } else { - return SerializeIF::BUFFER_TOO_SHORT; - } -} - - -Type PoolRawAccess::getType() { - return type; -} - -size_t PoolRawAccess::getSizeOfType() { - return typeSize; -} - -size_t PoolRawAccess::getArraySize(){ - return arraySize; -} - -uint32_t PoolRawAccess::getDataPoolId() const { - return dataPoolId; -} - -PoolVariableIF::ReadWriteMode_t PoolRawAccess::getReadWriteMode() const { - return readWriteMode; -} - -ReturnValue_t PoolRawAccess::setEntryFromBigEndian(const uint8_t *buffer, - size_t setSize) { - if (typeSize == setSize) { - EndianConverter::convertBigEndian(value, buffer, typeSize); - return HasReturnvaluesIF::RETURN_OK; - } else { - sif::error << "PoolRawAccess::setEntryFromBigEndian: Illegal sizes: " - "Internal" << (uint32_t) typeSize << ", Requested: " << setSize - << std::endl; - return INCORRECT_SIZE; - } -} - -bool PoolRawAccess::isValid() const { - if (valid != INVALID) - return true; - else - return false; -} - -void PoolRawAccess::setValid(bool valid) { - this->valid = valid; -} - -size_t PoolRawAccess::getSizeTillEnd() const { - return sizeTillEnd; -} - - -size_t PoolRawAccess::getSerializedSize() const { - return typeSize; -} - -ReturnValue_t PoolRawAccess::deSerialize(const uint8_t **buffer, size_t *size, - Endianness streamEndianness) { - - if (*size >= typeSize) { - switch(streamEndianness) { - case(Endianness::BIG): - EndianConverter::convertBigEndian(value, *buffer, typeSize); - break; - case(Endianness::LITTLE): - EndianConverter::convertLittleEndian(value, *buffer, typeSize); - break; - case(Endianness::MACHINE): - default: - memcpy(value, *buffer, typeSize); - break; - } - *size -= typeSize; - *buffer += typeSize; - return HasReturnvaluesIF::RETURN_OK; - } - else { - return SerializeIF::STREAM_TOO_SHORT; - } -} +#include "../datapoolglob/GlobalDataPool.h" +#include "../datapoolglob/PoolRawAccess.h" +#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../serialize/EndianConverter.h" + +#include + +PoolRawAccess::PoolRawAccess(uint32_t set_id, uint8_t setArrayEntry, + DataSetIF* dataSet, ReadWriteMode_t setReadWriteMode) : + dataPoolId(set_id), arrayEntry(setArrayEntry), valid(false), + type(Type::UNKNOWN_TYPE), typeSize(0), arraySize(0), sizeTillEnd(0), + readWriteMode(setReadWriteMode) { + memset(value, 0, sizeof(value)); + if (dataSet != nullptr) { + dataSet->registerVariable(this); + } +} + +PoolRawAccess::~PoolRawAccess() {} + +ReturnValue_t PoolRawAccess::read(uint32_t lockTimeout) { + ReturnValue_t result = glob::dataPool.lockDataPool(lockTimeout); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = readWithoutLock(); + ReturnValue_t unlockResult = glob::dataPool.unlockDataPool(); + if(unlockResult != HasReturnvaluesIF::RETURN_OK) { + sif::error << "GlobPoolVar::read: Could not unlock global data pool" + << std::endl; + } + return result; +} + +ReturnValue_t PoolRawAccess::readWithoutLock() { + ReturnValue_t result = RETURN_FAILED; + PoolEntryIF* readOut = glob::dataPool.getRawData(dataPoolId); + if (readOut != nullptr) { + result = handleReadOut(readOut); + if(result == RETURN_OK) { + return result; + } + } else { + result = READ_ENTRY_NON_EXISTENT; + } + handleReadError(result); + return result; +} + +ReturnValue_t PoolRawAccess::handleReadOut(PoolEntryIF* readOut) { + ReturnValue_t result = RETURN_FAILED; + valid = readOut->getValid(); + if (readOut->getSize() > arrayEntry) { + arraySize = readOut->getSize(); + typeSize = readOut->getByteSize() / readOut->getSize(); + type = readOut->getType(); + if (typeSize <= sizeof(value)) { + uint16_t arrayPosition = arrayEntry * typeSize; + sizeTillEnd = readOut->getByteSize() - arrayPosition; + uint8_t* ptr = &((uint8_t*) readOut->getRawData())[arrayPosition]; + memcpy(value, ptr, typeSize); + return RETURN_OK; + } else { + result = READ_TYPE_TOO_LARGE; + } + } else { + //debug << "PoolRawAccess: Size: " << (int)read_out->getSize() << std::endl; + result = READ_INDEX_TOO_LARGE; + } + return result; +} + +void PoolRawAccess::handleReadError(ReturnValue_t result) { + sif::error << "PoolRawAccess: read of DP Variable 0x" << std::hex << dataPoolId + << std::dec << " failed, "; + if(result == READ_TYPE_TOO_LARGE) { + sif::error << "type too large." << std::endl; + } + else if(result == READ_INDEX_TOO_LARGE) { + sif::error << "index too large." << std::endl; + } + else if(result == READ_ENTRY_NON_EXISTENT) { + sif::error << "entry does not exist." << std::endl; + } + + valid = INVALID; + typeSize = 0; + sizeTillEnd = 0; + memset(value, 0, sizeof(value)); +} + +ReturnValue_t PoolRawAccess::commit(uint32_t lockTimeout) { + ReturnValue_t result = glob::dataPool.lockDataPool(lockTimeout); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = commitWithoutLock(); + ReturnValue_t unlockResult = glob::dataPool.unlockDataPool(); + if(unlockResult != HasReturnvaluesIF::RETURN_OK) { + sif::error << "GlobPoolVar::read: Could not unlock global data pool" + << std::endl; + } + return result; +} + +ReturnValue_t PoolRawAccess::commitWithoutLock() { + PoolEntryIF* write_back = glob::dataPool.getRawData(dataPoolId); + if ((write_back != NULL) && (readWriteMode != VAR_READ)) { + write_back->setValid(valid); + uint8_t array_position = arrayEntry * typeSize; + uint8_t* ptr = &((uint8_t*) write_back->getRawData())[array_position]; + memcpy(ptr, value, typeSize); + return HasReturnvaluesIF::RETURN_OK; + } else { + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +uint8_t* PoolRawAccess::getEntry() { + return value; +} + +ReturnValue_t PoolRawAccess::getEntryEndianSafe(uint8_t* buffer, + size_t* writtenBytes, size_t max_size) { + uint8_t* data_ptr = getEntry(); + // debug << "PoolRawAccess::getEntry: Array position: " << + // index * size_of_type << " Size of T: " << (int)size_of_type << + // " ByteSize: " << byte_size << " Position: " << *size << std::endl; + if (typeSize == 0) + return DATA_POOL_ACCESS_FAILED; + if (typeSize > max_size) + return INCORRECT_SIZE; + EndianConverter::convertBigEndian(buffer, data_ptr, typeSize); + *writtenBytes = typeSize; + return HasReturnvaluesIF::RETURN_OK; +} + + +ReturnValue_t PoolRawAccess::serialize(uint8_t** buffer, size_t* size, + size_t maxSize, Endianness streamEndianness) const { + if (typeSize + *size <= maxSize) { + switch(streamEndianness) { + case(Endianness::BIG): + EndianConverter::convertBigEndian(*buffer, value, typeSize); + break; + case(Endianness::LITTLE): + EndianConverter::convertLittleEndian(*buffer, value, typeSize); + break; + case(Endianness::MACHINE): + default: + memcpy(*buffer, value, typeSize); + break; + } + *size += typeSize; + (*buffer) += typeSize; + return HasReturnvaluesIF::RETURN_OK; + } else { + return SerializeIF::BUFFER_TOO_SHORT; + } +} + + +Type PoolRawAccess::getType() { + return type; +} + +size_t PoolRawAccess::getSizeOfType() { + return typeSize; +} + +size_t PoolRawAccess::getArraySize(){ + return arraySize; +} + +uint32_t PoolRawAccess::getDataPoolId() const { + return dataPoolId; +} + +PoolVariableIF::ReadWriteMode_t PoolRawAccess::getReadWriteMode() const { + return readWriteMode; +} + +ReturnValue_t PoolRawAccess::setEntryFromBigEndian(const uint8_t *buffer, + size_t setSize) { + if (typeSize == setSize) { + EndianConverter::convertBigEndian(value, buffer, typeSize); + return HasReturnvaluesIF::RETURN_OK; + } else { + sif::error << "PoolRawAccess::setEntryFromBigEndian: Illegal sizes: " + "Internal" << (uint32_t) typeSize << ", Requested: " << setSize + << std::endl; + return INCORRECT_SIZE; + } +} + +bool PoolRawAccess::isValid() const { + if (valid != INVALID) + return true; + else + return false; +} + +void PoolRawAccess::setValid(bool valid) { + this->valid = valid; +} + +size_t PoolRawAccess::getSizeTillEnd() const { + return sizeTillEnd; +} + + +size_t PoolRawAccess::getSerializedSize() const { + return typeSize; +} + +ReturnValue_t PoolRawAccess::deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) { + + if (*size >= typeSize) { + switch(streamEndianness) { + case(Endianness::BIG): + EndianConverter::convertBigEndian(value, *buffer, typeSize); + break; + case(Endianness::LITTLE): + EndianConverter::convertLittleEndian(value, *buffer, typeSize); + break; + case(Endianness::MACHINE): + default: + memcpy(value, *buffer, typeSize); + break; + } + *size -= typeSize; + *buffer += typeSize; + return HasReturnvaluesIF::RETURN_OK; + } + else { + return SerializeIF::STREAM_TOO_SHORT; + } +} diff --git a/datapoolglob/PoolRawAccess.h b/datapoolglob/PoolRawAccess.h index 22dc312d..a1bed466 100644 --- a/datapoolglob/PoolRawAccess.h +++ b/datapoolglob/PoolRawAccess.h @@ -1,220 +1,220 @@ -#ifndef POOLRAWACCESS_H_ -#define POOLRAWACCESS_H_ - -#include -#include -#include -#include - -/** - * @brief This class allows accessing Data Pool variables as raw bytes. - * @details - * This is necessary to have an access method for HK data, as the PID's alone - * do not provide type information. Please note that the the raw pool access - * read() and commit() calls are not thread-safe. - * - * Please supply a data set and use the data set read(), commit() calls for - * thread-safe data pool access. - * @ingroup data_pool - */ -class PoolRawAccess: public PoolVariableIF, HasReturnvaluesIF { -public: - /** - * This constructor is used to access a data pool entry with a - * given ID if the target type is not known. A DataSet object is supplied - * and the data pool entry with the given ID is registered to that data set. - * Please note that a pool raw access buffer only has a buffer - * with a size of double. As such, for vector entries which have - * @param data_pool_id Target data pool entry ID - * @param arrayEntry - * @param data_set Dataset to register data pool entry to - * @param setReadWriteMode - * @param registerVectors If set to true, the constructor checks if - * there are multiple vector entries to registers - * and registers all of them recursively into the data_set - * - */ - PoolRawAccess(uint32_t data_pool_id, uint8_t arrayEntry, - DataSetIF* data_set, ReadWriteMode_t setReadWriteMode = - PoolVariableIF::VAR_READ); - - /** - * @brief This operation returns a pointer to the entry fetched. - * @details Return pointer to the buffer containing the raw data - * Size and number of data can be retrieved by other means. - */ - uint8_t* getEntry(); - /** - * @brief This operation returns the fetched entry from the data pool and - * flips the bytes, if necessary. - * @details It makes use of the getEntry call of this function, but additionally flips the - * bytes to big endian, which is the default for external communication (as House- - * keeping telemetry). To achieve this, the data is copied directly to the passed - * buffer, if it fits in the given max_size. - * @param buffer A pointer to a buffer to write to - * @param writtenBytes The number of bytes written is returned with this value. - * @param max_size The maximum size that the function may write to buffer. - * @return - @c RETURN_OK if entry could be acquired - * - @c RETURN_FAILED else. - */ - ReturnValue_t getEntryEndianSafe(uint8_t *buffer, size_t *size, - size_t maxSize); - - /** - * @brief Serialize raw pool entry into provided buffer directly - * @param buffer Provided buffer. Raw pool data will be copied here - * @param size [out] Increment provided size value by serialized size - * @param max_size Maximum allowed serialization size - * @param bigEndian Specify endianess - * @return - @c RETURN_OK if serialization was successfull - * - @c SerializeIF::BUFFER_TOO_SHORT if range check failed - */ - ReturnValue_t serialize(uint8_t **buffer, size_t *size, - size_t maxSize, Endianness streamEndianness) const override; - - size_t getSerializedSize() const override; - - ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, - Endianness streamEndianness) override; - - /** - * With this method, the content can be set from a big endian buffer safely. - * @param buffer Pointer to the data to set - * @param size Size of the data to write. Must fit this->size. - * @return - @c RETURN_OK on success - * - @c RETURN_FAILED on failure - */ - ReturnValue_t setEntryFromBigEndian(const uint8_t* buffer, - size_t setSize); - /** - * @brief This operation returns the type of the entry currently stored. - */ - Type getType(); - /** - * @brief This operation returns the size of the entry currently stored. - */ - size_t getSizeOfType(); - /** - * - * @return the size of the datapool array - */ - size_t getArraySize(); - /** - * @brief This operation returns the data pool id of the variable. - */ - uint32_t getDataPoolId() const; - - static const uint8_t INTERFACE_ID = CLASS_ID::POOL_RAW_ACCESS_CLASS; - static const ReturnValue_t INCORRECT_SIZE = MAKE_RETURN_CODE(0x01); - static const ReturnValue_t DATA_POOL_ACCESS_FAILED = MAKE_RETURN_CODE(0x02); - static const ReturnValue_t READ_TYPE_TOO_LARGE = MAKE_RETURN_CODE(0x03); - static const ReturnValue_t READ_INDEX_TOO_LARGE = MAKE_RETURN_CODE(0x04); - static const ReturnValue_t READ_ENTRY_NON_EXISTENT = MAKE_RETURN_CODE(0x05); - static const uint8_t RAW_MAX_SIZE = sizeof(double); - uint8_t value[RAW_MAX_SIZE]; - - - /** - * @brief The classes destructor is empty. If commit() was not called, the local value is - * discarded and not written back to the data pool. - */ - ~PoolRawAccess(); - - /** - * This method returns if the variable is read-write or read-only. - */ - ReadWriteMode_t getReadWriteMode() const; - /** - * @brief With this call, the valid information of the variable is returned. - */ - bool isValid() const; - - void setValid(bool valid); - /** - * Getter for the remaining size. - */ - size_t getSizeTillEnd() const; - - /** - * @brief This is a call to read the value from the global data pool. - * @details - * When executed, this operation tries to fetch the pool entry with matching - * data pool id from the global data pool and copies the value and the valid - * information to its local attributes. In case of a failure (wrong type or - * pool id not found), the variable is set to zero and invalid. - * The call is protected by a lock of the global data pool. - * @return -@c RETURN_OK Read successfull - * -@c READ_TYPE_TOO_LARGE - * -@c READ_INDEX_TOO_LARGE - * -@c READ_ENTRY_NON_EXISTENT - */ - ReturnValue_t read(uint32_t lockTimeout = MutexIF::BLOCKING) override; - /** - * @brief The commit call writes back the variable's value to the data pool. - * @details - * It checks type and size, as well as if the variable is writable. If so, - * the value is copied and the valid flag is automatically set to "valid". - * The call is protected by a lock of the global data pool. - * - */ - ReturnValue_t commit(uint32_t lockTimeout = MutexIF::BLOCKING) override; - -protected: - /** - * @brief Like #read, but without a lock protection of the global pool. - * @details - * The operation does NOT provide any mutual exclusive protection by itself. - * This can be used if the lock is handled externally to avoid the overhead - * of consecutive lock und unlock operations. - * Declared protected to discourage free public usage. - */ - ReturnValue_t readWithoutLock() override; - /** - * @brief Like #commit, but without a lock protection of the global pool. - * @details - * The operation does NOT provide any mutual exclusive protection by itself. - * This can be used if the lock is handled externally to avoid the overhead - * of consecutive lock und unlock operations. - * Declared protected to discourage free public usage. - */ - ReturnValue_t commitWithoutLock() override; - - ReturnValue_t handleReadOut(PoolEntryIF* read_out); - void handleReadError(ReturnValue_t result); -private: - /** - * @brief To access the correct data pool entry on read and commit calls, the data pool id - * is stored. - */ - uint32_t dataPoolId; - /** - * @brief The array entry that is fetched from the data pool. - */ - uint8_t arrayEntry; - /** - * @brief The valid information as it was stored in the data pool is copied to this attribute. - */ - uint8_t valid; - /** - * @brief This value contains the type of the data pool entry. - */ - Type type; - /** - * @brief This value contains the size of the data pool entry type in bytes. - */ - size_t typeSize; - /** - * The size of the DP array (single values return 1) - */ - size_t arraySize; - /** - * The size (in bytes) from the selected entry till the end of this DataPool variable. - */ - size_t sizeTillEnd; - /** - * @brief The information whether the class is read-write or read-only is stored here. - */ - ReadWriteMode_t readWriteMode; -}; - -#endif /* POOLRAWACCESS_H_ */ +#ifndef POOLRAWACCESS_H_ +#define POOLRAWACCESS_H_ + +#include "../datapool/DataSetIF.h" +#include "../datapool/PoolEntryIF.h" +#include "../datapool/PoolVariableIF.h" +#include "../globalfunctions/Type.h" + +/** + * @brief This class allows accessing Data Pool variables as raw bytes. + * @details + * This is necessary to have an access method for HK data, as the PID's alone + * do not provide type information. Please note that the the raw pool access + * read() and commit() calls are not thread-safe. + * + * Please supply a data set and use the data set read(), commit() calls for + * thread-safe data pool access. + * @ingroup data_pool + */ +class PoolRawAccess: public PoolVariableIF, HasReturnvaluesIF { +public: + /** + * This constructor is used to access a data pool entry with a + * given ID if the target type is not known. A DataSet object is supplied + * and the data pool entry with the given ID is registered to that data set. + * Please note that a pool raw access buffer only has a buffer + * with a size of double. As such, for vector entries which have + * @param data_pool_id Target data pool entry ID + * @param arrayEntry + * @param data_set Dataset to register data pool entry to + * @param setReadWriteMode + * @param registerVectors If set to true, the constructor checks if + * there are multiple vector entries to registers + * and registers all of them recursively into the data_set + * + */ + PoolRawAccess(uint32_t data_pool_id, uint8_t arrayEntry, + DataSetIF* data_set, ReadWriteMode_t setReadWriteMode = + PoolVariableIF::VAR_READ); + + /** + * @brief This operation returns a pointer to the entry fetched. + * @details Return pointer to the buffer containing the raw data + * Size and number of data can be retrieved by other means. + */ + uint8_t* getEntry(); + /** + * @brief This operation returns the fetched entry from the data pool and + * flips the bytes, if necessary. + * @details It makes use of the getEntry call of this function, but additionally flips the + * bytes to big endian, which is the default for external communication (as House- + * keeping telemetry). To achieve this, the data is copied directly to the passed + * buffer, if it fits in the given max_size. + * @param buffer A pointer to a buffer to write to + * @param writtenBytes The number of bytes written is returned with this value. + * @param max_size The maximum size that the function may write to buffer. + * @return - @c RETURN_OK if entry could be acquired + * - @c RETURN_FAILED else. + */ + ReturnValue_t getEntryEndianSafe(uint8_t *buffer, size_t *size, + size_t maxSize); + + /** + * @brief Serialize raw pool entry into provided buffer directly + * @param buffer Provided buffer. Raw pool data will be copied here + * @param size [out] Increment provided size value by serialized size + * @param max_size Maximum allowed serialization size + * @param bigEndian Specify endianess + * @return - @c RETURN_OK if serialization was successfull + * - @c SerializeIF::BUFFER_TOO_SHORT if range check failed + */ + ReturnValue_t serialize(uint8_t **buffer, size_t *size, + size_t maxSize, Endianness streamEndianness) const override; + + size_t getSerializedSize() const override; + + ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) override; + + /** + * With this method, the content can be set from a big endian buffer safely. + * @param buffer Pointer to the data to set + * @param size Size of the data to write. Must fit this->size. + * @return - @c RETURN_OK on success + * - @c RETURN_FAILED on failure + */ + ReturnValue_t setEntryFromBigEndian(const uint8_t* buffer, + size_t setSize); + /** + * @brief This operation returns the type of the entry currently stored. + */ + Type getType(); + /** + * @brief This operation returns the size of the entry currently stored. + */ + size_t getSizeOfType(); + /** + * + * @return the size of the datapool array + */ + size_t getArraySize(); + /** + * @brief This operation returns the data pool id of the variable. + */ + uint32_t getDataPoolId() const; + + static const uint8_t INTERFACE_ID = CLASS_ID::POOL_RAW_ACCESS_CLASS; + static const ReturnValue_t INCORRECT_SIZE = MAKE_RETURN_CODE(0x01); + static const ReturnValue_t DATA_POOL_ACCESS_FAILED = MAKE_RETURN_CODE(0x02); + static const ReturnValue_t READ_TYPE_TOO_LARGE = MAKE_RETURN_CODE(0x03); + static const ReturnValue_t READ_INDEX_TOO_LARGE = MAKE_RETURN_CODE(0x04); + static const ReturnValue_t READ_ENTRY_NON_EXISTENT = MAKE_RETURN_CODE(0x05); + static const uint8_t RAW_MAX_SIZE = sizeof(double); + uint8_t value[RAW_MAX_SIZE]; + + + /** + * @brief The classes destructor is empty. If commit() was not called, the local value is + * discarded and not written back to the data pool. + */ + ~PoolRawAccess(); + + /** + * This method returns if the variable is read-write or read-only. + */ + ReadWriteMode_t getReadWriteMode() const; + /** + * @brief With this call, the valid information of the variable is returned. + */ + bool isValid() const; + + void setValid(bool valid); + /** + * Getter for the remaining size. + */ + size_t getSizeTillEnd() const; + + /** + * @brief This is a call to read the value from the global data pool. + * @details + * When executed, this operation tries to fetch the pool entry with matching + * data pool id from the global data pool and copies the value and the valid + * information to its local attributes. In case of a failure (wrong type or + * pool id not found), the variable is set to zero and invalid. + * The call is protected by a lock of the global data pool. + * @return -@c RETURN_OK Read successfull + * -@c READ_TYPE_TOO_LARGE + * -@c READ_INDEX_TOO_LARGE + * -@c READ_ENTRY_NON_EXISTENT + */ + ReturnValue_t read(uint32_t lockTimeout = MutexIF::BLOCKING) override; + /** + * @brief The commit call writes back the variable's value to the data pool. + * @details + * It checks type and size, as well as if the variable is writable. If so, + * the value is copied and the valid flag is automatically set to "valid". + * The call is protected by a lock of the global data pool. + * + */ + ReturnValue_t commit(uint32_t lockTimeout = MutexIF::BLOCKING) override; + +protected: + /** + * @brief Like #read, but without a lock protection of the global pool. + * @details + * The operation does NOT provide any mutual exclusive protection by itself. + * This can be used if the lock is handled externally to avoid the overhead + * of consecutive lock und unlock operations. + * Declared protected to discourage free public usage. + */ + ReturnValue_t readWithoutLock() override; + /** + * @brief Like #commit, but without a lock protection of the global pool. + * @details + * The operation does NOT provide any mutual exclusive protection by itself. + * This can be used if the lock is handled externally to avoid the overhead + * of consecutive lock und unlock operations. + * Declared protected to discourage free public usage. + */ + ReturnValue_t commitWithoutLock() override; + + ReturnValue_t handleReadOut(PoolEntryIF* read_out); + void handleReadError(ReturnValue_t result); +private: + /** + * @brief To access the correct data pool entry on read and commit calls, the data pool id + * is stored. + */ + uint32_t dataPoolId; + /** + * @brief The array entry that is fetched from the data pool. + */ + uint8_t arrayEntry; + /** + * @brief The valid information as it was stored in the data pool is copied to this attribute. + */ + uint8_t valid; + /** + * @brief This value contains the type of the data pool entry. + */ + Type type; + /** + * @brief This value contains the size of the data pool entry type in bytes. + */ + size_t typeSize; + /** + * The size of the DP array (single values return 1) + */ + size_t arraySize; + /** + * The size (in bytes) from the selected entry till the end of this DataPool variable. + */ + size_t sizeTillEnd; + /** + * @brief The information whether the class is read-write or read-only is stored here. + */ + ReadWriteMode_t readWriteMode; +}; + +#endif /* POOLRAWACCESS_H_ */ diff --git a/datapoollocal/HasLocalDataPoolIF.h b/datapoollocal/HasLocalDataPoolIF.h index 0095f894..8703233c 100644 --- a/datapoollocal/HasLocalDataPoolIF.h +++ b/datapoollocal/HasLocalDataPoolIF.h @@ -1,77 +1,77 @@ -#ifndef FRAMEWORK_DATAPOOL_HASHKPOOLPARAMETERSIF_H_ -#define FRAMEWORK_DATAPOOL_HASHKPOOLPARAMETERSIF_H_ -#include -#include -#include -#include - -class LocalDataPoolManager; -class DataSetIF; -/** - * @brief Type definition for local pool entries. - */ -using lp_id_t = uint32_t; -using LocalDataPool = std::map; -using LocalDataPoolMapIter = LocalDataPool::iterator; - -/** - * @brief This interface is implemented by classes which posses a local - * data pool (not the managing class). It defines the relationship - * between the local data pool owner and the LocalDataPoolManager. - * @details - * Any class implementing this interface shall also have a LocalDataPoolManager - * member class which contains the actual pool data structure - * and exposes the public interface for it. - * This is required because the pool entries are templates, which makes - * specifying an interface rather difficult. The local data pool can be - * accessed by using the LocalPoolVariable, LocalPoolVector or LocalDataSet - * classes. - * - * Architectural Note: - * This could be circumvented by using a wrapper/accessor function or - * implementing the templated function in this interface.. - * The first solution sounds better than the second but - * the LocalPoolVariable classes are templates as well, so this just shifts - * the problem somewhere else. Interfaces are nice, but the most - * pragmatic solution I found was to offer the client the full interface - * of the LocalDataPoolManager. - */ -class HasLocalDataPoolIF { -public: - virtual~ HasLocalDataPoolIF() {}; - - static constexpr uint8_t INTERFACE_ID = CLASS_ID::LOCAL_POOL_OWNER_IF; - - /** Command queue for housekeeping messages. */ - virtual MessageQueueId_t getCommandQueue() const = 0; - - /** Is used by pool owner to initialize the pool map once */ - virtual ReturnValue_t initializePoolEntries( - LocalDataPool& localDataPoolMap) = 0; - - /** Can be used to get a handle to the local data pool manager. */ - virtual LocalDataPoolManager* getHkManagerHandle() = 0; - - /** - * This function is used by the pool manager to get a valid dataset - * from a SID - * @param sid Corresponding structure ID - * @return - */ - virtual DataSetIF* getDataSetHandle(sid_t sid) = 0; - - /* These function can be implemented by pool owner, as they are required - * by the housekeeping message interface */ - virtual ReturnValue_t addDataSet(sid_t sid) { - return HasReturnvaluesIF::RETURN_FAILED; - }; - virtual ReturnValue_t removeDataSet(sid_t sid) { - return HasReturnvaluesIF::RETURN_FAILED; - }; - virtual ReturnValue_t changeCollectionInterval(sid_t sid, - dur_seconds_t newInterval) { - return HasReturnvaluesIF::RETURN_FAILED; - }; -}; - -#endif /* FRAMEWORK_DATAPOOL_HASHKPOOLPARAMETERSIF_H_ */ +#ifndef FRAMEWORK_DATAPOOL_HASHKPOOLPARAMETERSIF_H_ +#define FRAMEWORK_DATAPOOL_HASHKPOOLPARAMETERSIF_H_ +#include "../datapool/PoolEntryIF.h" +#include "../ipc/MessageQueueSenderIF.h" +#include "../housekeeping/HousekeepingMessage.h" +#include + +class LocalDataPoolManager; +class DataSetIF; +/** + * @brief Type definition for local pool entries. + */ +using lp_id_t = uint32_t; +using LocalDataPool = std::map; +using LocalDataPoolMapIter = LocalDataPool::iterator; + +/** + * @brief This interface is implemented by classes which posses a local + * data pool (not the managing class). It defines the relationship + * between the local data pool owner and the LocalDataPoolManager. + * @details + * Any class implementing this interface shall also have a LocalDataPoolManager + * member class which contains the actual pool data structure + * and exposes the public interface for it. + * This is required because the pool entries are templates, which makes + * specifying an interface rather difficult. The local data pool can be + * accessed by using the LocalPoolVariable, LocalPoolVector or LocalDataSet + * classes. + * + * Architectural Note: + * This could be circumvented by using a wrapper/accessor function or + * implementing the templated function in this interface.. + * The first solution sounds better than the second but + * the LocalPoolVariable classes are templates as well, so this just shifts + * the problem somewhere else. Interfaces are nice, but the most + * pragmatic solution I found was to offer the client the full interface + * of the LocalDataPoolManager. + */ +class HasLocalDataPoolIF { +public: + virtual~ HasLocalDataPoolIF() {}; + + static constexpr uint8_t INTERFACE_ID = CLASS_ID::LOCAL_POOL_OWNER_IF; + + /** Command queue for housekeeping messages. */ + virtual MessageQueueId_t getCommandQueue() const = 0; + + /** Is used by pool owner to initialize the pool map once */ + virtual ReturnValue_t initializePoolEntries( + LocalDataPool& localDataPoolMap) = 0; + + /** Can be used to get a handle to the local data pool manager. */ + virtual LocalDataPoolManager* getHkManagerHandle() = 0; + + /** + * This function is used by the pool manager to get a valid dataset + * from a SID + * @param sid Corresponding structure ID + * @return + */ + virtual DataSetIF* getDataSetHandle(sid_t sid) = 0; + + /* These function can be implemented by pool owner, as they are required + * by the housekeeping message interface */ + virtual ReturnValue_t addDataSet(sid_t sid) { + return HasReturnvaluesIF::RETURN_FAILED; + }; + virtual ReturnValue_t removeDataSet(sid_t sid) { + return HasReturnvaluesIF::RETURN_FAILED; + }; + virtual ReturnValue_t changeCollectionInterval(sid_t sid, + dur_seconds_t newInterval) { + return HasReturnvaluesIF::RETURN_FAILED; + }; +}; + +#endif /* FRAMEWORK_DATAPOOL_HASHKPOOLPARAMETERSIF_H_ */ diff --git a/datapoollocal/LocalDataPoolManager.cpp b/datapoollocal/LocalDataPoolManager.cpp index 02016abf..434dd6ae 100644 --- a/datapoollocal/LocalDataPoolManager.cpp +++ b/datapoollocal/LocalDataPoolManager.cpp @@ -1,218 +1,218 @@ -#include -#include -#include -#include -#include -#include - -#include - -LocalDataPoolManager::LocalDataPoolManager(HasLocalDataPoolIF* owner, - MessageQueueIF* queueToUse, bool appendValidityBuffer): - appendValidityBuffer(appendValidityBuffer) { - if(owner == nullptr) { - sif::error << "HkManager: Invalid supplied owner!" << std::endl; - return; - } - this->owner = owner; - mutex = MutexFactory::instance()->createMutex(); - if(mutex == nullptr) { - sif::error << "LocalDataPoolManager::LocalDataPoolManager: " - "Could not create mutex." << std::endl; - } - ipcStore = objectManager->get(objects::IPC_STORE); - if(ipcStore == nullptr) { - sif::error << "LocalDataPoolManager::LocalDataPoolManager: " - "Could not set IPC store." << std::endl; - } - hkQueue = queueToUse; -} - -ReturnValue_t LocalDataPoolManager::initialize(MessageQueueIF* queueToUse, - object_id_t hkDestination) { - if(queueToUse == nullptr) { - sif::error << "LocalDataPoolManager::initialize: Supplied queue " - "invalid!" << std::endl; - } - hkQueue = queueToUse; - - if(hkDestination == objects::NO_OBJECT) { - return initializeHousekeepingPoolEntriesOnce(); - } - - AcceptsHkPacketsIF* hkReceiver = - objectManager->get(hkDestination); - if(hkReceiver != nullptr) { - setHkPacketDestination(hkReceiver->getHkQueue()); - } - else { - sif::warning << "LocalDataPoolManager::initialize: Could not retrieve" - " queue ID from HK destination object ID. " << std::flush; - sif::warning << "Make sure it exists and the object impements " - "AcceptsHkPacketsIF!" << std::endl; - } - return initializeHousekeepingPoolEntriesOnce(); -} - -void LocalDataPoolManager::setHkPacketDestination( - MessageQueueId_t hkDestination) { - this->hkDestination = hkDestination; -} - -LocalDataPoolManager::~LocalDataPoolManager() {} - -ReturnValue_t LocalDataPoolManager::initializeHousekeepingPoolEntriesOnce() { - if(not mapInitialized) { - ReturnValue_t result = owner->initializePoolEntries(localPoolMap); - if(result == HasReturnvaluesIF::RETURN_OK) { - mapInitialized = true; - } - return result; - } - sif::warning << "HousekeepingManager: The map should only be initialized " - "once!" << std::endl; - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t LocalDataPoolManager::handleHousekeepingMessage( - CommandMessage* message) { - Command_t command = message->getCommand(); - switch(command) { - // I think those are the only commands which can be handled here.. - case(HousekeepingMessage::ADD_HK_REPORT_STRUCT): - case(HousekeepingMessage::ADD_DIAGNOSTICS_REPORT_STRUCT): - // We should use OwnsLocalPoolDataIF to specify those functions.. - return HasReturnvaluesIF::RETURN_OK; - case(HousekeepingMessage::REPORT_DIAGNOSTICS_REPORT_STRUCTURES): - case(HousekeepingMessage::REPORT_HK_REPORT_STRUCTURES): - //return generateSetStructurePacket(message->getSid()); - case(HousekeepingMessage::GENERATE_ONE_PARAMETER_REPORT): - case(HousekeepingMessage::GENERATE_ONE_DIAGNOSTICS_REPORT): - //return generateHousekeepingPacket(message->getSid()); - default: - return CommandMessageIF::UNKNOWN_COMMAND; - } -} - -ReturnValue_t LocalDataPoolManager::printPoolEntry( - lp_id_t localPoolId) { - auto poolIter = localPoolMap.find(localPoolId); - if (poolIter == localPoolMap.end()) { - sif::debug << "HousekeepingManager::fechPoolEntry:" - " Pool entry not found." << std::endl; - return POOL_ENTRY_NOT_FOUND; - } - poolIter->second->print(); - return HasReturnvaluesIF::RETURN_OK; -} - -MutexIF* LocalDataPoolManager::getMutexHandle() { - return mutex; -} - -const HasLocalDataPoolIF* LocalDataPoolManager::getOwner() const { - return owner; -} - -ReturnValue_t LocalDataPoolManager::generateHousekeepingPacket(sid_t sid, - MessageQueueId_t sendTo) { - LocalDataSet* dataSetToSerialize = dynamic_cast( - owner->getDataSetHandle(sid)); - if(dataSetToSerialize == nullptr) { - sif::warning << "HousekeepingManager::generateHousekeepingPacket:" - " Set ID not found" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - store_address_t storeId; - ReturnValue_t result = serializeHkPacketIntoStore(&storeId, - dataSetToSerialize); - if(result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - // and now we set a HK message and send it the HK packet destination. - CommandMessage hkMessage; - HousekeepingMessage::setHkReportMessage(&hkMessage, sid, storeId); - if(hkQueue == nullptr) { - return QUEUE_OR_DESTINATION_NOT_SET; - } - - if(sendTo != MessageQueueIF::NO_QUEUE) { - result = hkQueue->sendMessage(sendTo, &hkMessage); - } - else { - if(hkDestination == MessageQueueIF::NO_QUEUE) { - sif::warning << "LocalDataPoolManager::generateHousekeepingPacket:" - " Destination is not set properly!" << std::endl; - return QUEUE_OR_DESTINATION_NOT_SET; - } - else { - result = hkQueue->sendMessage(hkDestination, &hkMessage); - } - } - - return result; -} - -ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid) { - LocalDataSet* dataSet = dynamic_cast( - owner->getDataSetHandle(sid)); - if(dataSet == nullptr) { - sif::warning << "HousekeepingManager::generateHousekeepingPacket:" - " Set ID not found" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - size_t expectedSize = dataSet->getFillCount() * sizeof(lp_id_t); - uint8_t* storePtr = nullptr; - store_address_t storeId; - ReturnValue_t result = ipcStore->getFreeElement(&storeId, - expectedSize,&storePtr); - if(result != HasReturnvaluesIF::RETURN_OK) { - sif::error << "HousekeepingManager::generateHousekeepingPacket: " - "Could not get free element from IPC store." << std::endl; - return result; - } - size_t size = 0; - result = dataSet->serializeLocalPoolIds(&storePtr, &size, - expectedSize, SerializeIF::Endianness::BIG); - if(expectedSize != size) { - sif::error << "HousekeepingManager::generateSetStructurePacket: " - "Expected size is not equal to serialized size" << std::endl; - } - return result; -} - -void LocalDataPoolManager::setMinimalSamplingFrequency(float frequencySeconds) { -} - -ReturnValue_t LocalDataPoolManager::serializeHkPacketIntoStore( - store_address_t *storeId, LocalDataSet* dataSet) { - size_t hkSize = dataSet->getSerializedSize(); - uint8_t* storePtr = nullptr; - ReturnValue_t result = ipcStore->getFreeElement(storeId, hkSize,&storePtr); - if(result != HasReturnvaluesIF::RETURN_OK) { - sif::error << "HousekeepingManager::generateHousekeepingPacket: " - "Could not get free element from IPC store." << std::endl; - return result; - } - size_t size = 0; - - if(appendValidityBuffer) { - result = dataSet->serializeWithValidityBuffer(&storePtr, - &size, hkSize, SerializeIF::Endianness::MACHINE); - } - else { - result = dataSet->serialize(&storePtr, &size, hkSize, - SerializeIF::Endianness::MACHINE); - } - - if(result != HasReturnvaluesIF::RETURN_OK) { - sif::error << "HousekeepingManager::serializeHkPacketIntoStore: " - "Serialization proccess failed!" << std::endl; - } - return result; -} - -ReturnValue_t LocalDataPoolManager::performHkOperation() { - return HasReturnvaluesIF::RETURN_OK; -} +#include "../datapoollocal/LocalDataPoolManager.h" +#include "../datapoollocal/LocalDataSet.h" +#include "../housekeeping/AcceptsHkPacketsIF.h" +#include "../ipc/MutexFactory.h" +#include "../ipc/MutexHelper.h" +#include "../ipc/QueueFactory.h" + +#include + +LocalDataPoolManager::LocalDataPoolManager(HasLocalDataPoolIF* owner, + MessageQueueIF* queueToUse, bool appendValidityBuffer): + appendValidityBuffer(appendValidityBuffer) { + if(owner == nullptr) { + sif::error << "HkManager: Invalid supplied owner!" << std::endl; + return; + } + this->owner = owner; + mutex = MutexFactory::instance()->createMutex(); + if(mutex == nullptr) { + sif::error << "LocalDataPoolManager::LocalDataPoolManager: " + "Could not create mutex." << std::endl; + } + ipcStore = objectManager->get(objects::IPC_STORE); + if(ipcStore == nullptr) { + sif::error << "LocalDataPoolManager::LocalDataPoolManager: " + "Could not set IPC store." << std::endl; + } + hkQueue = queueToUse; +} + +ReturnValue_t LocalDataPoolManager::initialize(MessageQueueIF* queueToUse, + object_id_t hkDestination) { + if(queueToUse == nullptr) { + sif::error << "LocalDataPoolManager::initialize: Supplied queue " + "invalid!" << std::endl; + } + hkQueue = queueToUse; + + if(hkDestination == objects::NO_OBJECT) { + return initializeHousekeepingPoolEntriesOnce(); + } + + AcceptsHkPacketsIF* hkReceiver = + objectManager->get(hkDestination); + if(hkReceiver != nullptr) { + setHkPacketDestination(hkReceiver->getHkQueue()); + } + else { + sif::warning << "LocalDataPoolManager::initialize: Could not retrieve" + " queue ID from HK destination object ID. " << std::flush; + sif::warning << "Make sure it exists and the object impements " + "AcceptsHkPacketsIF!" << std::endl; + } + return initializeHousekeepingPoolEntriesOnce(); +} + +void LocalDataPoolManager::setHkPacketDestination( + MessageQueueId_t hkDestination) { + this->hkDestination = hkDestination; +} + +LocalDataPoolManager::~LocalDataPoolManager() {} + +ReturnValue_t LocalDataPoolManager::initializeHousekeepingPoolEntriesOnce() { + if(not mapInitialized) { + ReturnValue_t result = owner->initializePoolEntries(localPoolMap); + if(result == HasReturnvaluesIF::RETURN_OK) { + mapInitialized = true; + } + return result; + } + sif::warning << "HousekeepingManager: The map should only be initialized " + "once!" << std::endl; + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t LocalDataPoolManager::handleHousekeepingMessage( + CommandMessage* message) { + Command_t command = message->getCommand(); + switch(command) { + // I think those are the only commands which can be handled here.. + case(HousekeepingMessage::ADD_HK_REPORT_STRUCT): + case(HousekeepingMessage::ADD_DIAGNOSTICS_REPORT_STRUCT): + // We should use OwnsLocalPoolDataIF to specify those functions.. + return HasReturnvaluesIF::RETURN_OK; + case(HousekeepingMessage::REPORT_DIAGNOSTICS_REPORT_STRUCTURES): + case(HousekeepingMessage::REPORT_HK_REPORT_STRUCTURES): + //return generateSetStructurePacket(message->getSid()); + case(HousekeepingMessage::GENERATE_ONE_PARAMETER_REPORT): + case(HousekeepingMessage::GENERATE_ONE_DIAGNOSTICS_REPORT): + //return generateHousekeepingPacket(message->getSid()); + default: + return CommandMessageIF::UNKNOWN_COMMAND; + } +} + +ReturnValue_t LocalDataPoolManager::printPoolEntry( + lp_id_t localPoolId) { + auto poolIter = localPoolMap.find(localPoolId); + if (poolIter == localPoolMap.end()) { + sif::debug << "HousekeepingManager::fechPoolEntry:" + " Pool entry not found." << std::endl; + return POOL_ENTRY_NOT_FOUND; + } + poolIter->second->print(); + return HasReturnvaluesIF::RETURN_OK; +} + +MutexIF* LocalDataPoolManager::getMutexHandle() { + return mutex; +} + +const HasLocalDataPoolIF* LocalDataPoolManager::getOwner() const { + return owner; +} + +ReturnValue_t LocalDataPoolManager::generateHousekeepingPacket(sid_t sid, + MessageQueueId_t sendTo) { + LocalDataSet* dataSetToSerialize = dynamic_cast( + owner->getDataSetHandle(sid)); + if(dataSetToSerialize == nullptr) { + sif::warning << "HousekeepingManager::generateHousekeepingPacket:" + " Set ID not found" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + store_address_t storeId; + ReturnValue_t result = serializeHkPacketIntoStore(&storeId, + dataSetToSerialize); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + // and now we set a HK message and send it the HK packet destination. + CommandMessage hkMessage; + HousekeepingMessage::setHkReportMessage(&hkMessage, sid, storeId); + if(hkQueue == nullptr) { + return QUEUE_OR_DESTINATION_NOT_SET; + } + + if(sendTo != MessageQueueIF::NO_QUEUE) { + result = hkQueue->sendMessage(sendTo, &hkMessage); + } + else { + if(hkDestination == MessageQueueIF::NO_QUEUE) { + sif::warning << "LocalDataPoolManager::generateHousekeepingPacket:" + " Destination is not set properly!" << std::endl; + return QUEUE_OR_DESTINATION_NOT_SET; + } + else { + result = hkQueue->sendMessage(hkDestination, &hkMessage); + } + } + + return result; +} + +ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid) { + LocalDataSet* dataSet = dynamic_cast( + owner->getDataSetHandle(sid)); + if(dataSet == nullptr) { + sif::warning << "HousekeepingManager::generateHousekeepingPacket:" + " Set ID not found" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + size_t expectedSize = dataSet->getFillCount() * sizeof(lp_id_t); + uint8_t* storePtr = nullptr; + store_address_t storeId; + ReturnValue_t result = ipcStore->getFreeElement(&storeId, + expectedSize,&storePtr); + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::error << "HousekeepingManager::generateHousekeepingPacket: " + "Could not get free element from IPC store." << std::endl; + return result; + } + size_t size = 0; + result = dataSet->serializeLocalPoolIds(&storePtr, &size, + expectedSize, SerializeIF::Endianness::BIG); + if(expectedSize != size) { + sif::error << "HousekeepingManager::generateSetStructurePacket: " + "Expected size is not equal to serialized size" << std::endl; + } + return result; +} + +void LocalDataPoolManager::setMinimalSamplingFrequency(float frequencySeconds) { +} + +ReturnValue_t LocalDataPoolManager::serializeHkPacketIntoStore( + store_address_t *storeId, LocalDataSet* dataSet) { + size_t hkSize = dataSet->getSerializedSize(); + uint8_t* storePtr = nullptr; + ReturnValue_t result = ipcStore->getFreeElement(storeId, hkSize,&storePtr); + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::error << "HousekeepingManager::generateHousekeepingPacket: " + "Could not get free element from IPC store." << std::endl; + return result; + } + size_t size = 0; + + if(appendValidityBuffer) { + result = dataSet->serializeWithValidityBuffer(&storePtr, + &size, hkSize, SerializeIF::Endianness::MACHINE); + } + else { + result = dataSet->serialize(&storePtr, &size, hkSize, + SerializeIF::Endianness::MACHINE); + } + + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::error << "HousekeepingManager::serializeHkPacketIntoStore: " + "Serialization proccess failed!" << std::endl; + } + return result; +} + +ReturnValue_t LocalDataPoolManager::performHkOperation() { + return HasReturnvaluesIF::RETURN_OK; +} diff --git a/datapoollocal/LocalDataPoolManager.h b/datapoollocal/LocalDataPoolManager.h index df7b9ff4..c5f8761f 100644 --- a/datapoollocal/LocalDataPoolManager.h +++ b/datapoollocal/LocalDataPoolManager.h @@ -1,229 +1,229 @@ -#ifndef FRAMEWORK_DATAPOOLLOCAL_LOCALDATAPOOLMANAGER_H_ -#define FRAMEWORK_DATAPOOLLOCAL_LOCALDATAPOOLMANAGER_H_ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -class LocalDataSet; - -/** - * @brief This class is the managing instance for local data pool. - * @details - * The actual data pool structure is a member of this class. Any class which - * has a local data pool shall have this class as a member and implement - * the HasLocalDataPoolIF. - * - * Users of the data pool use the helper classes LocalDataSet, - * LocalPoolVariable and LocalPoolVector to access pool entries in - * a thread-safe and efficient way. - * - * The local data pools employ a blackboard logic: Only the most recent - * value is stored. The helper classes offer a read() and commit() interface - * through the PoolVariableIF which is used to read and update values. - * Each pool entry has a valid state too. - * - */ -class LocalDataPoolManager { - template - friend class LocalPoolVar; - template - friend class LocalPoolVector; - friend class LocalDataSet; -public: - static constexpr uint8_t INTERFACE_ID = CLASS_ID::HOUSEKEEPING_MANAGER; - - static constexpr ReturnValue_t POOL_ENTRY_NOT_FOUND = MAKE_RETURN_CODE(0x0); - static constexpr ReturnValue_t POOL_ENTRY_TYPE_CONFLICT = MAKE_RETURN_CODE(0x1); - - static constexpr ReturnValue_t QUEUE_OR_DESTINATION_NOT_SET = MAKE_RETURN_CODE(0x2); - //static constexpr ReturnValue_t SET_NOT_FOUND = MAKE_RETURN_CODE(0x3); - - /** - * This constructor is used by a class which wants to implement - * a personal local data pool. The queueToUse can be supplied if it - * is already known. - * - * initialize() has to be called in any case before using the object! - * @param owner - * @param queueToUse - * @param appendValidityBuffer - */ - LocalDataPoolManager(HasLocalDataPoolIF* owner, MessageQueueIF* queueToUse, - bool appendValidityBuffer = true); - virtual~ LocalDataPoolManager(); - - /** - * Initializes the map by calling the map initialization function of the - * owner and assigns the queue to use. - * @param queueToUse - * @return - */ - ReturnValue_t initialize(MessageQueueIF* queueToUse, - object_id_t hkDestination); - - /** - * This should be called in the periodic handler of the owner. - * It performs all the periodic functionalities of the data pool manager. - * @return - */ - ReturnValue_t performHkOperation(); - /** - * This function is used to set the default HK packet destination. - * This destination will usually only be set once. - * @param hkDestination - */ - void setHkPacketDestination(MessageQueueId_t hkDestination); - - /** - * Generate a housekeeping packet with a given SID. - * @param sid - * @return - */ - ReturnValue_t generateHousekeepingPacket(sid_t sid, MessageQueueId_t sendTo - = MessageQueueIF::NO_QUEUE); - ReturnValue_t generateSetStructurePacket(sid_t sid); - - ReturnValue_t handleHousekeepingMessage(CommandMessage* message); - - /** - * This function is used to fill the local data pool map with pool - * entries. It should only be called once by the pool owner. - * @param localDataPoolMap - * @return - */ - ReturnValue_t initializeHousekeepingPoolEntriesOnce(); - - const HasLocalDataPoolIF* getOwner() const; - - ReturnValue_t printPoolEntry(lp_id_t localPoolId); - - /** - * Different types of housekeeping reporting are possible. - * 1. PERIODIC: HK packets are generated in fixed intervals - * 2. UPDATED: HK packets are generated if a value was updated - * 3. REQUESTED: HK packets are only generated if explicitely requested - */ - enum class ReportingType: uint8_t { - PERIODIC, - ON_UPDATE, - REQUESTED - }; - - /* Copying forbidden */ - LocalDataPoolManager(const LocalDataPoolManager &) = delete; - LocalDataPoolManager operator=(const LocalDataPoolManager&) = delete; - -private: - LocalDataPool localPoolMap; - /** Every housekeeping data manager has a mutex to protect access - * to it's data pool. */ - MutexIF* mutex = nullptr; - /** The class which actually owns the manager (and its datapool). */ - HasLocalDataPoolIF* owner = nullptr; - - /** - * The data pool manager will keep an internal map of HK receivers. - */ - struct HkReceiver { - LocalDataSet* dataSet = nullptr; - MessageQueueId_t destinationQueue = MessageQueueIF::NO_QUEUE; - ReportingType reportingType = ReportingType::PERIODIC; - bool reportingStatus = true; - /** Different members of this union will be used depending on reporting - * type */ - union hkParameter { - /** This parameter will be used for the PERIODIC type */ - dur_seconds_t collectionInterval = 0; - /** This parameter will be used for the ON_UPDATE type */ - bool hkDataChanged; - }; - }; - - /** Using a multimap as the same object might request multiple datasets */ - using HkReceiversMap = std::multimap; - - HkReceiversMap hkReceiversMap; - - /** This is the map holding the actual data. Should only be initialized - * once ! */ - bool mapInitialized = false; - /** This specifies whether a validity buffer is appended at the end - * of generated housekeeping packets. */ - bool appendValidityBuffer = true; - - /** - * @brief Queue used for communication, for example commands. - * Is also used to send messages. Can be set either in the constructor - * or in the initialize() function. - */ - MessageQueueIF* hkQueue = nullptr; - - /** - * HK replies will always be a reply to the commander, but HK packet - * can be sent to another destination by specifying this message queue - * ID, for example to a dedicated housekeeping service implementation. - */ - MessageQueueId_t hkDestination = MessageQueueIF::NO_QUEUE; - - /** Global IPC store is used to store all packets. */ - StorageManagerIF* ipcStore = nullptr; - /** - * Get the pointer to the mutex. Can be used to lock the data pool - * eternally. 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 - * entry to the supplied PoolEntry pointer. The type of the pool entry - * is deduced automatically. This call is not thread-safe! - * For now, only friend classes like LocalPoolVar may access this - * function. - * @tparam T Type of the pool entry - * @param localPoolId Pool ID of the variable to read - * @param poolVar [out] Corresponding pool entry will be assigned to the - * supplied pointer. - * @return - */ - template ReturnValue_t fetchPoolEntry(lp_id_t localPoolId, - PoolEntry **poolEntry); - - void setMinimalSamplingFrequency(float frequencySeconds); - ReturnValue_t serializeHkPacketIntoStore(store_address_t* storeId, - LocalDataSet* dataSet); -}; - - -template inline -ReturnValue_t LocalDataPoolManager::fetchPoolEntry(lp_id_t localPoolId, - PoolEntry **poolEntry) { - auto poolIter = localPoolMap.find(localPoolId); - if (poolIter == localPoolMap.end()) { - sif::warning << "HousekeepingManager::fechPoolEntry: Pool entry " - "not found." << std::endl; - return POOL_ENTRY_NOT_FOUND; - } - - *poolEntry = dynamic_cast< PoolEntry* >(poolIter->second); - if(*poolEntry == nullptr) { - sif::debug << "HousekeepingManager::fetchPoolEntry:" - " Pool entry not found." << std::endl; - return POOL_ENTRY_TYPE_CONFLICT; - } - return HasReturnvaluesIF::RETURN_OK; -} - - -#endif /* FRAMEWORK_DATAPOOLLOCAL_LOCALDATAPOOLMANAGER_H_ */ +#ifndef FRAMEWORK_DATAPOOLLOCAL_LOCALDATAPOOLMANAGER_H_ +#define FRAMEWORK_DATAPOOLLOCAL_LOCALDATAPOOLMANAGER_H_ + +#include "../datapool/DataSetIF.h" +#include "../objectmanager/SystemObjectIF.h" +#include "../ipc/MutexIF.h" + +#include "../housekeeping/HousekeepingMessage.h" +#include "../datapool/PoolEntry.h" +#include "../datapoollocal/HasLocalDataPoolIF.h" +#include "../ipc/CommandMessage.h" +#include "../ipc/MessageQueueIF.h" +#include "../ipc/MutexHelper.h" + +#include + +class LocalDataSet; + +/** + * @brief This class is the managing instance for local data pool. + * @details + * The actual data pool structure is a member of this class. Any class which + * has a local data pool shall have this class as a member and implement + * the HasLocalDataPoolIF. + * + * Users of the data pool use the helper classes LocalDataSet, + * LocalPoolVariable and LocalPoolVector to access pool entries in + * a thread-safe and efficient way. + * + * The local data pools employ a blackboard logic: Only the most recent + * value is stored. The helper classes offer a read() and commit() interface + * through the PoolVariableIF which is used to read and update values. + * Each pool entry has a valid state too. + * + */ +class LocalDataPoolManager { + template + friend class LocalPoolVar; + template + friend class LocalPoolVector; + friend class LocalDataSet; +public: + static constexpr uint8_t INTERFACE_ID = CLASS_ID::HOUSEKEEPING_MANAGER; + + static constexpr ReturnValue_t POOL_ENTRY_NOT_FOUND = MAKE_RETURN_CODE(0x0); + static constexpr ReturnValue_t POOL_ENTRY_TYPE_CONFLICT = MAKE_RETURN_CODE(0x1); + + static constexpr ReturnValue_t QUEUE_OR_DESTINATION_NOT_SET = MAKE_RETURN_CODE(0x2); + //static constexpr ReturnValue_t SET_NOT_FOUND = MAKE_RETURN_CODE(0x3); + + /** + * This constructor is used by a class which wants to implement + * a personal local data pool. The queueToUse can be supplied if it + * is already known. + * + * initialize() has to be called in any case before using the object! + * @param owner + * @param queueToUse + * @param appendValidityBuffer + */ + LocalDataPoolManager(HasLocalDataPoolIF* owner, MessageQueueIF* queueToUse, + bool appendValidityBuffer = true); + virtual~ LocalDataPoolManager(); + + /** + * Initializes the map by calling the map initialization function of the + * owner and assigns the queue to use. + * @param queueToUse + * @return + */ + ReturnValue_t initialize(MessageQueueIF* queueToUse, + object_id_t hkDestination); + + /** + * This should be called in the periodic handler of the owner. + * It performs all the periodic functionalities of the data pool manager. + * @return + */ + ReturnValue_t performHkOperation(); + /** + * This function is used to set the default HK packet destination. + * This destination will usually only be set once. + * @param hkDestination + */ + void setHkPacketDestination(MessageQueueId_t hkDestination); + + /** + * Generate a housekeeping packet with a given SID. + * @param sid + * @return + */ + ReturnValue_t generateHousekeepingPacket(sid_t sid, MessageQueueId_t sendTo + = MessageQueueIF::NO_QUEUE); + ReturnValue_t generateSetStructurePacket(sid_t sid); + + ReturnValue_t handleHousekeepingMessage(CommandMessage* message); + + /** + * This function is used to fill the local data pool map with pool + * entries. It should only be called once by the pool owner. + * @param localDataPoolMap + * @return + */ + ReturnValue_t initializeHousekeepingPoolEntriesOnce(); + + const HasLocalDataPoolIF* getOwner() const; + + ReturnValue_t printPoolEntry(lp_id_t localPoolId); + + /** + * Different types of housekeeping reporting are possible. + * 1. PERIODIC: HK packets are generated in fixed intervals + * 2. UPDATED: HK packets are generated if a value was updated + * 3. REQUESTED: HK packets are only generated if explicitely requested + */ + enum class ReportingType: uint8_t { + PERIODIC, + ON_UPDATE, + REQUESTED + }; + + /* Copying forbidden */ + LocalDataPoolManager(const LocalDataPoolManager &) = delete; + LocalDataPoolManager operator=(const LocalDataPoolManager&) = delete; + +private: + LocalDataPool localPoolMap; + /** Every housekeeping data manager has a mutex to protect access + * to it's data pool. */ + MutexIF* mutex = nullptr; + /** The class which actually owns the manager (and its datapool). */ + HasLocalDataPoolIF* owner = nullptr; + + /** + * The data pool manager will keep an internal map of HK receivers. + */ + struct HkReceiver { + LocalDataSet* dataSet = nullptr; + MessageQueueId_t destinationQueue = MessageQueueIF::NO_QUEUE; + ReportingType reportingType = ReportingType::PERIODIC; + bool reportingStatus = true; + /** Different members of this union will be used depending on reporting + * type */ + union hkParameter { + /** This parameter will be used for the PERIODIC type */ + dur_seconds_t collectionInterval = 0; + /** This parameter will be used for the ON_UPDATE type */ + bool hkDataChanged; + }; + }; + + /** Using a multimap as the same object might request multiple datasets */ + using HkReceiversMap = std::multimap; + + HkReceiversMap hkReceiversMap; + + /** This is the map holding the actual data. Should only be initialized + * once ! */ + bool mapInitialized = false; + /** This specifies whether a validity buffer is appended at the end + * of generated housekeeping packets. */ + bool appendValidityBuffer = true; + + /** + * @brief Queue used for communication, for example commands. + * Is also used to send messages. Can be set either in the constructor + * or in the initialize() function. + */ + MessageQueueIF* hkQueue = nullptr; + + /** + * HK replies will always be a reply to the commander, but HK packet + * can be sent to another destination by specifying this message queue + * ID, for example to a dedicated housekeeping service implementation. + */ + MessageQueueId_t hkDestination = MessageQueueIF::NO_QUEUE; + + /** Global IPC store is used to store all packets. */ + StorageManagerIF* ipcStore = nullptr; + /** + * Get the pointer to the mutex. Can be used to lock the data pool + * eternally. 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 + * entry to the supplied PoolEntry pointer. The type of the pool entry + * is deduced automatically. This call is not thread-safe! + * For now, only friend classes like LocalPoolVar may access this + * function. + * @tparam T Type of the pool entry + * @param localPoolId Pool ID of the variable to read + * @param poolVar [out] Corresponding pool entry will be assigned to the + * supplied pointer. + * @return + */ + template ReturnValue_t fetchPoolEntry(lp_id_t localPoolId, + PoolEntry **poolEntry); + + void setMinimalSamplingFrequency(float frequencySeconds); + ReturnValue_t serializeHkPacketIntoStore(store_address_t* storeId, + LocalDataSet* dataSet); +}; + + +template inline +ReturnValue_t LocalDataPoolManager::fetchPoolEntry(lp_id_t localPoolId, + PoolEntry **poolEntry) { + auto poolIter = localPoolMap.find(localPoolId); + if (poolIter == localPoolMap.end()) { + sif::warning << "HousekeepingManager::fechPoolEntry: Pool entry " + "not found." << std::endl; + return POOL_ENTRY_NOT_FOUND; + } + + *poolEntry = dynamic_cast< PoolEntry* >(poolIter->second); + if(*poolEntry == nullptr) { + sif::debug << "HousekeepingManager::fetchPoolEntry:" + " Pool entry not found." << std::endl; + return POOL_ENTRY_TYPE_CONFLICT; + } + return HasReturnvaluesIF::RETURN_OK; +} + + +#endif /* FRAMEWORK_DATAPOOLLOCAL_LOCALDATAPOOLMANAGER_H_ */ diff --git a/datapoollocal/LocalDataSet.cpp b/datapoollocal/LocalDataSet.cpp index 8725f697..163482e3 100644 --- a/datapoollocal/LocalDataSet.cpp +++ b/datapoollocal/LocalDataSet.cpp @@ -1,106 +1,106 @@ -#include -#include -#include - -#include -#include - -LocalDataSet::LocalDataSet(HasLocalDataPoolIF *hkOwner, - const size_t maxNumberOfVariables): - DataSetBase(poolVarList.data(), maxNumberOfVariables) { - poolVarList.reserve(maxNumberOfVariables); - poolVarList.resize(maxNumberOfVariables); - if(hkOwner == nullptr) { - sif::error << "LocalDataSet::LocalDataSet: Owner can't be nullptr!" - << std::endl; - return; - } - hkManager = hkOwner->getHkManagerHandle(); -} - -LocalDataSet::LocalDataSet(object_id_t ownerId, - const size_t maxNumberOfVariables): - DataSetBase(poolVarList.data(), maxNumberOfVariables) { - poolVarList.reserve(maxNumberOfVariables); - poolVarList.resize(maxNumberOfVariables); - HasLocalDataPoolIF* hkOwner = objectManager->get( - ownerId); - if(hkOwner == nullptr) { - sif::error << "LocalDataSet::LocalDataSet: Owner can't be nullptr!" - << std::endl; - return; - } - hkManager = hkOwner->getHkManagerHandle(); -} - -LocalDataSet::~LocalDataSet() { -} - -ReturnValue_t LocalDataSet::lockDataPool(uint32_t timeoutMs) { - MutexIF* mutex = hkManager->getMutexHandle(); - return mutex->lockMutex(MutexIF::TimeoutType::WAITING, timeoutMs); -} - -ReturnValue_t LocalDataSet::serializeWithValidityBuffer(uint8_t **buffer, - size_t *size, size_t maxSize, - SerializeIF::Endianness streamEndianness) const { - ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; - uint8_t validityMaskSize = std::ceil(static_cast(fillCount)/8.0); - uint8_t validityMask[validityMaskSize]; - uint8_t validBufferIndex = 0; - uint8_t validBufferIndexBit = 0; - for (uint16_t count = 0; count < fillCount; count++) { - if(registeredVariables[count]->isValid()) { - // set validity buffer here. - this->bitSetter(validityMask + validBufferIndex, - validBufferIndexBit); - if(validBufferIndexBit == 7) { - validBufferIndex ++; - validBufferIndexBit = 0; - } - else { - validBufferIndexBit ++; - } - } - result = registeredVariables[count]->serialize(buffer, size, maxSize, - streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - } - // copy validity buffer to end - std::memcpy(*buffer, validityMask, validityMaskSize); - *size += validityMaskSize; - return result; -} - -ReturnValue_t LocalDataSet::unlockDataPool() { - MutexIF* mutex = hkManager->getMutexHandle(); - return mutex->unlockMutex(); -} - -ReturnValue_t LocalDataSet::serializeLocalPoolIds(uint8_t** buffer, - size_t* size, size_t maxSize, - SerializeIF::Endianness streamEndianness) const { - for (uint16_t count = 0; count < fillCount; count++) { - lp_id_t currentPoolId = registeredVariables[count]->getDataPoolId(); - auto result = SerializeAdapter::serialize(¤tPoolId, buffer, - size, maxSize, streamEndianness); - if(result != HasReturnvaluesIF::RETURN_OK) { - sif::warning << "LocalDataSet::serializeLocalPoolIds: Serialization" - " error!" << std::endl; - return result; - } - } - return HasReturnvaluesIF::RETURN_OK; -} - -void LocalDataSet::bitSetter(uint8_t* byte, uint8_t position) const { - if(position > 7) { - sif::debug << "Pool Raw Access: Bit setting invalid position" << std::endl; - return; - } - uint8_t shiftNumber = position + (7 - 2 * position); - *byte |= 1 << shiftNumber; -} - +#include "../datapoollocal/LocalDataPoolManager.h" +#include "../datapoollocal/LocalDataSet.h" +#include "../serialize/SerializeAdapter.h" + +#include +#include + +LocalDataSet::LocalDataSet(HasLocalDataPoolIF *hkOwner, + const size_t maxNumberOfVariables): + DataSetBase(poolVarList.data(), maxNumberOfVariables) { + poolVarList.reserve(maxNumberOfVariables); + poolVarList.resize(maxNumberOfVariables); + if(hkOwner == nullptr) { + sif::error << "LocalDataSet::LocalDataSet: Owner can't be nullptr!" + << std::endl; + return; + } + hkManager = hkOwner->getHkManagerHandle(); +} + +LocalDataSet::LocalDataSet(object_id_t ownerId, + const size_t maxNumberOfVariables): + DataSetBase(poolVarList.data(), maxNumberOfVariables) { + poolVarList.reserve(maxNumberOfVariables); + poolVarList.resize(maxNumberOfVariables); + HasLocalDataPoolIF* hkOwner = objectManager->get( + ownerId); + if(hkOwner == nullptr) { + sif::error << "LocalDataSet::LocalDataSet: Owner can't be nullptr!" + << std::endl; + return; + } + hkManager = hkOwner->getHkManagerHandle(); +} + +LocalDataSet::~LocalDataSet() { +} + +ReturnValue_t LocalDataSet::lockDataPool(uint32_t timeoutMs) { + MutexIF* mutex = hkManager->getMutexHandle(); + return mutex->lockMutex(MutexIF::TimeoutType::WAITING, timeoutMs); +} + +ReturnValue_t LocalDataSet::serializeWithValidityBuffer(uint8_t **buffer, + size_t *size, size_t maxSize, + SerializeIF::Endianness streamEndianness) const { + ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; + uint8_t validityMaskSize = std::ceil(static_cast(fillCount)/8.0); + uint8_t validityMask[validityMaskSize]; + uint8_t validBufferIndex = 0; + uint8_t validBufferIndexBit = 0; + for (uint16_t count = 0; count < fillCount; count++) { + if(registeredVariables[count]->isValid()) { + // set validity buffer here. + this->bitSetter(validityMask + validBufferIndex, + validBufferIndexBit); + if(validBufferIndexBit == 7) { + validBufferIndex ++; + validBufferIndexBit = 0; + } + else { + validBufferIndexBit ++; + } + } + result = registeredVariables[count]->serialize(buffer, size, maxSize, + streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + // copy validity buffer to end + std::memcpy(*buffer, validityMask, validityMaskSize); + *size += validityMaskSize; + return result; +} + +ReturnValue_t LocalDataSet::unlockDataPool() { + MutexIF* mutex = hkManager->getMutexHandle(); + return mutex->unlockMutex(); +} + +ReturnValue_t LocalDataSet::serializeLocalPoolIds(uint8_t** buffer, + size_t* size, size_t maxSize, + SerializeIF::Endianness streamEndianness) const { + for (uint16_t count = 0; count < fillCount; count++) { + lp_id_t currentPoolId = registeredVariables[count]->getDataPoolId(); + auto result = SerializeAdapter::serialize(¤tPoolId, buffer, + size, maxSize, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::warning << "LocalDataSet::serializeLocalPoolIds: Serialization" + " error!" << std::endl; + return result; + } + } + return HasReturnvaluesIF::RETURN_OK; +} + +void LocalDataSet::bitSetter(uint8_t* byte, uint8_t position) const { + if(position > 7) { + sif::debug << "Pool Raw Access: Bit setting invalid position" << std::endl; + return; + } + uint8_t shiftNumber = position + (7 - 2 * position); + *byte |= 1 << shiftNumber; +} + diff --git a/datapoollocal/LocalDataSet.h b/datapoollocal/LocalDataSet.h index 2c70de82..75111d93 100644 --- a/datapoollocal/LocalDataSet.h +++ b/datapoollocal/LocalDataSet.h @@ -1,115 +1,115 @@ -#ifndef FRAMEWORK_DATAPOOLLOCAL_LOCALDATASET_H_ -#define FRAMEWORK_DATAPOOLLOCAL_LOCALDATASET_H_ -#include -#include -#include -#include - -#include - -class LocalDataPoolManager; - -/** - * @brief The LocalDataSet class manages a set of locally checked out variables - * for local data pools - * @details - * This class manages a list, where a set of local variables (or pool variables) - * are registered. They are checked-out (i.e. their values are looked - * up and copied) with the read call. After the user finishes working with the - * pool variables, he can write back all variable values to the pool with - * the commit call. The data set manages locking and freeing the local data pools, - * to ensure thread-safety. - * - * An internal state manages usage of this class. Variables may only be - * registered before the read call is made, and the commit call only - * after the read call. - * - * If pool variables are writable and not committed until destruction - * of the set, the DataSet class automatically sets the valid flag in the - * data pool to invalid (without) changing the variable's value. - * - * @ingroup data_pool - */ -class LocalDataSet: public DataSetBase { -public: - /** - * @brief Constructor for the creator of local pool data. - * The constructor simply sets the fill_count to zero and sets - * the state to "uninitialized". - */ - LocalDataSet(HasLocalDataPoolIF *hkOwner, - const size_t maxNumberOfVariables); - - /** - * @brief Constructor for users of local pool data. The passed pool - * owner should implement the HasHkPoolParametersIF. - * The constructor simply sets the fill_count to zero and sets - * the state to "uninitialized". - */ - LocalDataSet(object_id_t ownerId, - const size_t maxNumberOfVariables); - - /** - * @brief The destructor automatically manages writing the valid - * information of variables. - * @details - * In case the data set was read out, but not committed(indicated by state), - * the destructor parses all variables that are still registered to the set. - * For each, the valid flag in the data pool is set to "invalid". - */ - ~LocalDataSet(); - - /** - * Special version of the serilization function which appends a - * validity buffer at the end. Each bit of this validity buffer - * denotes whether the container data set entries are valid from left - * to right, MSB first. - * @param buffer - * @param size - * @param maxSize - * @param bigEndian - * @param withValidityBuffer - * @return - */ - ReturnValue_t serializeWithValidityBuffer(uint8_t** buffer, - size_t* size, size_t maxSize, - SerializeIF::Endianness streamEndianness) const; - - ReturnValue_t serializeLocalPoolIds(uint8_t** buffer, - size_t* size, size_t maxSize, - SerializeIF::Endianness streamEndianness) const; -protected: -private: - /** - * If the valid state of a dataset is always relevant to the whole - * data set we can use this flag. - */ - bool valid = false; - - /** - * @brief This is a small helper function to facilitate locking - * the global data pool. - * @details - * It makes use of the lockDataPool method offered by the DataPool class. - */ - ReturnValue_t lockDataPool(uint32_t timeoutMs) override; - /** - * @brief This is a small helper function to facilitate - * unlocking the global data pool - * @details - * It makes use of the freeDataPoolLock method offered by the DataPool class. - */ - ReturnValue_t unlockDataPool() override; - - LocalDataPoolManager* hkManager; - - /** - * Set n-th bit of a byte, with n being the position from 0 - * (most significant bit) to 7 (least significant bit) - */ - void bitSetter(uint8_t* byte, uint8_t position) const; - - std::vector poolVarList; -}; - -#endif /* FRAMEWORK_DATAPOOLLOCAL_LOCALDATASET_H_ */ +#ifndef FRAMEWORK_DATAPOOLLOCAL_LOCALDATASET_H_ +#define FRAMEWORK_DATAPOOLLOCAL_LOCALDATASET_H_ +#include "../datapool/DataSetBase.h" +#include "../datapool/DataSetIF.h" +#include "../datapoollocal/HasLocalDataPoolIF.h" +#include "../serialize/SerializeIF.h" + +#include + +class LocalDataPoolManager; + +/** + * @brief The LocalDataSet class manages a set of locally checked out variables + * for local data pools + * @details + * This class manages a list, where a set of local variables (or pool variables) + * are registered. They are checked-out (i.e. their values are looked + * up and copied) with the read call. After the user finishes working with the + * pool variables, he can write back all variable values to the pool with + * the commit call. The data set manages locking and freeing the local data pools, + * to ensure thread-safety. + * + * An internal state manages usage of this class. Variables may only be + * registered before the read call is made, and the commit call only + * after the read call. + * + * If pool variables are writable and not committed until destruction + * of the set, the DataSet class automatically sets the valid flag in the + * data pool to invalid (without) changing the variable's value. + * + * @ingroup data_pool + */ +class LocalDataSet: public DataSetBase { +public: + /** + * @brief Constructor for the creator of local pool data. + * The constructor simply sets the fill_count to zero and sets + * the state to "uninitialized". + */ + LocalDataSet(HasLocalDataPoolIF *hkOwner, + const size_t maxNumberOfVariables); + + /** + * @brief Constructor for users of local pool data. The passed pool + * owner should implement the HasHkPoolParametersIF. + * The constructor simply sets the fill_count to zero and sets + * the state to "uninitialized". + */ + LocalDataSet(object_id_t ownerId, + const size_t maxNumberOfVariables); + + /** + * @brief The destructor automatically manages writing the valid + * information of variables. + * @details + * In case the data set was read out, but not committed(indicated by state), + * the destructor parses all variables that are still registered to the set. + * For each, the valid flag in the data pool is set to "invalid". + */ + ~LocalDataSet(); + + /** + * Special version of the serilization function which appends a + * validity buffer at the end. Each bit of this validity buffer + * denotes whether the container data set entries are valid from left + * to right, MSB first. + * @param buffer + * @param size + * @param maxSize + * @param bigEndian + * @param withValidityBuffer + * @return + */ + ReturnValue_t serializeWithValidityBuffer(uint8_t** buffer, + size_t* size, size_t maxSize, + SerializeIF::Endianness streamEndianness) const; + + ReturnValue_t serializeLocalPoolIds(uint8_t** buffer, + size_t* size, size_t maxSize, + SerializeIF::Endianness streamEndianness) const; +protected: +private: + /** + * If the valid state of a dataset is always relevant to the whole + * data set we can use this flag. + */ + bool valid = false; + + /** + * @brief This is a small helper function to facilitate locking + * the global data pool. + * @details + * It makes use of the lockDataPool method offered by the DataPool class. + */ + ReturnValue_t lockDataPool(uint32_t timeoutMs) override; + /** + * @brief This is a small helper function to facilitate + * unlocking the global data pool + * @details + * It makes use of the freeDataPoolLock method offered by the DataPool class. + */ + ReturnValue_t unlockDataPool() override; + + LocalDataPoolManager* hkManager; + + /** + * Set n-th bit of a byte, with n being the position from 0 + * (most significant bit) to 7 (least significant bit) + */ + void bitSetter(uint8_t* byte, uint8_t position) const; + + std::vector poolVarList; +}; + +#endif /* FRAMEWORK_DATAPOOLLOCAL_LOCALDATASET_H_ */ diff --git a/datapoollocal/LocalPoolVariable.h b/datapoollocal/LocalPoolVariable.h index 73d691d7..efebdaef 100644 --- a/datapoollocal/LocalPoolVariable.h +++ b/datapoollocal/LocalPoolVariable.h @@ -1,173 +1,173 @@ -#ifndef FRAMEWORK_DATAPOOLLOCAL_LOCALPOOLVARIABLE_H_ -#define FRAMEWORK_DATAPOOLLOCAL_LOCALPOOLVARIABLE_H_ - -#include -#include -#include -#include -#include - -#include - -/** - * @brief Local Pool Variable class which is used to access the local pools. - * @details - * This class is not stored in the map. Instead, it is used to access - * the pool entries by using a pointer to the map storing the pool - * entries. It can also be used to organize these pool entries into data sets. - * - * @tparam T The template parameter sets the type of the variable. Currently, - * all plain data types are supported, but in principle any type is possible. - * @ingroup data_pool - */ -template -class LocalPoolVar: public PoolVariableIF, HasReturnvaluesIF { -public: - //! Default ctor is forbidden. - LocalPoolVar() = delete; - - /** - * This constructor is used by the data creators to have pool variable - * instances which can also be stored in datasets. - * - * It does not fetch the current value from the data pool, which - * has to be done by calling the read() operation. - * Datasets can be used to access multiple local pool entries in an - * efficient way. A pointer to a dataset can be passed to register - * the pool variable in that dataset directly. - * @param poolId ID of the local pool entry. - * @param hkOwner Pointer of the owner. This will generally be the calling - * class itself which passes "this". - * @param setReadWriteMode Specify the read-write mode of the pool variable. - * @param dataSet The data set in which the variable shall register itself. - * If nullptr, the variable is not registered. - */ - LocalPoolVar(lp_id_t poolId, HasLocalDataPoolIF* hkOwner, - pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE, - DataSetIF* dataSet = nullptr); - - /** - * This constructor is used by data users like controllers to have - * access to the local pool variables of data creators by supplying - * the respective creator object ID. - * - * It does not fetch the current value from the data pool, which - * has to be done by calling the read() operation. - * Datasets can be used to access multiple local pool entries in an - * efficient way. A pointer to a dataset can be passed to register - * the pool variable in that dataset directly. - * @param poolId ID of the local pool entry. - * @param hkOwner object ID of the pool owner. - * @param setReadWriteMode Specify the read-write mode of the pool variable. - * @param dataSet The data set in which the variable shall register itself. - * If nullptr, the variable is not registered. - */ - LocalPoolVar(lp_id_t poolId, object_id_t poolOwner, - pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE, - DataSetIF* dataSet = nullptr); - - virtual~ LocalPoolVar() {}; - - /** - * @brief This is the local copy of the data pool entry. - * @details The user can work on this attribute - * just like he would on a simple local variable. - */ - T value = 0; - - pool_rwm_t getReadWriteMode() const override; - - lp_id_t getDataPoolId() const override; - void setDataPoolId(lp_id_t poolId); - - bool isValid() const override; - void setValid(bool validity) override; - uint8_t getValid() const; - - ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, - SerializeIF::Endianness streamEndianness) const override; - virtual size_t getSerializedSize() const override; - virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - SerializeIF::Endianness streamEndianness) override; - - /** - * @brief This is a call to read the array's values - * from the global data pool. - * @details - * When executed, this operation tries to fetch the pool entry with matching - * data pool id from the data pool and copies all array values and the valid - * information to its local attributes. - * In case of a failure (wrong type, size or pool id not found), the - * variable is set to zero and invalid. - * The read call is protected with a lock. - * It is recommended to use DataSets to read and commit multiple variables - * at once to avoid the overhead of unnecessary lock und unlock operations. - * - */ - ReturnValue_t read(dur_millis_t lockTimeout = MutexIF::BLOCKING) override; - /** - * @brief The commit call copies the array values back to the data pool. - * @details - * It checks type and size, as well as if the variable is writable. If so, - * the value is copied and the local valid flag is written back as well. - * The read call is protected with a lock. - * It is recommended to use DataSets to read and commit multiple variables - * at once to avoid the overhead of unnecessary lock und unlock operations. - */ - ReturnValue_t commit(dur_millis_t lockTimeout = MutexIF::BLOCKING) override; - -protected: - /** - * @brief Like #read, but without a lock protection of the global pool. - * @details - * The operation does NOT provide any mutual exclusive protection by itself. - * This can be used if the lock is handled externally to avoid the overhead - * of consecutive lock und unlock operations. - * Declared protected to discourage free public usage. - */ - ReturnValue_t readWithoutLock() override; - /** - * @brief Like #commit, but without a lock protection of the global pool. - * @details - * The operation does NOT provide any mutual exclusive protection by itself. - * This can be used if the lock is handled externally to avoid the overhead - * of consecutive lock und unlock operations. - * Declared protected to discourage free public usage. - */ - ReturnValue_t commitWithoutLock() override; - - // std::ostream is the type for object std::cout - template - friend std::ostream& operator<< (std::ostream &out, - const LocalPoolVar &var); - -private: - //! @brief Pool ID of pool entry inside the used local pool. - lp_id_t localPoolId = PoolVariableIF::NO_PARAMETER; - //! @brief Read-write mode of the pool variable - pool_rwm_t readWriteMode = pool_rwm_t::VAR_READ_WRITE; - //! @brief Specifies whether the entry is valid or invalid. - bool valid = false; - - //! Pointer to the class which manages the HK pool. - LocalDataPoolManager* hkManager; -}; - -#include - -template -using lp_var_t = LocalPoolVar; - -using lp_bool_t = LocalPoolVar; -using lp_uint8_t = LocalPoolVar; -using lp_uint16_t = LocalPoolVar; -using lp_uint32_t = LocalPoolVar; -using lp_uint64_t = LocalPoolVar; -using lp_int8_t = LocalPoolVar; -using lp_int16_t = LocalPoolVar; -using lp_int32_t = LocalPoolVar; -using lp_int64_t = LocalPoolVar; -using lp_float_t = LocalPoolVar; -using lp_double_t = LocalPoolVar; - -#endif +#ifndef FRAMEWORK_DATAPOOLLOCAL_LOCALPOOLVARIABLE_H_ +#define FRAMEWORK_DATAPOOLLOCAL_LOCALPOOLVARIABLE_H_ + +#include "../datapool/PoolVariableIF.h" +#include "../datapool/DataSetIF.h" +#include "../datapoollocal/HasLocalDataPoolIF.h" +#include "../datapoollocal/LocalDataPoolManager.h" +#include "../objectmanager/ObjectManagerIF.h" + +#include "../serialize/SerializeAdapter.h" + +/** + * @brief Local Pool Variable class which is used to access the local pools. + * @details + * This class is not stored in the map. Instead, it is used to access + * the pool entries by using a pointer to the map storing the pool + * entries. It can also be used to organize these pool entries into data sets. + * + * @tparam T The template parameter sets the type of the variable. Currently, + * all plain data types are supported, but in principle any type is possible. + * @ingroup data_pool + */ +template +class LocalPoolVar: public PoolVariableIF, HasReturnvaluesIF { +public: + //! Default ctor is forbidden. + LocalPoolVar() = delete; + + /** + * This constructor is used by the data creators to have pool variable + * instances which can also be stored in datasets. + * + * It does not fetch the current value from the data pool, which + * has to be done by calling the read() operation. + * Datasets can be used to access multiple local pool entries in an + * efficient way. A pointer to a dataset can be passed to register + * the pool variable in that dataset directly. + * @param poolId ID of the local pool entry. + * @param hkOwner Pointer of the owner. This will generally be the calling + * class itself which passes "this". + * @param setReadWriteMode Specify the read-write mode of the pool variable. + * @param dataSet The data set in which the variable shall register itself. + * If nullptr, the variable is not registered. + */ + LocalPoolVar(lp_id_t poolId, HasLocalDataPoolIF* hkOwner, + pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE, + DataSetIF* dataSet = nullptr); + + /** + * This constructor is used by data users like controllers to have + * access to the local pool variables of data creators by supplying + * the respective creator object ID. + * + * It does not fetch the current value from the data pool, which + * has to be done by calling the read() operation. + * Datasets can be used to access multiple local pool entries in an + * efficient way. A pointer to a dataset can be passed to register + * the pool variable in that dataset directly. + * @param poolId ID of the local pool entry. + * @param hkOwner object ID of the pool owner. + * @param setReadWriteMode Specify the read-write mode of the pool variable. + * @param dataSet The data set in which the variable shall register itself. + * If nullptr, the variable is not registered. + */ + LocalPoolVar(lp_id_t poolId, object_id_t poolOwner, + pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE, + DataSetIF* dataSet = nullptr); + + virtual~ LocalPoolVar() {}; + + /** + * @brief This is the local copy of the data pool entry. + * @details The user can work on this attribute + * just like he would on a simple local variable. + */ + T value = 0; + + pool_rwm_t getReadWriteMode() const override; + + lp_id_t getDataPoolId() const override; + void setDataPoolId(lp_id_t poolId); + + bool isValid() const override; + void setValid(bool validity) override; + uint8_t getValid() const; + + ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, + SerializeIF::Endianness streamEndianness) const override; + virtual size_t getSerializedSize() const override; + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + SerializeIF::Endianness streamEndianness) override; + + /** + * @brief This is a call to read the array's values + * from the global data pool. + * @details + * When executed, this operation tries to fetch the pool entry with matching + * data pool id from the data pool and copies all array values and the valid + * information to its local attributes. + * In case of a failure (wrong type, size or pool id not found), the + * variable is set to zero and invalid. + * The read call is protected with a lock. + * It is recommended to use DataSets to read and commit multiple variables + * at once to avoid the overhead of unnecessary lock und unlock operations. + * + */ + ReturnValue_t read(dur_millis_t lockTimeout = MutexIF::BLOCKING) override; + /** + * @brief The commit call copies the array values back to the data pool. + * @details + * It checks type and size, as well as if the variable is writable. If so, + * the value is copied and the local valid flag is written back as well. + * The read call is protected with a lock. + * It is recommended to use DataSets to read and commit multiple variables + * at once to avoid the overhead of unnecessary lock und unlock operations. + */ + ReturnValue_t commit(dur_millis_t lockTimeout = MutexIF::BLOCKING) override; + +protected: + /** + * @brief Like #read, but without a lock protection of the global pool. + * @details + * The operation does NOT provide any mutual exclusive protection by itself. + * This can be used if the lock is handled externally to avoid the overhead + * of consecutive lock und unlock operations. + * Declared protected to discourage free public usage. + */ + ReturnValue_t readWithoutLock() override; + /** + * @brief Like #commit, but without a lock protection of the global pool. + * @details + * The operation does NOT provide any mutual exclusive protection by itself. + * This can be used if the lock is handled externally to avoid the overhead + * of consecutive lock und unlock operations. + * Declared protected to discourage free public usage. + */ + ReturnValue_t commitWithoutLock() override; + + // std::ostream is the type for object std::cout + template + friend std::ostream& operator<< (std::ostream &out, + const LocalPoolVar &var); + +private: + //! @brief Pool ID of pool entry inside the used local pool. + lp_id_t localPoolId = PoolVariableIF::NO_PARAMETER; + //! @brief Read-write mode of the pool variable + pool_rwm_t readWriteMode = pool_rwm_t::VAR_READ_WRITE; + //! @brief Specifies whether the entry is valid or invalid. + bool valid = false; + + //! Pointer to the class which manages the HK pool. + LocalDataPoolManager* hkManager; +}; + +#include "../datapoollocal/LocalPoolVariable.tpp" + +template +using lp_var_t = LocalPoolVar; + +using lp_bool_t = LocalPoolVar; +using lp_uint8_t = LocalPoolVar; +using lp_uint16_t = LocalPoolVar; +using lp_uint32_t = LocalPoolVar; +using lp_uint64_t = LocalPoolVar; +using lp_int8_t = LocalPoolVar; +using lp_int16_t = LocalPoolVar; +using lp_int32_t = LocalPoolVar; +using lp_int64_t = LocalPoolVar; +using lp_float_t = LocalPoolVar; +using lp_double_t = LocalPoolVar; + +#endif diff --git a/datapoollocal/LocalPoolVector.h b/datapoollocal/LocalPoolVector.h index 3083646f..8c3c50db 100644 --- a/datapoollocal/LocalPoolVector.h +++ b/datapoollocal/LocalPoolVector.h @@ -1,200 +1,200 @@ -#ifndef FRAMEWORK_DATAPOOLLOCAL_LOCALPOOLVECTOR_H_ -#define FRAMEWORK_DATAPOOLLOCAL_LOCALPOOLVECTOR_H_ - -#include -#include -#include -#include -#include -#include - - -/** - * @brief This is the access class for array-type data pool entries. - * @details - * To ensure safe usage of the data pool, operation is not done directly on the - * data pool entries, but on local copies. This class provides simple type- - * and length-safe access to vector-style data pool entries (i.e. entries with - * length > 1). The class can be instantiated as read-write and read only. - * - * It provides a commit-and-roll-back semantic, which means that no array - * entry in the data pool is changed until the commit call is executed. - * There are two template parameters: - * @tparam T - * This template parameter specifies the data type of an array entry. Currently, - * all plain data types are supported, but in principle any type is possible. - * @tparam vector_size - * This template parameter specifies the vector size of this entry. Using a - * template parameter for this is not perfect, but avoids - * dynamic memory allocation. - * @ingroup data_pool - */ -template -class LocalPoolVector: public PoolVariableIF, public HasReturnvaluesIF { -public: - LocalPoolVector() = delete; - /** - * This constructor is used by the data creators to have pool variable - * instances which can also be stored in datasets. - * It does not fetch the current value from the data pool. This is performed - * by the read() operation (which is not thread-safe). - * Datasets can be used to access local pool entires in a thread-safe way. - * @param poolId ID of the local pool entry. - * @param hkOwner Pointer of the owner. This will generally be the calling - * class itself which passes "this". - * @param setReadWriteMode Specify the read-write mode of the pool variable. - * @param dataSet The data set in which the variable shall register itself. - * If nullptr, the variable is not registered. - */ - LocalPoolVector(lp_id_t poolId, HasLocalDataPoolIF* hkOwner, - pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE, - DataSetIF* dataSet = nullptr); - - /** - * This constructor is used by data users like controllers to have - * access to the local pool variables of data creators by supplying - * the respective creator object ID. - * It does not fetch the current value from the data pool. This is performed - * by the read() operation (which is not thread-safe). - * Datasets can be used to access local pool entires in a thread-safe way. - * @param poolId ID of the local pool entry. - * @param hkOwner Pointer of the owner. This will generally be the calling - * class itself which passes "this". - * @param setReadWriteMode Specify the read-write mode of the pool variable. - * @param dataSet The data set in which the variable shall register itself. - * If nullptr, the variable is not registered. - */ - LocalPoolVector(lp_id_t poolId, object_id_t poolOwner, - pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE, - DataSetIF* dataSet = nullptr); - - /** - * @brief This is the local copy of the data pool entry. - * @details - * The user can work on this attribute just like he would on a local - * array of this type. - */ - T value[vectorSize]; - /** - * @brief The classes destructor is empty. - * @details If commit() was not called, the local value is - * discarded and not written back to the data pool. - */ - ~LocalPoolVector() {}; - /** - * @brief The operation returns the number of array entries - * in this variable. - */ - uint8_t getSize() { - return vectorSize; - } - - uint32_t getDataPoolId() const override; - /** - * @brief This operation sets the data pool ID of the variable. - * @details - * The method is necessary to set id's of data pool member variables - * with bad initialization. - */ - void setDataPoolId(uint32_t poolId); - - /** - * This method returns if the variable is write-only, read-write or read-only. - */ - pool_rwm_t getReadWriteMode() const; - - /** - * @brief With this call, the valid information of the variable is returned. - */ - bool isValid() const override; - void setValid(bool valid) override; - uint8_t getValid() const; - - T& operator [](int i); - const T &operator [](int i) const; - - virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, - const size_t maxSize, - SerializeIF::Endianness streamEndiannes) const override; - virtual size_t getSerializedSize() const override; - virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - SerializeIF::Endianness streamEndianness) override; - - /** - * @brief This is a call to read the array's values - * from the global data pool. - * @details - * When executed, this operation tries to fetch the pool entry with matching - * data pool id from the data pool and copies all array values and the valid - * information to its local attributes. - * In case of a failure (wrong type, size or pool id not found), the - * variable is set to zero and invalid. - * The read call is protected with a lock. - * It is recommended to use DataSets to read and commit multiple variables - * at once to avoid the overhead of unnecessary lock und unlock operations. - */ - ReturnValue_t read(uint32_t lockTimeout = MutexIF::BLOCKING) override; - /** - * @brief The commit call copies the array values back to the data pool. - * @details - * It checks type and size, as well as if the variable is writable. If so, - * the value is copied and the local valid flag is written back as well. - * The read call is protected with a lock. - * It is recommended to use DataSets to read and commit multiple variables - * at once to avoid the overhead of unnecessary lock und unlock operations. - */ - ReturnValue_t commit(uint32_t lockTimeout = MutexIF::BLOCKING) override; - -protected: - /** - * @brief Like #read, but without a lock protection of the global pool. - * @details - * The operation does NOT provide any mutual exclusive protection by itself. - * This can be used if the lock is handled externally to avoid the overhead - * of consecutive lock und unlock operations. - * Declared protected to discourage free public usage. - */ - ReturnValue_t readWithoutLock() override; - /** - * @brief Like #commit, but without a lock protection of the global pool. - * @details - * The operation does NOT provide any mutual exclusive protection by itself. - * This can be used if the lock is handled externally to avoid the overhead - * of consecutive lock und unlock operations. - * Declared protected to discourage free public usage. - */ - ReturnValue_t commitWithoutLock() override; - -private: - /** - * @brief To access the correct data pool entry on read and commit calls, - * the data pool id is stored. - */ - uint32_t localPoolId; - /** - * @brief The valid information as it was stored in the data pool - * is copied to this attribute. - */ - bool valid; - /** - * @brief The information whether the class is read-write or - * read-only is stored here. - */ - ReadWriteMode_t readWriteMode; - //! @brief Pointer to the class which manages the HK pool. - LocalDataPoolManager* hkManager; - - // std::ostream is the type for object std::cout - template - friend std::ostream& operator<< (std::ostream &out, - const LocalPoolVector &var); - - -}; - -#include - -template -using lp_vec_t = LocalPoolVector; - -#endif /* FRAMEWORK_DATAPOOLLOCAL_LOCALPOOLVECTOR_H_ */ +#ifndef FRAMEWORK_DATAPOOLLOCAL_LOCALPOOLVECTOR_H_ +#define FRAMEWORK_DATAPOOLLOCAL_LOCALPOOLVECTOR_H_ + +#include "../datapool/DataSetIF.h" +#include "../datapool/PoolEntry.h" +#include "../datapool/PoolVariableIF.h" +#include "../datapoollocal/LocalDataPoolManager.h" +#include "../serialize/SerializeAdapter.h" +#include "../serviceinterface/ServiceInterfaceStream.h" + + +/** + * @brief This is the access class for array-type data pool entries. + * @details + * To ensure safe usage of the data pool, operation is not done directly on the + * data pool entries, but on local copies. This class provides simple type- + * and length-safe access to vector-style data pool entries (i.e. entries with + * length > 1). The class can be instantiated as read-write and read only. + * + * It provides a commit-and-roll-back semantic, which means that no array + * entry in the data pool is changed until the commit call is executed. + * There are two template parameters: + * @tparam T + * This template parameter specifies the data type of an array entry. Currently, + * all plain data types are supported, but in principle any type is possible. + * @tparam vector_size + * This template parameter specifies the vector size of this entry. Using a + * template parameter for this is not perfect, but avoids + * dynamic memory allocation. + * @ingroup data_pool + */ +template +class LocalPoolVector: public PoolVariableIF, public HasReturnvaluesIF { +public: + LocalPoolVector() = delete; + /** + * This constructor is used by the data creators to have pool variable + * instances which can also be stored in datasets. + * It does not fetch the current value from the data pool. This is performed + * by the read() operation (which is not thread-safe). + * Datasets can be used to access local pool entires in a thread-safe way. + * @param poolId ID of the local pool entry. + * @param hkOwner Pointer of the owner. This will generally be the calling + * class itself which passes "this". + * @param setReadWriteMode Specify the read-write mode of the pool variable. + * @param dataSet The data set in which the variable shall register itself. + * If nullptr, the variable is not registered. + */ + LocalPoolVector(lp_id_t poolId, HasLocalDataPoolIF* hkOwner, + pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE, + DataSetIF* dataSet = nullptr); + + /** + * This constructor is used by data users like controllers to have + * access to the local pool variables of data creators by supplying + * the respective creator object ID. + * It does not fetch the current value from the data pool. This is performed + * by the read() operation (which is not thread-safe). + * Datasets can be used to access local pool entires in a thread-safe way. + * @param poolId ID of the local pool entry. + * @param hkOwner Pointer of the owner. This will generally be the calling + * class itself which passes "this". + * @param setReadWriteMode Specify the read-write mode of the pool variable. + * @param dataSet The data set in which the variable shall register itself. + * If nullptr, the variable is not registered. + */ + LocalPoolVector(lp_id_t poolId, object_id_t poolOwner, + pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE, + DataSetIF* dataSet = nullptr); + + /** + * @brief This is the local copy of the data pool entry. + * @details + * The user can work on this attribute just like he would on a local + * array of this type. + */ + T value[vectorSize]; + /** + * @brief The classes destructor is empty. + * @details If commit() was not called, the local value is + * discarded and not written back to the data pool. + */ + ~LocalPoolVector() {}; + /** + * @brief The operation returns the number of array entries + * in this variable. + */ + uint8_t getSize() { + return vectorSize; + } + + uint32_t getDataPoolId() const override; + /** + * @brief This operation sets the data pool ID of the variable. + * @details + * The method is necessary to set id's of data pool member variables + * with bad initialization. + */ + void setDataPoolId(uint32_t poolId); + + /** + * This method returns if the variable is write-only, read-write or read-only. + */ + pool_rwm_t getReadWriteMode() const; + + /** + * @brief With this call, the valid information of the variable is returned. + */ + bool isValid() const override; + void setValid(bool valid) override; + uint8_t getValid() const; + + T& operator [](int i); + const T &operator [](int i) const; + + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t maxSize, + SerializeIF::Endianness streamEndiannes) const override; + virtual size_t getSerializedSize() const override; + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + SerializeIF::Endianness streamEndianness) override; + + /** + * @brief This is a call to read the array's values + * from the global data pool. + * @details + * When executed, this operation tries to fetch the pool entry with matching + * data pool id from the data pool and copies all array values and the valid + * information to its local attributes. + * In case of a failure (wrong type, size or pool id not found), the + * variable is set to zero and invalid. + * The read call is protected with a lock. + * It is recommended to use DataSets to read and commit multiple variables + * at once to avoid the overhead of unnecessary lock und unlock operations. + */ + ReturnValue_t read(uint32_t lockTimeout = MutexIF::BLOCKING) override; + /** + * @brief The commit call copies the array values back to the data pool. + * @details + * It checks type and size, as well as if the variable is writable. If so, + * the value is copied and the local valid flag is written back as well. + * The read call is protected with a lock. + * It is recommended to use DataSets to read and commit multiple variables + * at once to avoid the overhead of unnecessary lock und unlock operations. + */ + ReturnValue_t commit(uint32_t lockTimeout = MutexIF::BLOCKING) override; + +protected: + /** + * @brief Like #read, but without a lock protection of the global pool. + * @details + * The operation does NOT provide any mutual exclusive protection by itself. + * This can be used if the lock is handled externally to avoid the overhead + * of consecutive lock und unlock operations. + * Declared protected to discourage free public usage. + */ + ReturnValue_t readWithoutLock() override; + /** + * @brief Like #commit, but without a lock protection of the global pool. + * @details + * The operation does NOT provide any mutual exclusive protection by itself. + * This can be used if the lock is handled externally to avoid the overhead + * of consecutive lock und unlock operations. + * Declared protected to discourage free public usage. + */ + ReturnValue_t commitWithoutLock() override; + +private: + /** + * @brief To access the correct data pool entry on read and commit calls, + * the data pool id is stored. + */ + uint32_t localPoolId; + /** + * @brief The valid information as it was stored in the data pool + * is copied to this attribute. + */ + bool valid; + /** + * @brief The information whether the class is read-write or + * read-only is stored here. + */ + ReadWriteMode_t readWriteMode; + //! @brief Pointer to the class which manages the HK pool. + LocalDataPoolManager* hkManager; + + // std::ostream is the type for object std::cout + template + friend std::ostream& operator<< (std::ostream &out, + const LocalPoolVector &var); + + +}; + +#include "../datapoollocal/LocalPoolVector.tpp" + +template +using lp_vec_t = LocalPoolVector; + +#endif /* FRAMEWORK_DATAPOOLLOCAL_LOCALPOOLVECTOR_H_ */ diff --git a/datapoollocal/StaticLocalDataSet.cpp b/datapoollocal/StaticLocalDataSet.cpp index 15d4251a..c845a0d1 100644 --- a/datapoollocal/StaticLocalDataSet.cpp +++ b/datapoollocal/StaticLocalDataSet.cpp @@ -1,6 +1,6 @@ -#include - - - - - +#include "../datapoollocal/StaticLocalDataSet.h" + + + + + diff --git a/datapoollocal/StaticLocalDataSet.h b/datapoollocal/StaticLocalDataSet.h index 15a79aae..add9c48c 100644 --- a/datapoollocal/StaticLocalDataSet.h +++ b/datapoollocal/StaticLocalDataSet.h @@ -1,11 +1,11 @@ -#ifndef FRAMEWORK_DATAPOOLLOCAL_STATICLOCALDATASET_H_ -#define FRAMEWORK_DATAPOOLLOCAL_STATICLOCALDATASET_H_ -#include - - -class StaticLocalDataSet: public DataSetBase { - -}; - - -#endif /* FRAMEWORK_DATAPOOLLOCAL_STATICLOCALDATASET_H_ */ +#ifndef FRAMEWORK_DATAPOOLLOCAL_STATICLOCALDATASET_H_ +#define FRAMEWORK_DATAPOOLLOCAL_STATICLOCALDATASET_H_ +#include "../datapool/DataSetBase.h" + + +class StaticLocalDataSet: public DataSetBase { + +}; + + +#endif /* FRAMEWORK_DATAPOOLLOCAL_STATICLOCALDATASET_H_ */ diff --git a/devicehandlers/AcceptsDeviceResponsesIF.h b/devicehandlers/AcceptsDeviceResponsesIF.h index fcf5237d..d7e11714 100644 --- a/devicehandlers/AcceptsDeviceResponsesIF.h +++ b/devicehandlers/AcceptsDeviceResponsesIF.h @@ -1,19 +1,19 @@ -#ifndef FRAMEWORK_DEVICEHANDLERS_ACCEPTSDEVICERESPONSESIF_H_ -#define FRAMEWORK_DEVICEHANDLERS_ACCEPTSDEVICERESPONSESIF_H_ - -#include - -/** - * This interface is used by the device handler to send a device response - * to the queue ID, which is returned in the implemented abstract method. - */ -class AcceptsDeviceResponsesIF { -public: - /** - * Default empty virtual destructor. - */ - virtual ~AcceptsDeviceResponsesIF() {} - virtual MessageQueueId_t getDeviceQueue() = 0; -}; - -#endif /* FRAMEWORK_DEVICEHANDLERS_ACCEPTSDEVICERESPONSESIF_H_ */ +#ifndef FRAMEWORK_DEVICEHANDLERS_ACCEPTSDEVICERESPONSESIF_H_ +#define FRAMEWORK_DEVICEHANDLERS_ACCEPTSDEVICERESPONSESIF_H_ + +#include "../ipc/MessageQueueSenderIF.h" + +/** + * This interface is used by the device handler to send a device response + * to the queue ID, which is returned in the implemented abstract method. + */ +class AcceptsDeviceResponsesIF { +public: + /** + * Default empty virtual destructor. + */ + virtual ~AcceptsDeviceResponsesIF() {} + virtual MessageQueueId_t getDeviceQueue() = 0; +}; + +#endif /* FRAMEWORK_DEVICEHANDLERS_ACCEPTSDEVICERESPONSESIF_H_ */ diff --git a/devicehandlers/AssemblyBase.cpp b/devicehandlers/AssemblyBase.cpp index f5657327..c98a9f67 100644 --- a/devicehandlers/AssemblyBase.cpp +++ b/devicehandlers/AssemblyBase.cpp @@ -1,273 +1,273 @@ -#include - -AssemblyBase::AssemblyBase(object_id_t objectId, object_id_t parentId, - uint16_t commandQueueDepth) : - SubsystemBase(objectId, parentId, MODE_OFF, commandQueueDepth), - internalState(STATE_NONE), recoveryState(RECOVERY_IDLE), - recoveringDevice(childrenMap.end()), targetMode(MODE_OFF), - targetSubmode(SUBMODE_NONE) { - recoveryOffTimer.setTimeout(POWER_OFF_TIME_MS); -} - -AssemblyBase::~AssemblyBase() { -} - -ReturnValue_t AssemblyBase::handleCommandMessage(CommandMessage* message) { - return handleHealthReply(message); -} - -void AssemblyBase::performChildOperation() { - if (isInTransition()) { - handleChildrenTransition(); - } else { - handleChildrenChanged(); - } -} - -void AssemblyBase::startTransition(Mode_t mode, Submode_t submode) { - doStartTransition(mode, submode); - if (modeHelper.isForced()) { - triggerEvent(FORCING_MODE, mode, submode); - } else { - triggerEvent(CHANGING_MODE, mode, submode); - } -} - -void AssemblyBase::doStartTransition(Mode_t mode, Submode_t submode) { - targetMode = mode; - targetSubmode = submode; - internalState = STATE_SINGLE_STEP; - ReturnValue_t result = commandChildren(mode, submode); - if (result == NEED_SECOND_STEP) { - internalState = STATE_NEED_SECOND_STEP; - } -} - -bool AssemblyBase::isInTransition() { - return (internalState != STATE_NONE) || (recoveryState != RECOVERY_IDLE); -} - -bool AssemblyBase::handleChildrenChanged() { - if (childrenChangedMode) { - ReturnValue_t result = checkChildrenState(); - if (result != RETURN_OK) { - handleChildrenLostMode(result); - } - return true; - } else { - return handleChildrenChangedHealth(); - } -} - -void AssemblyBase::handleChildrenLostMode(ReturnValue_t result) { - triggerEvent(CANT_KEEP_MODE, mode, submode); - startTransition(MODE_OFF, SUBMODE_NONE); -} - -bool AssemblyBase::handleChildrenChangedHealth() { - auto iter = childrenMap.begin(); - for (; iter != childrenMap.end(); iter++) { - if (iter->second.healthChanged) { - iter->second.healthChanged = false; - break; - } - } - if (iter == childrenMap.end()) { - return false; - } - HealthState healthState = healthHelper.healthTable->getHealth(iter->first); - if (healthState == HasHealthIF::NEEDS_RECOVERY) { - triggerEvent(TRYING_RECOVERY); - recoveryState = RECOVERY_STARTED; - recoveringDevice = iter; - doStartTransition(targetMode, targetSubmode); - } else { - triggerEvent(CHILD_CHANGED_HEALTH); - doStartTransition(mode, submode); - } - if (modeHelper.isForced()) { - triggerEvent(FORCING_MODE, targetMode, targetSubmode); - } - return true; -} - -void AssemblyBase::handleChildrenTransition() { - if (commandsOutstanding <= 0) { - switch (internalState) { - case STATE_NEED_SECOND_STEP: - internalState = STATE_SECOND_STEP; - commandChildren(targetMode, targetSubmode); - return; - case STATE_OVERWRITE_HEALTH: { - internalState = STATE_SINGLE_STEP; - ReturnValue_t result = commandChildren(mode, submode); - if (result == NEED_SECOND_STEP) { - internalState = STATE_NEED_SECOND_STEP; - } - return; - } - case STATE_NONE: - //Valid state, used in recovery. - case STATE_SINGLE_STEP: - case STATE_SECOND_STEP: - if (checkAndHandleRecovery()) { - return; - } - break; - } - ReturnValue_t result = checkChildrenState(); - if (result == RETURN_OK) { - handleModeReached(); - } else { - handleModeTransitionFailed(result); - } - } -} - -void AssemblyBase::handleModeReached() { - internalState = STATE_NONE; - setMode(targetMode, targetSubmode); -} - -void AssemblyBase::handleModeTransitionFailed(ReturnValue_t result) { -//always accept transition to OFF, there is nothing we can do except sending an info event -//In theory this should never happen, but we would risk an infinite loop otherwise - if (targetMode == MODE_OFF) { - triggerEvent(CHILD_PROBLEMS, result); - internalState = STATE_NONE; - setMode(targetMode, targetSubmode); - } else { - if (handleChildrenChangedHealth()) { - //If any health change is pending, handle that first. - return; - } - triggerEvent(MODE_TRANSITION_FAILED, result); - startTransition(MODE_OFF, SUBMODE_NONE); - } -} - -void AssemblyBase::sendHealthCommand(MessageQueueId_t sendTo, - HealthState health) { - CommandMessage command; - HealthMessage::setHealthMessage(&command, HealthMessage::HEALTH_SET, - health); - if (commandQueue->sendMessage(sendTo, &command) == RETURN_OK) { - commandsOutstanding++; - } -} - -ReturnValue_t AssemblyBase::checkChildrenState() { - if (targetMode == MODE_OFF) { - return checkChildrenStateOff(); - } else { - return checkChildrenStateOn(targetMode, targetSubmode); - } -} - -ReturnValue_t AssemblyBase::checkChildrenStateOff() { - for (const auto& childIter: childrenMap) { - if (checkChildOff(childIter.first) != RETURN_OK) { - return NOT_ENOUGH_CHILDREN_IN_CORRECT_STATE; - } - } - return RETURN_OK; -} - -ReturnValue_t AssemblyBase::checkChildOff(uint32_t objectId) { - ChildInfo childInfo = childrenMap.find(objectId)->second; - if (healthHelper.healthTable->isCommandable(objectId)) { - if (childInfo.submode != SUBMODE_NONE) { - return RETURN_FAILED; - } else { - if ((childInfo.mode != MODE_OFF) - && (childInfo.mode != DeviceHandlerIF::MODE_ERROR_ON)) { - return RETURN_FAILED; - } - } - } - return RETURN_OK; -} - -ReturnValue_t AssemblyBase::checkModeCommand(Mode_t mode, Submode_t submode, - uint32_t* msToReachTheMode) { - -//always accept transition to OFF - if (mode == MODE_OFF) { - if (submode != SUBMODE_NONE) { - return INVALID_SUBMODE; - } - return RETURN_OK; - } - - if ((mode != MODE_ON) && (mode != DeviceHandlerIF::MODE_NORMAL)) { - return INVALID_MODE; - } - - if (internalState != STATE_NONE) { - return IN_TRANSITION; - } - - return isModeCombinationValid(mode, submode); -} - -ReturnValue_t AssemblyBase::handleHealthReply(CommandMessage* message) { - if (message->getCommand() == HealthMessage::HEALTH_INFO) { - HealthState health = HealthMessage::getHealth(message); - if (health != EXTERNAL_CONTROL) { - updateChildChangedHealth(message->getSender(), true); - } - return RETURN_OK; - } - if (message->getCommand() == HealthMessage::REPLY_HEALTH_SET - || (message->getCommand() == CommandMessage::REPLY_REJECTED - && message->getParameter2() == HealthMessage::HEALTH_SET)) { - if (isInTransition()) { - commandsOutstanding--; - } - return RETURN_OK; - } - return RETURN_FAILED; -} - -bool AssemblyBase::checkAndHandleRecovery() { - switch (recoveryState) { - case RECOVERY_STARTED: - recoveryState = RECOVERY_WAIT; - recoveryOffTimer.resetTimer(); - return true; - case RECOVERY_WAIT: - if (recoveryOffTimer.isBusy()) { - return true; - } - triggerEvent(RECOVERY_STEP, 0); - sendHealthCommand(recoveringDevice->second.commandQueue, HEALTHY); - internalState = STATE_NONE; - recoveryState = RECOVERY_ONGOING; - //Don't check state! - return true; - case RECOVERY_ONGOING: - triggerEvent(RECOVERY_STEP, 1); - recoveryState = RECOVERY_ONGOING_2; - recoveringDevice->second.healthChanged = false; - //Device should be healthy again, so restart a transition. - //Might be including second step, but that's already handled. - doStartTransition(targetMode, targetSubmode); - return true; - case RECOVERY_ONGOING_2: - triggerEvent(RECOVERY_DONE); - //Now we're through, but not sure if it was successful. - recoveryState = RECOVERY_IDLE; - return false; - case RECOVERY_IDLE: - default: - return false; - } -} - -void AssemblyBase::overwriteDeviceHealth(object_id_t objectId, - HasHealthIF::HealthState oldHealth) { - triggerEvent(OVERWRITING_HEALTH, objectId, oldHealth); - internalState = STATE_OVERWRITE_HEALTH; - modeHelper.setForced(true); - sendHealthCommand(childrenMap[objectId].commandQueue, EXTERNAL_CONTROL); -} +#include "../devicehandlers/AssemblyBase.h" + +AssemblyBase::AssemblyBase(object_id_t objectId, object_id_t parentId, + uint16_t commandQueueDepth) : + SubsystemBase(objectId, parentId, MODE_OFF, commandQueueDepth), + internalState(STATE_NONE), recoveryState(RECOVERY_IDLE), + recoveringDevice(childrenMap.end()), targetMode(MODE_OFF), + targetSubmode(SUBMODE_NONE) { + recoveryOffTimer.setTimeout(POWER_OFF_TIME_MS); +} + +AssemblyBase::~AssemblyBase() { +} + +ReturnValue_t AssemblyBase::handleCommandMessage(CommandMessage* message) { + return handleHealthReply(message); +} + +void AssemblyBase::performChildOperation() { + if (isInTransition()) { + handleChildrenTransition(); + } else { + handleChildrenChanged(); + } +} + +void AssemblyBase::startTransition(Mode_t mode, Submode_t submode) { + doStartTransition(mode, submode); + if (modeHelper.isForced()) { + triggerEvent(FORCING_MODE, mode, submode); + } else { + triggerEvent(CHANGING_MODE, mode, submode); + } +} + +void AssemblyBase::doStartTransition(Mode_t mode, Submode_t submode) { + targetMode = mode; + targetSubmode = submode; + internalState = STATE_SINGLE_STEP; + ReturnValue_t result = commandChildren(mode, submode); + if (result == NEED_SECOND_STEP) { + internalState = STATE_NEED_SECOND_STEP; + } +} + +bool AssemblyBase::isInTransition() { + return (internalState != STATE_NONE) || (recoveryState != RECOVERY_IDLE); +} + +bool AssemblyBase::handleChildrenChanged() { + if (childrenChangedMode) { + ReturnValue_t result = checkChildrenState(); + if (result != RETURN_OK) { + handleChildrenLostMode(result); + } + return true; + } else { + return handleChildrenChangedHealth(); + } +} + +void AssemblyBase::handleChildrenLostMode(ReturnValue_t result) { + triggerEvent(CANT_KEEP_MODE, mode, submode); + startTransition(MODE_OFF, SUBMODE_NONE); +} + +bool AssemblyBase::handleChildrenChangedHealth() { + auto iter = childrenMap.begin(); + for (; iter != childrenMap.end(); iter++) { + if (iter->second.healthChanged) { + iter->second.healthChanged = false; + break; + } + } + if (iter == childrenMap.end()) { + return false; + } + HealthState healthState = healthHelper.healthTable->getHealth(iter->first); + if (healthState == HasHealthIF::NEEDS_RECOVERY) { + triggerEvent(TRYING_RECOVERY); + recoveryState = RECOVERY_STARTED; + recoveringDevice = iter; + doStartTransition(targetMode, targetSubmode); + } else { + triggerEvent(CHILD_CHANGED_HEALTH); + doStartTransition(mode, submode); + } + if (modeHelper.isForced()) { + triggerEvent(FORCING_MODE, targetMode, targetSubmode); + } + return true; +} + +void AssemblyBase::handleChildrenTransition() { + if (commandsOutstanding <= 0) { + switch (internalState) { + case STATE_NEED_SECOND_STEP: + internalState = STATE_SECOND_STEP; + commandChildren(targetMode, targetSubmode); + return; + case STATE_OVERWRITE_HEALTH: { + internalState = STATE_SINGLE_STEP; + ReturnValue_t result = commandChildren(mode, submode); + if (result == NEED_SECOND_STEP) { + internalState = STATE_NEED_SECOND_STEP; + } + return; + } + case STATE_NONE: + //Valid state, used in recovery. + case STATE_SINGLE_STEP: + case STATE_SECOND_STEP: + if (checkAndHandleRecovery()) { + return; + } + break; + } + ReturnValue_t result = checkChildrenState(); + if (result == RETURN_OK) { + handleModeReached(); + } else { + handleModeTransitionFailed(result); + } + } +} + +void AssemblyBase::handleModeReached() { + internalState = STATE_NONE; + setMode(targetMode, targetSubmode); +} + +void AssemblyBase::handleModeTransitionFailed(ReturnValue_t result) { +//always accept transition to OFF, there is nothing we can do except sending an info event +//In theory this should never happen, but we would risk an infinite loop otherwise + if (targetMode == MODE_OFF) { + triggerEvent(CHILD_PROBLEMS, result); + internalState = STATE_NONE; + setMode(targetMode, targetSubmode); + } else { + if (handleChildrenChangedHealth()) { + //If any health change is pending, handle that first. + return; + } + triggerEvent(MODE_TRANSITION_FAILED, result); + startTransition(MODE_OFF, SUBMODE_NONE); + } +} + +void AssemblyBase::sendHealthCommand(MessageQueueId_t sendTo, + HealthState health) { + CommandMessage command; + HealthMessage::setHealthMessage(&command, HealthMessage::HEALTH_SET, + health); + if (commandQueue->sendMessage(sendTo, &command) == RETURN_OK) { + commandsOutstanding++; + } +} + +ReturnValue_t AssemblyBase::checkChildrenState() { + if (targetMode == MODE_OFF) { + return checkChildrenStateOff(); + } else { + return checkChildrenStateOn(targetMode, targetSubmode); + } +} + +ReturnValue_t AssemblyBase::checkChildrenStateOff() { + for (const auto& childIter: childrenMap) { + if (checkChildOff(childIter.first) != RETURN_OK) { + return NOT_ENOUGH_CHILDREN_IN_CORRECT_STATE; + } + } + return RETURN_OK; +} + +ReturnValue_t AssemblyBase::checkChildOff(uint32_t objectId) { + ChildInfo childInfo = childrenMap.find(objectId)->second; + if (healthHelper.healthTable->isCommandable(objectId)) { + if (childInfo.submode != SUBMODE_NONE) { + return RETURN_FAILED; + } else { + if ((childInfo.mode != MODE_OFF) + && (childInfo.mode != DeviceHandlerIF::MODE_ERROR_ON)) { + return RETURN_FAILED; + } + } + } + return RETURN_OK; +} + +ReturnValue_t AssemblyBase::checkModeCommand(Mode_t mode, Submode_t submode, + uint32_t* msToReachTheMode) { + +//always accept transition to OFF + if (mode == MODE_OFF) { + if (submode != SUBMODE_NONE) { + return INVALID_SUBMODE; + } + return RETURN_OK; + } + + if ((mode != MODE_ON) && (mode != DeviceHandlerIF::MODE_NORMAL)) { + return INVALID_MODE; + } + + if (internalState != STATE_NONE) { + return IN_TRANSITION; + } + + return isModeCombinationValid(mode, submode); +} + +ReturnValue_t AssemblyBase::handleHealthReply(CommandMessage* message) { + if (message->getCommand() == HealthMessage::HEALTH_INFO) { + HealthState health = HealthMessage::getHealth(message); + if (health != EXTERNAL_CONTROL) { + updateChildChangedHealth(message->getSender(), true); + } + return RETURN_OK; + } + if (message->getCommand() == HealthMessage::REPLY_HEALTH_SET + || (message->getCommand() == CommandMessage::REPLY_REJECTED + && message->getParameter2() == HealthMessage::HEALTH_SET)) { + if (isInTransition()) { + commandsOutstanding--; + } + return RETURN_OK; + } + return RETURN_FAILED; +} + +bool AssemblyBase::checkAndHandleRecovery() { + switch (recoveryState) { + case RECOVERY_STARTED: + recoveryState = RECOVERY_WAIT; + recoveryOffTimer.resetTimer(); + return true; + case RECOVERY_WAIT: + if (recoveryOffTimer.isBusy()) { + return true; + } + triggerEvent(RECOVERY_STEP, 0); + sendHealthCommand(recoveringDevice->second.commandQueue, HEALTHY); + internalState = STATE_NONE; + recoveryState = RECOVERY_ONGOING; + //Don't check state! + return true; + case RECOVERY_ONGOING: + triggerEvent(RECOVERY_STEP, 1); + recoveryState = RECOVERY_ONGOING_2; + recoveringDevice->second.healthChanged = false; + //Device should be healthy again, so restart a transition. + //Might be including second step, but that's already handled. + doStartTransition(targetMode, targetSubmode); + return true; + case RECOVERY_ONGOING_2: + triggerEvent(RECOVERY_DONE); + //Now we're through, but not sure if it was successful. + recoveryState = RECOVERY_IDLE; + return false; + case RECOVERY_IDLE: + default: + return false; + } +} + +void AssemblyBase::overwriteDeviceHealth(object_id_t objectId, + HasHealthIF::HealthState oldHealth) { + triggerEvent(OVERWRITING_HEALTH, objectId, oldHealth); + internalState = STATE_OVERWRITE_HEALTH; + modeHelper.setForced(true); + sendHealthCommand(childrenMap[objectId].commandQueue, EXTERNAL_CONTROL); +} diff --git a/devicehandlers/AssemblyBase.h b/devicehandlers/AssemblyBase.h index d0dc868c..7c66b21d 100644 --- a/devicehandlers/AssemblyBase.h +++ b/devicehandlers/AssemblyBase.h @@ -1,163 +1,163 @@ -#ifndef FRAMEWORK_DEVICEHANDLERS_ASSEMBLYBASE_H_ -#define FRAMEWORK_DEVICEHANDLERS_ASSEMBLYBASE_H_ - -#include -#include -#include - -/** - * @brief Base class to implement reconfiguration and failure handling for - * redundant devices by monitoring their modes health states. - * @details - * Documentation: Dissertation Baetz p.156, 157. - * - * This class reduces the complexity of controller components which would - * otherwise be needed for the handling of redundant devices. - * - * The template class monitors mode and health state of its children - * and checks availability of devices on every detected change. - * AssemblyBase does not implement any redundancy logic by itself, but provides - * adaptation points for implementations to do so. Since most monitoring - * activities rely on mode and health state only and are therefore - * generic, it is sufficient for subclasses to provide: - * - * 1. check logic when active-> checkChildrenStateOn - * 2. transition logic to change the mode -> commandChildren - * - */ -class AssemblyBase: public SubsystemBase { -public: - static const uint8_t INTERFACE_ID = CLASS_ID::ASSEMBLY_BASE; - static const ReturnValue_t NEED_SECOND_STEP = MAKE_RETURN_CODE(0x01); - static const ReturnValue_t NEED_TO_RECONFIGURE = MAKE_RETURN_CODE(0x02); - static const ReturnValue_t MODE_FALLBACK = MAKE_RETURN_CODE(0x03); - static const ReturnValue_t CHILD_NOT_COMMANDABLE = MAKE_RETURN_CODE(0x04); - static const ReturnValue_t NEED_TO_CHANGE_HEALTH = MAKE_RETURN_CODE(0x05); - static const ReturnValue_t NOT_ENOUGH_CHILDREN_IN_CORRECT_STATE = - MAKE_RETURN_CODE(0xa1); - - AssemblyBase(object_id_t objectId, object_id_t parentId, - uint16_t commandQueueDepth = 8); - virtual ~AssemblyBase(); - -protected: - - // SHOULDDO: Change that OVERWRITE_HEALTH may be returned - // (or return internalState directly?) - /** - * Command children to reach [mode,submode] combination - * Can be done by setting #commandsOutstanding correctly, - * or using executeTable() - * @param mode - * @param submode - * @return - * - @c RETURN_OK if ok - * - @c NEED_SECOND_STEP if children need to be commanded again - */ - virtual ReturnValue_t commandChildren(Mode_t mode, Submode_t submode) = 0; - - /** - * Check whether desired assembly mode was achieved by checking the modes - * or/and health states of child device handlers. - * The assembly template class will also call this function if a health - * or mode change of a child device handler was detected. - * @param wantedMode - * @param wantedSubmode - * @return - */ - virtual ReturnValue_t checkChildrenStateOn(Mode_t wantedMode, - Submode_t wantedSubmode) = 0; - - virtual ReturnValue_t isModeCombinationValid(Mode_t mode, - Submode_t submode) = 0; - - enum InternalState { - STATE_NONE, - STATE_OVERWRITE_HEALTH, - STATE_NEED_SECOND_STEP, - STATE_SINGLE_STEP, - STATE_SECOND_STEP, - } internalState; - - enum RecoveryState { - RECOVERY_IDLE, - RECOVERY_STARTED, - RECOVERY_ONGOING, - RECOVERY_ONGOING_2, - RECOVERY_WAIT - } recoveryState; //!< Indicates if one of the children requested a recovery. - ChildrenMap::iterator recoveringDevice; - - /** - * the mode the current transition is trying to achieve. - * Can be different from the modehelper.commandedMode! - */ - Mode_t targetMode; - - /** - * the submode the current transition is trying to achieve. - * Can be different from the modehelper.commandedSubmode! - */ - Submode_t targetSubmode; - - Countdown recoveryOffTimer; - - static const uint32_t POWER_OFF_TIME_MS = 1000; - - virtual ReturnValue_t handleCommandMessage(CommandMessage *message); - - virtual ReturnValue_t handleHealthReply(CommandMessage *message); - - virtual void performChildOperation(); - - bool handleChildrenChanged(); - - /** - * This method is called if the children changed its mode in a way that - * the current mode can't be kept. - * Default behavior is to go to MODE_OFF. - * @param result The failure code which was returned by checkChildrenState. - */ - virtual void handleChildrenLostMode(ReturnValue_t result); - - bool handleChildrenChangedHealth(); - - virtual void handleChildrenTransition(); - - ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, - uint32_t *msToReachTheMode); - - virtual void startTransition(Mode_t mode, Submode_t submode); - - virtual void doStartTransition(Mode_t mode, Submode_t submode); - - virtual bool isInTransition(); - - virtual void handleModeReached(); - - virtual void handleModeTransitionFailed(ReturnValue_t result); - - void sendHealthCommand(MessageQueueId_t sendTo, HealthState health); - - virtual ReturnValue_t checkChildrenStateOff(); - - ReturnValue_t checkChildrenState(); - - virtual ReturnValue_t checkChildOff(uint32_t objectId); - - /** - * Manages recovery of a device - * @return true if recovery is still ongoing, false else. - */ - bool checkAndHandleRecovery(); - - /** - * Helper method to overwrite health state of one of the children. - * Also sets state to STATE_OVERWRITE_HEATH. - * @param objectId Must be a registered child. - */ - void overwriteDeviceHealth(object_id_t objectId, HasHealthIF::HealthState oldHealth); - -}; - -#endif /* FRAMEWORK_DEVICEHANDLERS_ASSEMBLYBASE_H_ */ +#ifndef FRAMEWORK_DEVICEHANDLERS_ASSEMBLYBASE_H_ +#define FRAMEWORK_DEVICEHANDLERS_ASSEMBLYBASE_H_ + +#include "../container/FixedArrayList.h" +#include "../devicehandlers/DeviceHandlerBase.h" +#include "../subsystem/SubsystemBase.h" + +/** + * @brief Base class to implement reconfiguration and failure handling for + * redundant devices by monitoring their modes health states. + * @details + * Documentation: Dissertation Baetz p.156, 157. + * + * This class reduces the complexity of controller components which would + * otherwise be needed for the handling of redundant devices. + * + * The template class monitors mode and health state of its children + * and checks availability of devices on every detected change. + * AssemblyBase does not implement any redundancy logic by itself, but provides + * adaptation points for implementations to do so. Since most monitoring + * activities rely on mode and health state only and are therefore + * generic, it is sufficient for subclasses to provide: + * + * 1. check logic when active-> checkChildrenStateOn + * 2. transition logic to change the mode -> commandChildren + * + */ +class AssemblyBase: public SubsystemBase { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::ASSEMBLY_BASE; + static const ReturnValue_t NEED_SECOND_STEP = MAKE_RETURN_CODE(0x01); + static const ReturnValue_t NEED_TO_RECONFIGURE = MAKE_RETURN_CODE(0x02); + static const ReturnValue_t MODE_FALLBACK = MAKE_RETURN_CODE(0x03); + static const ReturnValue_t CHILD_NOT_COMMANDABLE = MAKE_RETURN_CODE(0x04); + static const ReturnValue_t NEED_TO_CHANGE_HEALTH = MAKE_RETURN_CODE(0x05); + static const ReturnValue_t NOT_ENOUGH_CHILDREN_IN_CORRECT_STATE = + MAKE_RETURN_CODE(0xa1); + + AssemblyBase(object_id_t objectId, object_id_t parentId, + uint16_t commandQueueDepth = 8); + virtual ~AssemblyBase(); + +protected: + + // SHOULDDO: Change that OVERWRITE_HEALTH may be returned + // (or return internalState directly?) + /** + * Command children to reach [mode,submode] combination + * Can be done by setting #commandsOutstanding correctly, + * or using executeTable() + * @param mode + * @param submode + * @return + * - @c RETURN_OK if ok + * - @c NEED_SECOND_STEP if children need to be commanded again + */ + virtual ReturnValue_t commandChildren(Mode_t mode, Submode_t submode) = 0; + + /** + * Check whether desired assembly mode was achieved by checking the modes + * or/and health states of child device handlers. + * The assembly template class will also call this function if a health + * or mode change of a child device handler was detected. + * @param wantedMode + * @param wantedSubmode + * @return + */ + virtual ReturnValue_t checkChildrenStateOn(Mode_t wantedMode, + Submode_t wantedSubmode) = 0; + + virtual ReturnValue_t isModeCombinationValid(Mode_t mode, + Submode_t submode) = 0; + + enum InternalState { + STATE_NONE, + STATE_OVERWRITE_HEALTH, + STATE_NEED_SECOND_STEP, + STATE_SINGLE_STEP, + STATE_SECOND_STEP, + } internalState; + + enum RecoveryState { + RECOVERY_IDLE, + RECOVERY_STARTED, + RECOVERY_ONGOING, + RECOVERY_ONGOING_2, + RECOVERY_WAIT + } recoveryState; //!< Indicates if one of the children requested a recovery. + ChildrenMap::iterator recoveringDevice; + + /** + * the mode the current transition is trying to achieve. + * Can be different from the modehelper.commandedMode! + */ + Mode_t targetMode; + + /** + * the submode the current transition is trying to achieve. + * Can be different from the modehelper.commandedSubmode! + */ + Submode_t targetSubmode; + + Countdown recoveryOffTimer; + + static const uint32_t POWER_OFF_TIME_MS = 1000; + + virtual ReturnValue_t handleCommandMessage(CommandMessage *message); + + virtual ReturnValue_t handleHealthReply(CommandMessage *message); + + virtual void performChildOperation(); + + bool handleChildrenChanged(); + + /** + * This method is called if the children changed its mode in a way that + * the current mode can't be kept. + * Default behavior is to go to MODE_OFF. + * @param result The failure code which was returned by checkChildrenState. + */ + virtual void handleChildrenLostMode(ReturnValue_t result); + + bool handleChildrenChangedHealth(); + + virtual void handleChildrenTransition(); + + ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, + uint32_t *msToReachTheMode); + + virtual void startTransition(Mode_t mode, Submode_t submode); + + virtual void doStartTransition(Mode_t mode, Submode_t submode); + + virtual bool isInTransition(); + + virtual void handleModeReached(); + + virtual void handleModeTransitionFailed(ReturnValue_t result); + + void sendHealthCommand(MessageQueueId_t sendTo, HealthState health); + + virtual ReturnValue_t checkChildrenStateOff(); + + ReturnValue_t checkChildrenState(); + + virtual ReturnValue_t checkChildOff(uint32_t objectId); + + /** + * Manages recovery of a device + * @return true if recovery is still ongoing, false else. + */ + bool checkAndHandleRecovery(); + + /** + * Helper method to overwrite health state of one of the children. + * Also sets state to STATE_OVERWRITE_HEATH. + * @param objectId Must be a registered child. + */ + void overwriteDeviceHealth(object_id_t objectId, HasHealthIF::HealthState oldHealth); + +}; + +#endif /* FRAMEWORK_DEVICEHANDLERS_ASSEMBLYBASE_H_ */ diff --git a/devicehandlers/ChildHandlerBase.cpp b/devicehandlers/ChildHandlerBase.cpp index 2e4428e5..acc1b5a0 100644 --- a/devicehandlers/ChildHandlerBase.cpp +++ b/devicehandlers/ChildHandlerBase.cpp @@ -1,47 +1,47 @@ -#include -#include -#include - -ChildHandlerBase::ChildHandlerBase(object_id_t setObjectId, - object_id_t deviceCommunication, CookieIF * cookie, - object_id_t hkDestination, uint32_t thermalStatePoolId, - uint32_t thermalRequestPoolId, - object_id_t parent, - FailureIsolationBase* customFdir, size_t cmdQueueSize) : - DeviceHandlerBase(setObjectId, deviceCommunication, cookie, - (customFdir == nullptr? &childHandlerFdir : customFdir), - cmdQueueSize), - parentId(parent), childHandlerFdir(setObjectId) { - this->setHkDestination(hkDestination); - this->setThermalStateRequestPoolIds(thermalStatePoolId, - thermalRequestPoolId); - -} - -ChildHandlerBase::~ChildHandlerBase() { -} - -ReturnValue_t ChildHandlerBase::initialize() { - ReturnValue_t result = DeviceHandlerBase::initialize(); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - MessageQueueId_t parentQueue = 0; - - if (parentId != objects::NO_OBJECT) { - SubsystemBase *parent = objectManager->get(parentId); - if (parent == NULL) { - return RETURN_FAILED; - } - parentQueue = parent->getCommandQueue(); - - parent->registerChild(getObjectId()); - } - - healthHelper.setParentQueue(parentQueue); - - modeHelper.setParentQueue(parentQueue); - - return RETURN_OK; -} +#include "../subsystem/SubsystemBase.h" +#include "../devicehandlers/ChildHandlerBase.h" +#include "../subsystem/SubsystemBase.h" + +ChildHandlerBase::ChildHandlerBase(object_id_t setObjectId, + object_id_t deviceCommunication, CookieIF * cookie, + object_id_t hkDestination, uint32_t thermalStatePoolId, + uint32_t thermalRequestPoolId, + object_id_t parent, + FailureIsolationBase* customFdir, size_t cmdQueueSize) : + DeviceHandlerBase(setObjectId, deviceCommunication, cookie, + (customFdir == nullptr? &childHandlerFdir : customFdir), + cmdQueueSize), + parentId(parent), childHandlerFdir(setObjectId) { + this->setHkDestination(hkDestination); + this->setThermalStateRequestPoolIds(thermalStatePoolId, + thermalRequestPoolId); + +} + +ChildHandlerBase::~ChildHandlerBase() { +} + +ReturnValue_t ChildHandlerBase::initialize() { + ReturnValue_t result = DeviceHandlerBase::initialize(); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + MessageQueueId_t parentQueue = 0; + + if (parentId != objects::NO_OBJECT) { + SubsystemBase *parent = objectManager->get(parentId); + if (parent == NULL) { + return RETURN_FAILED; + } + parentQueue = parent->getCommandQueue(); + + parent->registerChild(getObjectId()); + } + + healthHelper.setParentQueue(parentQueue); + + modeHelper.setParentQueue(parentQueue); + + return RETURN_OK; +} diff --git a/devicehandlers/ChildHandlerBase.h b/devicehandlers/ChildHandlerBase.h index c8ac9541..625955f0 100644 --- a/devicehandlers/ChildHandlerBase.h +++ b/devicehandlers/ChildHandlerBase.h @@ -1,24 +1,24 @@ -#ifndef PAYLOADHANDLERBASE_H_ -#define PAYLOADHANDLERBASE_H_ - -#include -#include - -class ChildHandlerBase: public DeviceHandlerBase { -public: - ChildHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication, - CookieIF * cookie, object_id_t hkDestination, - uint32_t thermalStatePoolId, uint32_t thermalRequestPoolId, - object_id_t parent = objects::NO_OBJECT, - FailureIsolationBase* customFdir = nullptr, size_t cmdQueueSize = 20); - virtual ~ChildHandlerBase(); - - virtual ReturnValue_t initialize(); - -protected: - const uint32_t parentId; - ChildHandlerFDIR childHandlerFdir; - -}; - -#endif /* PAYLOADHANDLERBASE_H_ */ +#ifndef PAYLOADHANDLERBASE_H_ +#define PAYLOADHANDLERBASE_H_ + +#include "../devicehandlers/ChildHandlerFDIR.h" +#include "../devicehandlers/DeviceHandlerBase.h" + +class ChildHandlerBase: public DeviceHandlerBase { +public: + ChildHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication, + CookieIF * cookie, object_id_t hkDestination, + uint32_t thermalStatePoolId, uint32_t thermalRequestPoolId, + object_id_t parent = objects::NO_OBJECT, + FailureIsolationBase* customFdir = nullptr, size_t cmdQueueSize = 20); + virtual ~ChildHandlerBase(); + + virtual ReturnValue_t initialize(); + +protected: + const uint32_t parentId; + ChildHandlerFDIR childHandlerFdir; + +}; + +#endif /* PAYLOADHANDLERBASE_H_ */ diff --git a/devicehandlers/ChildHandlerFDIR.cpp b/devicehandlers/ChildHandlerFDIR.cpp index 1bba47fe..bab5a7e5 100644 --- a/devicehandlers/ChildHandlerFDIR.cpp +++ b/devicehandlers/ChildHandlerFDIR.cpp @@ -1,10 +1,10 @@ -#include - -ChildHandlerFDIR::ChildHandlerFDIR(object_id_t owner, object_id_t faultTreeParent, uint32_t recoveryCount) : - DeviceHandlerFailureIsolation(owner, faultTreeParent) { - recoveryCounter.setFailureThreshold(recoveryCount); -} - -ChildHandlerFDIR::~ChildHandlerFDIR() { -} - +#include "../devicehandlers/ChildHandlerFDIR.h" + +ChildHandlerFDIR::ChildHandlerFDIR(object_id_t owner, object_id_t faultTreeParent, uint32_t recoveryCount) : + DeviceHandlerFailureIsolation(owner, faultTreeParent) { + recoveryCounter.setFailureThreshold(recoveryCount); +} + +ChildHandlerFDIR::~ChildHandlerFDIR() { +} + diff --git a/devicehandlers/ChildHandlerFDIR.h b/devicehandlers/ChildHandlerFDIR.h index 7df9d238..83f79a63 100644 --- a/devicehandlers/ChildHandlerFDIR.h +++ b/devicehandlers/ChildHandlerFDIR.h @@ -1,20 +1,20 @@ -#ifndef FRAMEWORK_DEVICEHANDLERS_CHILDHANDLERFDIR_H_ -#define FRAMEWORK_DEVICEHANDLERS_CHILDHANDLERFDIR_H_ - -#include - -/** - * Very simple extension to normal FDIR. - * Does not have a default fault tree parent and - * allows to make the recovery count settable to 0. - */ -class ChildHandlerFDIR: public DeviceHandlerFailureIsolation { -public: - ChildHandlerFDIR(object_id_t owner, object_id_t faultTreeParent = - NO_FAULT_TREE_PARENT, uint32_t recoveryCount = 0); - virtual ~ChildHandlerFDIR(); -protected: - static const object_id_t NO_FAULT_TREE_PARENT = 0; -}; - -#endif /* FRAMEWORK_DEVICEHANDLERS_CHILDHANDLERFDIR_H_ */ +#ifndef FRAMEWORK_DEVICEHANDLERS_CHILDHANDLERFDIR_H_ +#define FRAMEWORK_DEVICEHANDLERS_CHILDHANDLERFDIR_H_ + +#include "../devicehandlers/DeviceHandlerFailureIsolation.h" + +/** + * Very simple extension to normal FDIR. + * Does not have a default fault tree parent and + * allows to make the recovery count settable to 0. + */ +class ChildHandlerFDIR: public DeviceHandlerFailureIsolation { +public: + ChildHandlerFDIR(object_id_t owner, object_id_t faultTreeParent = + NO_FAULT_TREE_PARENT, uint32_t recoveryCount = 0); + virtual ~ChildHandlerFDIR(); +protected: + static const object_id_t NO_FAULT_TREE_PARENT = 0; +}; + +#endif /* FRAMEWORK_DEVICEHANDLERS_CHILDHANDLERFDIR_H_ */ diff --git a/devicehandlers/CommunicationMessage.cpp b/devicehandlers/CommunicationMessage.cpp index a80e7de1..aacf5580 100644 --- a/devicehandlers/CommunicationMessage.cpp +++ b/devicehandlers/CommunicationMessage.cpp @@ -4,8 +4,8 @@ * @date 28.02.2020 */ -#include -#include +#include "../devicehandlers/CommunicationMessage.h" +#include "../serviceinterface/ServiceInterfaceStream.h" #include CommunicationMessage::CommunicationMessage(): uninitialized(true) { diff --git a/devicehandlers/CommunicationMessage.h b/devicehandlers/CommunicationMessage.h index 95266319..a31e270c 100644 --- a/devicehandlers/CommunicationMessage.h +++ b/devicehandlers/CommunicationMessage.h @@ -6,11 +6,11 @@ #ifndef FRAMEWORK_DEVICEHANDLERS_COMMUNICATIONMESSAGE_H_ #define FRAMEWORK_DEVICEHANDLERS_COMMUNICATIONMESSAGE_H_ -#include +#include "../devicehandlers/CommunicationMessage.h" -#include -#include -#include +#include "../ipc/MessageQueueMessage.h" +#include "../storagemanager/StorageManagerIF.h" +#include "../devicehandlers/DeviceHandlerBase.h" /** * @brief Message type to send larger messages diff --git a/devicehandlers/DeviceCommunicationIF.h b/devicehandlers/DeviceCommunicationIF.h index a2662d46..cbff5411 100644 --- a/devicehandlers/DeviceCommunicationIF.h +++ b/devicehandlers/DeviceCommunicationIF.h @@ -1,127 +1,127 @@ -#ifndef FRAMEWORK_DEVICES_DEVICECOMMUNICATIONIF_H_ -#define FRAMEWORK_DEVICES_DEVICECOMMUNICATIONIF_H_ - -#include -#include -#include -/** - * @defgroup interfaces Interfaces - * @brief Interfaces for flight software objects - */ - -/** - * @defgroup comm Communication - * @brief Communication software components. - */ - -/** - * @brief This is an interface to decouple device communication from - * the device handler to allow reuse of these components. - * @details - * Documentation: Dissertation Baetz p.138. - * It works with the assumption that received data is polled by a component. - * There are four generic steps of device communication: - * - * 1. Send data to a device - * 2. Get acknowledgement for sending - * 3. Request reading data from a device - * 4. Read received data - * - * To identify different connection over a single interface can return - * so-called cookies to components. - * The CommunicationMessage message type can be used to extend the - * functionality of the ComIF if a separate polling task is required. - * @ingroup interfaces - * @ingroup comm - */ -class DeviceCommunicationIF: public HasReturnvaluesIF { -public: - static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_COMMUNICATION_IF; - - //! This is returned in readReceivedMessage() if no reply was reived. - static const ReturnValue_t NO_REPLY_RECEIVED = MAKE_RETURN_CODE(0x01); - - //! General protocol error. Define more concrete errors in child handler - static const ReturnValue_t PROTOCOL_ERROR = MAKE_RETURN_CODE(0x02); - //! If cookie is a null pointer - static const ReturnValue_t NULLPOINTER = MAKE_RETURN_CODE(0x03); - static const ReturnValue_t INVALID_COOKIE_TYPE = MAKE_RETURN_CODE(0x04); - // is this needed if there is no open/close call? - static const ReturnValue_t NOT_ACTIVE = MAKE_RETURN_CODE(0x05); - static const ReturnValue_t TOO_MUCH_DATA = MAKE_RETURN_CODE(0x06); - - virtual ~DeviceCommunicationIF() {} - - /** - * @brief Device specific initialization, using the cookie. - * @details - * The cookie is already prepared in the factory. If the communication - * interface needs to be set up in some way and requires cookie information, - * this can be performed in this function, which is called on device handler - * initialization. - * @param cookie - * @return - * - @c RETURN_OK if initialization was successfull - * - Everything else triggers failure event with returnvalue as parameter 1 - */ - virtual ReturnValue_t initializeInterface(CookieIF * cookie) = 0; - - /** - * Called by DHB in the SEND_WRITE doSendWrite(). - * This function is used to send data to the physical device - * by implementing and calling related drivers or wrapper functions. - * @param cookie - * @param data - * @param len If this is 0, nothing shall be sent. - * @return - * - @c RETURN_OK for successfull send - * - Everything else triggers failure event with returnvalue as parameter 1 - */ - virtual ReturnValue_t sendMessage(CookieIF *cookie, - const uint8_t * sendData, size_t sendLen) = 0; - - /** - * Called by DHB in the GET_WRITE doGetWrite(). - * Get send confirmation that the data in sendMessage() was sent successfully. - * @param cookie - * @return - @c RETURN_OK if data was sent successfull - * - Everything else triggers falure event with - * returnvalue as parameter 1 - */ - virtual ReturnValue_t getSendSuccess(CookieIF *cookie) = 0; - - /** - * Called by DHB in the SEND_WRITE doSendRead(). - * It is assumed that it is always possible to request a reply - * from a device. If a requestLen of 0 is supplied, no reply was enabled - * and communication specific action should be taken (e.g. read nothing - * or read everything). - * - * @param cookie - * @param requestLen Size of data to read - * @return - @c RETURN_OK to confirm the request for data has been sent. - * - Everything else triggers failure event with - * returnvalue as parameter 1 - */ - virtual ReturnValue_t requestReceiveMessage(CookieIF *cookie, - size_t requestLen) = 0; - - /** - * Called by DHB in the GET_WRITE doGetRead(). - * This function is used to receive data from the physical device - * by implementing and calling related drivers or wrapper functions. - * @param cookie - * @param buffer [out] Set reply here (by using *buffer = ...) - * @param size [out] size pointer to set (by using *size = ...). - * Set to 0 if no reply was received - * @return - @c RETURN_OK for successfull receive - * - @c NO_REPLY_RECEIVED if not reply was received. Setting size to - * 0 has the same effect - * - Everything else triggers failure event with - * returnvalue as parameter 1 - */ - virtual ReturnValue_t readReceivedMessage(CookieIF *cookie, - uint8_t **buffer, size_t *size) = 0; -}; - -#endif /* DEVICECOMMUNICATIONIF_H_ */ +#ifndef FRAMEWORK_DEVICES_DEVICECOMMUNICATIONIF_H_ +#define FRAMEWORK_DEVICES_DEVICECOMMUNICATIONIF_H_ + +#include "../devicehandlers/CookieIF.h" +#include "../devicehandlers/DeviceHandlerIF.h" +#include "../returnvalues/HasReturnvaluesIF.h" +/** + * @defgroup interfaces Interfaces + * @brief Interfaces for flight software objects + */ + +/** + * @defgroup comm Communication + * @brief Communication software components. + */ + +/** + * @brief This is an interface to decouple device communication from + * the device handler to allow reuse of these components. + * @details + * Documentation: Dissertation Baetz p.138. + * It works with the assumption that received data is polled by a component. + * There are four generic steps of device communication: + * + * 1. Send data to a device + * 2. Get acknowledgement for sending + * 3. Request reading data from a device + * 4. Read received data + * + * To identify different connection over a single interface can return + * so-called cookies to components. + * The CommunicationMessage message type can be used to extend the + * functionality of the ComIF if a separate polling task is required. + * @ingroup interfaces + * @ingroup comm + */ +class DeviceCommunicationIF: public HasReturnvaluesIF { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_COMMUNICATION_IF; + + //! This is returned in readReceivedMessage() if no reply was reived. + static const ReturnValue_t NO_REPLY_RECEIVED = MAKE_RETURN_CODE(0x01); + + //! General protocol error. Define more concrete errors in child handler + static const ReturnValue_t PROTOCOL_ERROR = MAKE_RETURN_CODE(0x02); + //! If cookie is a null pointer + static const ReturnValue_t NULLPOINTER = MAKE_RETURN_CODE(0x03); + static const ReturnValue_t INVALID_COOKIE_TYPE = MAKE_RETURN_CODE(0x04); + // is this needed if there is no open/close call? + static const ReturnValue_t NOT_ACTIVE = MAKE_RETURN_CODE(0x05); + static const ReturnValue_t TOO_MUCH_DATA = MAKE_RETURN_CODE(0x06); + + virtual ~DeviceCommunicationIF() {} + + /** + * @brief Device specific initialization, using the cookie. + * @details + * The cookie is already prepared in the factory. If the communication + * interface needs to be set up in some way and requires cookie information, + * this can be performed in this function, which is called on device handler + * initialization. + * @param cookie + * @return + * - @c RETURN_OK if initialization was successfull + * - Everything else triggers failure event with returnvalue as parameter 1 + */ + virtual ReturnValue_t initializeInterface(CookieIF * cookie) = 0; + + /** + * Called by DHB in the SEND_WRITE doSendWrite(). + * This function is used to send data to the physical device + * by implementing and calling related drivers or wrapper functions. + * @param cookie + * @param data + * @param len If this is 0, nothing shall be sent. + * @return + * - @c RETURN_OK for successfull send + * - Everything else triggers failure event with returnvalue as parameter 1 + */ + virtual ReturnValue_t sendMessage(CookieIF *cookie, + const uint8_t * sendData, size_t sendLen) = 0; + + /** + * Called by DHB in the GET_WRITE doGetWrite(). + * Get send confirmation that the data in sendMessage() was sent successfully. + * @param cookie + * @return - @c RETURN_OK if data was sent successfull + * - Everything else triggers falure event with + * returnvalue as parameter 1 + */ + virtual ReturnValue_t getSendSuccess(CookieIF *cookie) = 0; + + /** + * Called by DHB in the SEND_WRITE doSendRead(). + * It is assumed that it is always possible to request a reply + * from a device. If a requestLen of 0 is supplied, no reply was enabled + * and communication specific action should be taken (e.g. read nothing + * or read everything). + * + * @param cookie + * @param requestLen Size of data to read + * @return - @c RETURN_OK to confirm the request for data has been sent. + * - Everything else triggers failure event with + * returnvalue as parameter 1 + */ + virtual ReturnValue_t requestReceiveMessage(CookieIF *cookie, + size_t requestLen) = 0; + + /** + * Called by DHB in the GET_WRITE doGetRead(). + * This function is used to receive data from the physical device + * by implementing and calling related drivers or wrapper functions. + * @param cookie + * @param buffer [out] Set reply here (by using *buffer = ...) + * @param size [out] size pointer to set (by using *size = ...). + * Set to 0 if no reply was received + * @return - @c RETURN_OK for successfull receive + * - @c NO_REPLY_RECEIVED if not reply was received. Setting size to + * 0 has the same effect + * - Everything else triggers failure event with + * returnvalue as parameter 1 + */ + virtual ReturnValue_t readReceivedMessage(CookieIF *cookie, + uint8_t **buffer, size_t *size) = 0; +}; + +#endif /* DEVICECOMMUNICATIONIF_H_ */ diff --git a/devicehandlers/DeviceHandlerBase.cpp b/devicehandlers/DeviceHandlerBase.cpp index a4346afb..06b26595 100644 --- a/devicehandlers/DeviceHandlerBase.cpp +++ b/devicehandlers/DeviceHandlerBase.cpp @@ -1,1397 +1,1397 @@ -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -object_id_t DeviceHandlerBase::powerSwitcherId = objects::NO_OBJECT; -object_id_t DeviceHandlerBase::rawDataReceiverId = objects::NO_OBJECT; -object_id_t DeviceHandlerBase::defaultFdirParentId = objects::NO_OBJECT; -object_id_t DeviceHandlerBase::defaultHkDestination = objects::NO_OBJECT; - -DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, - object_id_t deviceCommunication, CookieIF * comCookie, - FailureIsolationBase* fdirInstance, size_t cmdQueueSize) : - SystemObject(setObjectId), mode(MODE_OFF), submode(SUBMODE_NONE), - wiretappingMode(OFF), storedRawData(StorageManagerIF::INVALID_ADDRESS), - deviceCommunicationId(deviceCommunication), comCookie(comCookie), - healthHelper(this,setObjectId), modeHelper(this), parameterHelper(this), - actionHelper(this, nullptr), hkManager(this, nullptr), - childTransitionFailure(RETURN_OK), fdirInstance(fdirInstance), - hkSwitcher(this), defaultFDIRUsed(fdirInstance == nullptr), - switchOffWasReported(false), childTransitionDelay(5000), - transitionSourceMode(_MODE_POWER_DOWN), - transitionSourceSubMode(SUBMODE_NONE) { - commandQueue = QueueFactory::instance()->createMessageQueue(cmdQueueSize, - MessageQueueMessage::MAX_MESSAGE_SIZE); - insertInCommandMap(RAW_COMMAND_ID); - cookieInfo.state = COOKIE_UNUSED; - cookieInfo.pendingCommand = deviceCommandMap.end(); - if (comCookie == nullptr) { - sif::error << "DeviceHandlerBase: ObjectID 0x" << std::hex - << std::setw(8) << std::setfill('0') << this->getObjectId() - << std::dec << ": Do not pass nullptr as a cookie, consider " - << std::setfill(' ') << "passing a dummy cookie instead!" - << std::endl; - } - if (this->fdirInstance == nullptr) { - this->fdirInstance = new DeviceHandlerFailureIsolation(setObjectId, - defaultFdirParentId); - } -} - -void DeviceHandlerBase::setHkDestination(object_id_t hkDestination) { - this->hkDestination = hkDestination; -} - -void DeviceHandlerBase::setThermalStateRequestPoolIds( - uint32_t thermalStatePoolId, uint32_t thermalRequestPoolId) { - this->deviceThermalRequestPoolId = thermalStatePoolId; - this->deviceThermalRequestPoolId = thermalRequestPoolId; -} - - -DeviceHandlerBase::~DeviceHandlerBase() { - delete comCookie; - if (defaultFDIRUsed) { - delete fdirInstance; - } - QueueFactory::instance()->deleteMessageQueue(commandQueue); -} - -ReturnValue_t DeviceHandlerBase::performOperation(uint8_t counter) { - this->pstStep = counter; - - if (getComAction() == SEND_WRITE) { - cookieInfo.state = COOKIE_UNUSED; - readCommandQueue(); - doStateMachine(); - checkSwitchState(); - decrementDeviceReplyMap(); - fdirInstance->checkForFailures(); - hkSwitcher.performOperation(); - performOperationHook(); - } - if (mode == MODE_OFF) { - return RETURN_OK; - } - switch (getComAction()) { - case SEND_WRITE: - if ((cookieInfo.state == COOKIE_UNUSED)) { - buildInternalCommand(); - } - doSendWrite(); - break; - case GET_WRITE: - doGetWrite(); - break; - case SEND_READ: - doSendRead(); - break; - case GET_READ: - doGetRead(); - cookieInfo.state = COOKIE_UNUSED; - break; - default: - break; - } - return RETURN_OK; -} - -ReturnValue_t DeviceHandlerBase::initialize() { - ReturnValue_t result = SystemObject::initialize(); - if (result != RETURN_OK) { - return result; - } - - communicationInterface = objectManager->get( - deviceCommunicationId); - if (communicationInterface == nullptr) { - sif::error << "DeviceHandlerBase::initialize: Communication interface " - "invalid." << std::endl; - sif::error << "Make sure it is set up properly and implements" - " DeviceCommunicationIF" << std::endl; - return ObjectManagerIF::CHILD_INIT_FAILED; - } - - result = communicationInterface->initializeInterface(comCookie); - if (result != RETURN_OK) { - sif::error << "DeviceHandlerBase::initialize: Initializing " - "communication interface failed!" << std::endl; - return result; - } - - IPCStore = objectManager->get(objects::IPC_STORE); - if (IPCStore == nullptr) { - sif::error << "DeviceHandlerBase::initialize: IPC store not set up in " - "factory." << std::endl; - return ObjectManagerIF::CHILD_INIT_FAILED; - } - - if(rawDataReceiverId != objects::NO_OBJECT) { - AcceptsDeviceResponsesIF *rawReceiver = objectManager->get< - AcceptsDeviceResponsesIF>(rawDataReceiverId); - - if (rawReceiver == nullptr) { - sif::error << "DeviceHandlerBase::initialize: Raw receiver object " - "ID set but no valid object found." << std::endl; - sif::error << "Make sure the raw receiver object is set up properly" - " and implements AcceptsDeviceResponsesIF" << std::endl; - return ObjectManagerIF::CHILD_INIT_FAILED; - } - defaultRawReceiver = rawReceiver->getDeviceQueue(); - } - - if(powerSwitcherId != objects::NO_OBJECT) { - powerSwitcher = objectManager->get(powerSwitcherId); - if (powerSwitcher == nullptr) { - sif::error << "DeviceHandlerBase::initialize: Power switcher " - << "object ID set but no valid object found." << std::endl; - sif::error << "Make sure the raw receiver object is set up properly" - << " and implements PowerSwitchIF" << std::endl; - return ObjectManagerIF::CHILD_INIT_FAILED; - } - } - - result = healthHelper.initialize(); - if (result != RETURN_OK) { - return result; - } - - result = modeHelper.initialize(); - if (result != RETURN_OK) { - return result; - } - result = actionHelper.initialize(commandQueue); - if (result != RETURN_OK) { - return result; - } - result = fdirInstance->initialize(); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - result = parameterHelper.initialize(); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - result = hkSwitcher.initialize(); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - if(hkDestination == objects::NO_OBJECT) { - hkDestination = defaultHkDestination; - } - - result = hkManager.initialize(commandQueue, hkDestination); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - fillCommandAndReplyMap(); - - //Set temperature target state to NON_OP. - GlobDataSet mySet; - gp_uint8_t thermalRequest(deviceThermalRequestPoolId, &mySet, - PoolVariableIF::VAR_WRITE); - mySet.read(); - thermalRequest = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL; - mySet.commit(PoolVariableIF::VALID); - - return RETURN_OK; - -} - -void DeviceHandlerBase::decrementDeviceReplyMap() { - for (std::map::iterator iter = - deviceReplyMap.begin(); iter != deviceReplyMap.end(); iter++) { - if (iter->second.delayCycles != 0) { - iter->second.delayCycles--; - if (iter->second.delayCycles == 0) { - if (iter->second.periodic) { - iter->second.delayCycles = iter->second.maxDelayCycles; - } - replyToReply(iter, TIMEOUT); - missedReply(iter->first); - } - } - } -} - -void DeviceHandlerBase::readCommandQueue() { - - if (dontCheckQueue()) { - return; - } - - CommandMessage command; - ReturnValue_t result = commandQueue->receiveMessage(&command); - if (result != RETURN_OK) { - return; - } - - result = healthHelper.handleHealthCommand(&command); - if (result == RETURN_OK) { - return; - } - - result = modeHelper.handleModeCommand(&command); - if (result == RETURN_OK) { - return; - } - - result = actionHelper.handleActionMessage(&command); - if (result == RETURN_OK) { - return; - } - - result = parameterHelper.handleParameterMessage(&command); - if (result == RETURN_OK) { - return; - } - - result = hkManager.handleHousekeepingMessage(&command); - if (result == RETURN_OK) { - return; - } - - result = handleDeviceHandlerMessage(&command); - if (result == RETURN_OK) { - return; - } - - result = letChildHandleMessage(&command); - if (result == RETURN_OK) { - return; - } - - replyReturnvalueToCommand(CommandMessage::UNKNOWN_COMMAND); - -} - -void DeviceHandlerBase::doStateMachine() { - switch (mode) { - case _MODE_START_UP: - case _MODE_SHUT_DOWN: - case _MODE_TO_NORMAL: - case _MODE_TO_ON: - case _MODE_TO_RAW: { - Mode_t currentMode = mode; - callChildStatemachine(); - //Only do timeout if child did not change anything - if (mode != currentMode) { - break; - } - uint32_t currentUptime; - Clock::getUptime(¤tUptime); - if (currentUptime - timeoutStart >= childTransitionDelay) { - triggerEvent(MODE_TRANSITION_FAILED, childTransitionFailure, 0); - setMode(transitionSourceMode, transitionSourceSubMode); - break; - } - } - break; - case _MODE_POWER_DOWN: - commandSwitch(PowerSwitchIF::SWITCH_OFF); - setMode(_MODE_WAIT_OFF); - break; - case _MODE_POWER_ON: - commandSwitch(PowerSwitchIF::SWITCH_ON); - setMode(_MODE_WAIT_ON); - break; - case _MODE_WAIT_ON: { - uint32_t currentUptime; - Clock::getUptime(¤tUptime); - if (powerSwitcher != nullptr and currentUptime - timeoutStart >= - powerSwitcher->getSwitchDelayMs()) { - triggerEvent(MODE_TRANSITION_FAILED, PowerSwitchIF::SWITCH_TIMEOUT, - 0); - setMode(_MODE_POWER_DOWN); - callChildStatemachine(); - break; - } - ReturnValue_t switchState = getStateOfSwitches(); - if ((switchState == PowerSwitchIF::SWITCH_ON) - || (switchState == NO_SWITCH)) { - //NOTE: TransitionSourceMode and -SubMode are set by handleCommandedModeTransition - childTransitionFailure = CHILD_TIMEOUT; - setMode(_MODE_START_UP); - callChildStatemachine(); - } - } - break; - case _MODE_WAIT_OFF: { - uint32_t currentUptime; - Clock::getUptime(¤tUptime); - - if(powerSwitcher == nullptr) { - setMode(MODE_OFF); - break; - } - - if (currentUptime - timeoutStart >= powerSwitcher->getSwitchDelayMs()) { - triggerEvent(MODE_TRANSITION_FAILED, PowerSwitchIF::SWITCH_TIMEOUT, - 0); - setMode(MODE_ERROR_ON); - break; - } - ReturnValue_t switchState = getStateOfSwitches(); - if ((switchState == PowerSwitchIF::SWITCH_OFF) - || (switchState == NO_SWITCH)) { - setMode(_MODE_SWITCH_IS_OFF); - } - } - break; - case MODE_OFF: - doOffActivity(); - break; - case MODE_ON: - doOnActivity(); - break; - case MODE_RAW: - case MODE_NORMAL: - case MODE_ERROR_ON: - break; - case _MODE_SWITCH_IS_OFF: - setMode(MODE_OFF, SUBMODE_NONE); - break; - default: - triggerEvent(OBJECT_IN_INVALID_MODE, mode, submode); - setMode(_MODE_POWER_DOWN, 0); - break; - } -} - -ReturnValue_t DeviceHandlerBase::isModeCombinationValid(Mode_t mode, - Submode_t submode) { - switch (mode) { - case MODE_OFF: - case MODE_ON: - case MODE_NORMAL: - case MODE_RAW: - if (submode == SUBMODE_NONE) { - return RETURN_OK; - } else { - return INVALID_SUBMODE; - } - default: - return HasModesIF::INVALID_MODE; - } -} - -ReturnValue_t DeviceHandlerBase::insertInCommandAndReplyMap( - DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles, - size_t replyLen, bool periodic, bool hasDifferentReplyId, - DeviceCommandId_t replyId) { - //No need to check, as we may try to insert multiple times. - insertInCommandMap(deviceCommand); - if (hasDifferentReplyId) { - return insertInReplyMap(replyId, maxDelayCycles, replyLen, periodic); - } else { - return insertInReplyMap(deviceCommand, maxDelayCycles, replyLen, periodic); - } -} - -ReturnValue_t DeviceHandlerBase::insertInReplyMap(DeviceCommandId_t replyId, - uint16_t maxDelayCycles, size_t replyLen, bool periodic) { - DeviceReplyInfo info; - info.maxDelayCycles = maxDelayCycles; - info.periodic = periodic; - info.delayCycles = 0; - info.replyLen = replyLen; - info.command = deviceCommandMap.end(); - auto resultPair = deviceReplyMap.emplace(replyId, info); - if (resultPair.second) { - return RETURN_OK; - } else { - return RETURN_FAILED; - } -} - -ReturnValue_t DeviceHandlerBase::insertInCommandMap( - DeviceCommandId_t deviceCommand) { - DeviceCommandInfo info; - info.expectedReplies = 0; - info.isExecuting = false; - info.sendReplyTo = NO_COMMANDER; - auto resultPair = deviceCommandMap.emplace(deviceCommand, info); - if (resultPair.second) { - return RETURN_OK; - } else { - return RETURN_FAILED; - } -} - -ReturnValue_t DeviceHandlerBase::updateReplyMapEntry(DeviceCommandId_t deviceReply, - uint16_t delayCycles, uint16_t maxDelayCycles, bool periodic) { - std::map::iterator iter = - deviceReplyMap.find(deviceReply); - if (iter == deviceReplyMap.end()) { - triggerEvent(INVALID_DEVICE_COMMAND, deviceReply); - return RETURN_FAILED; - } else { - DeviceReplyInfo *info = &(iter->second); - if (maxDelayCycles != 0) { - info->maxDelayCycles = maxDelayCycles; - } - info->delayCycles = delayCycles; - info->periodic = periodic; - return RETURN_OK; - } -} - -void DeviceHandlerBase::callChildStatemachine() { - if (mode == _MODE_START_UP) { - doStartUp(); - } else if (mode == _MODE_SHUT_DOWN) { - doShutDown(); - } else if (mode & TRANSITION_MODE_CHILD_ACTION_MASK) { - doTransition(transitionSourceMode, transitionSourceSubMode); - } -} - -void DeviceHandlerBase::setTransition(Mode_t modeTo, Submode_t submodeTo) { - triggerEvent(CHANGING_MODE, modeTo, submodeTo); - childTransitionDelay = getTransitionDelayMs(mode, modeTo); - transitionSourceMode = mode; - transitionSourceSubMode = submode; - childTransitionFailure = CHILD_TIMEOUT; - - // transitionTargetMode is set by setMode - setMode((modeTo | TRANSITION_MODE_CHILD_ACTION_MASK), submodeTo); -} - -void DeviceHandlerBase::setMode(Mode_t newMode, uint8_t newSubmode) { - changeHK(mode, submode, false); - submode = newSubmode; - mode = newMode; - modeChanged(); - setNormalDatapoolEntriesInvalid(); - if (!isTransitionalMode()) { - modeHelper.modeChanged(newMode, newSubmode); - announceMode(false); - } - Clock::getUptime(&timeoutStart); - - if (mode == MODE_OFF) { - GlobDataSet mySet; - gp_uint8_t thermalRequest(deviceThermalRequestPoolId, &mySet, - PoolVariableIF::VAR_READ_WRITE); - mySet.read(); - if (thermalRequest != ThermalComponentIF::STATE_REQUEST_IGNORE) { - thermalRequest = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL; - } - mySet.commit(PoolVariableIF::VALID); - } - changeHK(mode, submode, true); -} - -void DeviceHandlerBase::setMode(Mode_t newMode) { - setMode(newMode, submode); -} - -void DeviceHandlerBase::replyReturnvalueToCommand(ReturnValue_t status, - uint32_t parameter) { - //This is actually the reply protocol for raw and misc DH commands. - if (status == RETURN_OK) { - CommandMessage reply(CommandMessage::REPLY_COMMAND_OK, 0, parameter); - commandQueue->reply(&reply); - } else { - CommandMessage reply(CommandMessage::REPLY_REJECTED, status, parameter); - commandQueue->reply(&reply); - } -} - -void DeviceHandlerBase::replyToCommand(ReturnValue_t status, - uint32_t parameter) { -//Check if we reply to a raw command. - if (cookieInfo.pendingCommand->first == RAW_COMMAND_ID) { - if (status == NO_REPLY_EXPECTED) { - status = RETURN_OK; - } - replyReturnvalueToCommand(status, parameter); - //Always delete data from a raw command. - IPCStore->deleteData(storedRawData); - return; - } -//Check if we were externally commanded. - if (cookieInfo.pendingCommand->second.sendReplyTo != NO_COMMANDER) { - MessageQueueId_t queueId = cookieInfo.pendingCommand->second.sendReplyTo; - if (status == NO_REPLY_EXPECTED) { - actionHelper.finish(queueId, cookieInfo.pendingCommand->first, - RETURN_OK); - } else { - actionHelper.step(1, queueId, cookieInfo.pendingCommand->first, - status); - } - } -} - -void DeviceHandlerBase::replyToReply(DeviceReplyMap::iterator iter, - ReturnValue_t status) { -//No need to check if iter exists, as this is checked by callers. If someone else uses the method, add check. - if (iter->second.command == deviceCommandMap.end()) { - //Is most likely periodic reply. Silent return. - return; - } -//Check if more replies are expected. If so, do nothing. - DeviceCommandInfo* info = &(iter->second.command->second); - if (--info->expectedReplies == 0) { - //Check if it was transition or internal command. Don't send any replies in that case. - if (info->sendReplyTo != NO_COMMANDER) { - actionHelper.finish(info->sendReplyTo, iter->first, status); - } - info->isExecuting = false; - } -} - -void DeviceHandlerBase::doSendWrite() { - if (cookieInfo.state == COOKIE_WRITE_READY) { - - ReturnValue_t result = communicationInterface->sendMessage(comCookie, - rawPacket, rawPacketLen); - - if (result == RETURN_OK) { - cookieInfo.state = COOKIE_WRITE_SENT; - } else { - //always generate a failure event, so that FDIR knows what's up - triggerEvent(DEVICE_SENDING_COMMAND_FAILED, result, - cookieInfo.pendingCommand->first); - replyToCommand(result); - cookieInfo.state = COOKIE_UNUSED; - cookieInfo.pendingCommand->second.isExecuting = false; - } - } -} - -void DeviceHandlerBase::doGetWrite() { - if (cookieInfo.state != COOKIE_WRITE_SENT) { - return; - } - cookieInfo.state = COOKIE_UNUSED; - ReturnValue_t result = communicationInterface->getSendSuccess(comCookie); - if (result == RETURN_OK) { - if (wiretappingMode == RAW) { - replyRawData(rawPacket, rawPacketLen, requestedRawTraffic, true); - } - - //We need to distinguish here, because a raw command never expects a reply. - //(Could be done in eRIRM, but then child implementations need to be careful. - result = enableReplyInReplyMap(cookieInfo.pendingCommand); - } else { - //always generate a failure event, so that FDIR knows what's up - triggerEvent(DEVICE_SENDING_COMMAND_FAILED, result, - cookieInfo.pendingCommand->first); - } - if (result != RETURN_OK) { - cookieInfo.pendingCommand->second.isExecuting = false; - } - replyToCommand(result); -} - -void DeviceHandlerBase::doSendRead() { - ReturnValue_t result; - - size_t requestLen = 0; - if(cookieInfo.pendingCommand != deviceCommandMap.end()) { - DeviceReplyIter iter = deviceReplyMap.find( - cookieInfo.pendingCommand->first); - if(iter != deviceReplyMap.end()) { - requestLen = iter->second.replyLen; - } - } - - result = communicationInterface->requestReceiveMessage(comCookie, requestLen); - - if (result == RETURN_OK) { - cookieInfo.state = COOKIE_READ_SENT; - } else { - triggerEvent(DEVICE_REQUESTING_REPLY_FAILED, result); - //We can't inform anyone, because we don't know which command was sent last. - //So, we need to wait for a timeout. - //but I think we can allow to ignore one missedReply. - ignoreMissedRepliesCount++; - cookieInfo.state = COOKIE_UNUSED; - } -} - -void DeviceHandlerBase::doGetRead() { - size_t receivedDataLen = 0; - uint8_t *receivedData = nullptr; - - if (cookieInfo.state != COOKIE_READ_SENT) { - cookieInfo.state = COOKIE_UNUSED; - return; - } - - cookieInfo.state = COOKIE_UNUSED; - - ReturnValue_t result = communicationInterface->readReceivedMessage( - comCookie, &receivedData, &receivedDataLen); - - if (result != RETURN_OK) { - triggerEvent(DEVICE_REQUESTING_REPLY_FAILED, result); - //I think we can allow to ignore one missedReply. - ignoreMissedRepliesCount++; - return; - } - - if (receivedDataLen == 0 or result == DeviceCommunicationIF::NO_REPLY_RECEIVED) - return; - - if (wiretappingMode == RAW) { - replyRawData(receivedData, receivedDataLen, requestedRawTraffic); - } - - if (mode == MODE_RAW and defaultRawReceiver != MessageQueueIF::NO_QUEUE) { - replyRawReplyIfnotWiretapped(receivedData, receivedDataLen); - } - else { - parseReply(receivedData, receivedDataLen); - } -} - -void DeviceHandlerBase::parseReply(const uint8_t* receivedData, - size_t receivedDataLen) { - ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; - DeviceCommandId_t foundId = 0xFFFFFFFF; - size_t foundLen = 0; - // The loop may not execute more often than the number of received bytes - // (worst case). This approach avoids infinite loops due to buggy - // scanForReply routines. - uint32_t remainingLength = receivedDataLen; - for (uint32_t count = 0; count < receivedDataLen; count++) { - result = scanForReply(receivedData, remainingLength, &foundId, - &foundLen); - switch (result) { - case RETURN_OK: - handleReply(receivedData, foundId, foundLen); - if(foundLen == 0) { - sif::warning << "DeviceHandlerBase::parseReply: foundLen is 0!" - " Packet parsing will be stuck." << std::endl; - } - break; - case APERIODIC_REPLY: { - result = interpretDeviceReply(foundId, receivedData); - if (result != RETURN_OK) { - replyRawReplyIfnotWiretapped(receivedData, foundLen); - triggerEvent(DEVICE_INTERPRETING_REPLY_FAILED, result, - foundId); - } - if(foundLen == 0) { - sif::warning << "DeviceHandlerBase::parseReply: foundLen is 0!" - " Packet parsing will be stuck." << std::endl; - } - break; - } - case IGNORE_REPLY_DATA: - break; - case IGNORE_FULL_PACKET: - return; - default: - //We need to wait for timeout.. don't know what command failed and who sent it. - replyRawReplyIfnotWiretapped(receivedData, foundLen); - triggerEvent(DEVICE_READING_REPLY_FAILED, result, foundLen); - break; - } - receivedData += foundLen; - if (remainingLength > foundLen) { - remainingLength -= foundLen; - } else { - return; - } - } -} - -void DeviceHandlerBase::handleReply(const uint8_t* receivedData, - DeviceCommandId_t foundId, uint32_t foundLen) { - ReturnValue_t result; - DeviceReplyMap::iterator iter = deviceReplyMap.find(foundId); - - if (iter == deviceReplyMap.end()) { - replyRawReplyIfnotWiretapped(receivedData, foundLen); - triggerEvent(DEVICE_UNKNOWN_REPLY, foundId); - return; - } - - DeviceReplyInfo *info = &(iter->second); - - if (info->delayCycles != 0) { - - if (info->periodic != false) { - info->delayCycles = info->maxDelayCycles; - } - else { - info->delayCycles = 0; - } - - result = interpretDeviceReply(foundId, receivedData); - - if (result != RETURN_OK) { - // Report failed interpretation to FDIR. - replyRawReplyIfnotWiretapped(receivedData, foundLen); - triggerEvent(DEVICE_INTERPRETING_REPLY_FAILED, result, foundId); - } - replyToReply(iter, result); - } - else { - // Other completion failure messages are created by timeout. - // Powering down the device might take some time during which periodic - // replies may still come in. - if (mode != _MODE_WAIT_OFF) { - triggerEvent(DEVICE_UNREQUESTED_REPLY, foundId); - } - } -} - -ReturnValue_t DeviceHandlerBase::getStorageData(store_address_t storageAddress, - uint8_t** data, uint32_t * len) { - size_t lenTmp; - - if (IPCStore == nullptr) { - *data = nullptr; - *len = 0; - return RETURN_FAILED; - } - ReturnValue_t result = IPCStore->modifyData(storageAddress, data, &lenTmp); - if (result == RETURN_OK) { - *len = lenTmp; - return RETURN_OK; - } else { - triggerEvent(StorageManagerIF::GET_DATA_FAILED, result, - storageAddress.raw); - *data = nullptr; - *len = 0; - return result; - } -} - -void DeviceHandlerBase::replyRawData(const uint8_t *data, size_t len, - MessageQueueId_t sendTo, bool isCommand) { - if (IPCStore == nullptr or len == 0 or sendTo == MessageQueueIF::NO_QUEUE) { - return; - } - store_address_t address; - ReturnValue_t result = IPCStore->addData(&address, data, len); - - if (result != RETURN_OK) { - triggerEvent(StorageManagerIF::STORE_DATA_FAILED, result); - return; - } - - CommandMessage command; - - DeviceHandlerMessage::setDeviceHandlerRawReplyMessage(&command, - getObjectId(), address, isCommand); - - result = commandQueue->sendMessage(sendTo, &command); - - if (result != RETURN_OK) { - IPCStore->deleteData(address); - // Silently discard data, this indicates heavy TM traffic which - // should not be increased by additional events. - } -} - -//Default child implementations -DeviceHandlerIF::CommunicationAction_t DeviceHandlerBase::getComAction() { - switch (pstStep) { - case 0: - return SEND_WRITE; - break; - case 1: - return GET_WRITE; - break; - case 2: - return SEND_READ; - break; - case 3: - return GET_READ; - break; - default: - break; - } - return NOTHING; -} - -MessageQueueId_t DeviceHandlerBase::getCommandQueue() const { - return commandQueue->getId(); -} - -void DeviceHandlerBase::buildRawDeviceCommand(CommandMessage* commandMessage) { - storedRawData = DeviceHandlerMessage::getStoreAddress(commandMessage); - ReturnValue_t result = getStorageData(storedRawData, &rawPacket, - &rawPacketLen); - if (result != RETURN_OK) { - replyReturnvalueToCommand(result, RAW_COMMAND_ID); - storedRawData.raw = StorageManagerIF::INVALID_ADDRESS; - } else { - cookieInfo.pendingCommand = deviceCommandMap.find( - (DeviceCommandId_t) RAW_COMMAND_ID); - cookieInfo.pendingCommand->second.isExecuting = true; - cookieInfo.state = COOKIE_WRITE_READY; - } -} - -void DeviceHandlerBase::commandSwitch(ReturnValue_t onOff) { - if(powerSwitcher == nullptr) { - return; - } - const uint8_t *switches; - uint8_t numberOfSwitches = 0; - ReturnValue_t result = getSwitches(&switches, &numberOfSwitches); - if (result == RETURN_OK) { - while (numberOfSwitches > 0) { - powerSwitcher->sendSwitchCommand(switches[numberOfSwitches - 1], - onOff); - numberOfSwitches--; - } - } -} - -ReturnValue_t DeviceHandlerBase::getSwitches(const uint8_t **switches, - uint8_t *numberOfSwitches) { - return DeviceHandlerBase::NO_SWITCH; -} - -void DeviceHandlerBase::modeChanged(void) { -} - -ReturnValue_t DeviceHandlerBase::enableReplyInReplyMap( - DeviceCommandMap::iterator command, uint8_t expectedReplies, - bool useAlternativeId, DeviceCommandId_t alternativeReply) { - DeviceReplyMap::iterator iter; - if (useAlternativeId) { - iter = deviceReplyMap.find(alternativeReply); - } else { - iter = deviceReplyMap.find(command->first); - } - if (iter != deviceReplyMap.end()) { - DeviceReplyInfo *info = &(iter->second); - info->delayCycles = info->maxDelayCycles; - info->command = command; - command->second.expectedReplies = expectedReplies; - return RETURN_OK; - } else { - return NO_REPLY_EXPECTED; - } -} - -void DeviceHandlerBase::doTransition(Mode_t modeFrom, Submode_t subModeFrom) { - setMode(getBaseMode(mode)); -} - -uint32_t DeviceHandlerBase::getTransitionDelayMs(Mode_t modeFrom, - Mode_t modeTo) { - return 0; -} - -ReturnValue_t DeviceHandlerBase::getStateOfSwitches(void) { - if(powerSwitcher == nullptr) { - return NO_SWITCH; - } - uint8_t numberOfSwitches = 0; - const uint8_t *switches; - - ReturnValue_t result = getSwitches(&switches, &numberOfSwitches); - if ((result == RETURN_OK) && (numberOfSwitches != 0)) { - while (numberOfSwitches > 0) { - if (powerSwitcher->getSwitchState(switches[numberOfSwitches - 1]) - == PowerSwitchIF::SWITCH_OFF) { - return PowerSwitchIF::SWITCH_OFF; - } - numberOfSwitches--; - } - return PowerSwitchIF::SWITCH_ON; - } - - return NO_SWITCH; -} - -Mode_t DeviceHandlerBase::getBaseMode(Mode_t transitionMode) { -//only child action special modes are handled, as a child should never see any base action modes - if (transitionMode == _MODE_START_UP) { - return _MODE_TO_ON; - } - if (transitionMode == _MODE_SHUT_DOWN) { - return _MODE_POWER_DOWN; - } - return transitionMode - & ~(TRANSITION_MODE_BASE_ACTION_MASK - | TRANSITION_MODE_CHILD_ACTION_MASK); -} - -//SHOULDDO: Allow transition from OFF to NORMAL to reduce complexity in assemblies. And, by the way, throw away DHB and write a new one: -// - Include power and thermal completely, but more modular :-) -// - Don't use modes for state transitions, reduce FSM (Finte State Machine) complexity. -// - Modularization? -ReturnValue_t DeviceHandlerBase::checkModeCommand(Mode_t commandedMode, - Submode_t commandedSubmode, uint32_t* msToReachTheMode) { - if (isTransitionalMode()) { - return IN_TRANSITION; - } - if ((mode == MODE_ERROR_ON) && (commandedMode != MODE_OFF)) { - return TRANS_NOT_ALLOWED; - } - if ((commandedMode == MODE_NORMAL) && (mode == MODE_OFF)) { - return TRANS_NOT_ALLOWED; - } - - if ((commandedMode == MODE_ON) && (mode == MODE_OFF) - && (deviceThermalStatePoolId != PoolVariableIF::NO_PARAMETER)) { - GlobDataSet mySet; - gp_uint8_t thermalState(deviceThermalStatePoolId, &mySet, - PoolVariableIF::VAR_READ); - gp_uint8_t thermalRequest(deviceThermalRequestPoolId, &mySet, - PoolVariableIF::VAR_READ); - mySet.read(); - if (thermalRequest != ThermalComponentIF::STATE_REQUEST_IGNORE) { - if (!ThermalComponentIF::isOperational(thermalState)) { - triggerEvent(ThermalComponentIF::TEMP_NOT_IN_OP_RANGE, - thermalState); - return NON_OP_TEMPERATURE; - } - } - } - - return isModeCombinationValid(commandedMode, commandedSubmode); -} - -void DeviceHandlerBase::startTransition(Mode_t commandedMode, - Submode_t commandedSubmode) { - switch (commandedMode) { - case MODE_ON: - if (mode == MODE_OFF) { - transitionSourceMode = _MODE_POWER_DOWN; - transitionSourceSubMode = SUBMODE_NONE; - setMode(_MODE_POWER_ON, commandedSubmode); - //already set the delay for the child transition so we don't need to call it twice - childTransitionDelay = getTransitionDelayMs(_MODE_START_UP, - MODE_ON); - triggerEvent(CHANGING_MODE, commandedMode, commandedSubmode); - GlobDataSet mySet; - gp_int8_t thermalRequest(deviceThermalRequestPoolId, - &mySet, PoolVariableIF::VAR_READ_WRITE); - mySet.read(); - if (thermalRequest != ThermalComponentIF::STATE_REQUEST_IGNORE) { - thermalRequest = ThermalComponentIF::STATE_REQUEST_OPERATIONAL; - mySet.commit(PoolVariableIF::VALID); - } - } else { - setTransition(MODE_ON, commandedSubmode); - } - break; - case MODE_OFF: - if (mode == MODE_OFF) { - triggerEvent(CHANGING_MODE, commandedMode, commandedSubmode); - setMode(_MODE_POWER_DOWN, commandedSubmode); - } else { - //already set the delay for the child transition so we don't need to call it twice - childTransitionDelay = getTransitionDelayMs(mode, _MODE_POWER_DOWN); - transitionSourceMode = _MODE_POWER_DOWN; - transitionSourceSubMode = commandedSubmode; - childTransitionFailure = CHILD_TIMEOUT; - setMode(_MODE_SHUT_DOWN, commandedSubmode); - triggerEvent(CHANGING_MODE, commandedMode, commandedSubmode); - } - break; - case MODE_RAW: - if (mode != MODE_OFF) { - setTransition(MODE_RAW, commandedSubmode); - } else { - setMode(MODE_RAW, commandedSubmode); - } - break; - case MODE_NORMAL: - if (mode != MODE_OFF) { - setTransition(MODE_NORMAL, commandedSubmode); - } else { - replyReturnvalueToCommand(HasModesIF::TRANS_NOT_ALLOWED); - } - break; - } -} - -void DeviceHandlerBase::getMode(Mode_t* mode, Submode_t* submode) { - *mode = this->mode; - *submode = this->submode; -} - -void DeviceHandlerBase::setToExternalControl() { - healthHelper.setHealth(EXTERNAL_CONTROL); -} - -void DeviceHandlerBase::announceMode(bool recursive) { - triggerEvent(MODE_INFO, mode, submode); -} - -bool DeviceHandlerBase::dontCheckQueue() { - return false; -} - -void DeviceHandlerBase::missedReply(DeviceCommandId_t id) { - if (ignoreMissedRepliesCount > 0) { - ignoreMissedRepliesCount--; - } else { - triggerEvent(DEVICE_MISSED_REPLY, id); - } -} - -HasHealthIF::HealthState DeviceHandlerBase::getHealth() { - return healthHelper.getHealth(); -} - -ReturnValue_t DeviceHandlerBase::setHealth(HealthState health) { - healthHelper.setHealth(health); - return HasReturnvaluesIF::RETURN_OK; -} - -void DeviceHandlerBase::checkSwitchState() { - if ((mode == MODE_ON || mode == MODE_NORMAL)) { - //We only check in ON and NORMAL, ignore RAW and ERROR_ON. - ReturnValue_t result = getStateOfSwitches(); - if (result == PowerSwitchIF::SWITCH_OFF && !switchOffWasReported) { - triggerEvent(PowerSwitchIF::SWITCH_WENT_OFF); - switchOffWasReported = true; - } - } else { - switchOffWasReported = false; - } -} - -void DeviceHandlerBase::doOnActivity() { -} - -ReturnValue_t DeviceHandlerBase::acceptExternalDeviceCommands() { - if ((mode != MODE_ON) && (mode != MODE_NORMAL)) { - return WRONG_MODE_FOR_COMMAND; - } - return RETURN_OK; -} - -void DeviceHandlerBase::replyRawReplyIfnotWiretapped(const uint8_t* data, - size_t len) { - if ((wiretappingMode == RAW) - && (defaultRawReceiver == requestedRawTraffic)) { - //The raw packet was already sent by the wiretapping service - } else { - replyRawData(data, len, defaultRawReceiver); - } -} - -ReturnValue_t DeviceHandlerBase::handleDeviceHandlerMessage( - CommandMessage * message) { - switch (message->getCommand()) { - case DeviceHandlerMessage::CMD_WIRETAPPING: - switch (DeviceHandlerMessage::getWiretappingMode(message)) { - case RAW: - wiretappingMode = RAW; - requestedRawTraffic = commandQueue->getLastPartner(); - break; - case TM: - wiretappingMode = TM; - requestedRawTraffic = commandQueue->getLastPartner(); - break; - case OFF: - wiretappingMode = OFF; - break; - default: - replyReturnvalueToCommand(INVALID_COMMAND_PARAMETER); - wiretappingMode = OFF; - return RETURN_OK; - } - replyReturnvalueToCommand(RETURN_OK); - return RETURN_OK; -// case DeviceHandlerMessage::CMD_SWITCH_IOBOARD: -// if (mode != MODE_OFF) { -// replyReturnvalueToCommand(WRONG_MODE_FOR_COMMAND); -// } else { -// result = switchCookieChannel( -// DeviceHandlerMessage::getIoBoardObjectId(message)); -// if (result == RETURN_OK) { -// replyReturnvalueToCommand(RETURN_OK); -// } else { -// replyReturnvalueToCommand(CANT_SWITCH_IO_ADDRESS); -// } -// } -// return RETURN_OK; - case DeviceHandlerMessage::CMD_RAW: - if ((mode != MODE_RAW)) { - DeviceHandlerMessage::clear(message); - replyReturnvalueToCommand(WRONG_MODE_FOR_COMMAND); - } else { - buildRawDeviceCommand(message); - } - return RETURN_OK; - default: - return RETURN_FAILED; - } -} - -void DeviceHandlerBase::setParentQueue(MessageQueueId_t parentQueueId) { - modeHelper.setParentQueue(parentQueueId); - healthHelper.setParentQueue(parentQueueId); -} - -bool DeviceHandlerBase::isAwaitingReply() { - std::map::iterator iter; - for (iter = deviceReplyMap.begin(); iter != deviceReplyMap.end(); ++iter) { - if (iter->second.delayCycles != 0) { - return true; - } - } - return false; -} - -ReturnValue_t DeviceHandlerBase::letChildHandleMessage( - CommandMessage * message) { - return RETURN_FAILED; -} - -void DeviceHandlerBase::handleDeviceTM(SerializeIF* data, - DeviceCommandId_t replyId, bool neverInDataPool, bool forceDirectTm) { - DeviceReplyMap::iterator iter = deviceReplyMap.find(replyId); - if (iter == deviceReplyMap.end()) { - triggerEvent(DEVICE_UNKNOWN_REPLY, replyId); - return; - } - DeviceTmReportingWrapper wrapper(getObjectId(), replyId, data); - //replies to a command - if (iter->second.command != deviceCommandMap.end()) - { - MessageQueueId_t queueId = iter->second.command->second.sendReplyTo; - - if (queueId != NO_COMMANDER) { - //This may fail, but we'll ignore the fault. - actionHelper.reportData(queueId, replyId, data); - } - - //This check should make sure we get any TM but don't get anything doubled. - if (wiretappingMode == TM && (requestedRawTraffic != queueId)) { - actionHelper.reportData(requestedRawTraffic, replyId, &wrapper); - } - else if (forceDirectTm and (defaultRawReceiver != queueId) and - (defaultRawReceiver != MessageQueueIF::NO_QUEUE)) - { - // hiding of sender needed so the service will handle it as - // unexpected Data, no matter what state (progress or completed) - // it is in - actionHelper.reportData(defaultRawReceiver, replyId, &wrapper, - true); - } - } - //unrequested/aperiodic replies - else - { - if (wiretappingMode == TM) { - actionHelper.reportData(requestedRawTraffic, replyId, &wrapper); - } - else if (forceDirectTm and defaultRawReceiver != - MessageQueueIF::NO_QUEUE) - { - // hiding of sender needed so the service will handle it as - // unexpected Data, no matter what state (progress or completed) - // it is in - actionHelper.reportData(defaultRawReceiver, replyId, &wrapper, - true); - } - } - //Try to cast to GlobDataSet and commit data. - if (!neverInDataPool) { - GlobDataSet* dataSet = dynamic_cast(data); - if (dataSet != NULL) { - dataSet->commit(PoolVariableIF::VALID); - } - } -} - -ReturnValue_t DeviceHandlerBase::executeAction(ActionId_t actionId, - MessageQueueId_t commandedBy, const uint8_t* data, size_t size) { - ReturnValue_t result = acceptExternalDeviceCommands(); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - DeviceCommandMap::iterator iter = deviceCommandMap.find(actionId); - if (iter == deviceCommandMap.end()) { - result = COMMAND_NOT_SUPPORTED; - } else if (iter->second.isExecuting) { - result = COMMAND_ALREADY_SENT; - } else { - result = buildCommandFromCommand(actionId, data, size); - } - if (result == RETURN_OK) { - iter->second.sendReplyTo = commandedBy; - iter->second.isExecuting = true; - cookieInfo.pendingCommand = iter; - cookieInfo.state = COOKIE_WRITE_READY; - } - return result; -} - -void DeviceHandlerBase::buildInternalCommand(void) { -//Neither Raw nor Direct could build a command - ReturnValue_t result = NOTHING_TO_SEND; - DeviceCommandId_t deviceCommandId = NO_COMMAND_ID; - if (mode == MODE_NORMAL) { - result = buildNormalDeviceCommand(&deviceCommandId); - if (result == BUSY) { - //so we can track misconfigurations - sif::debug << std::hex << getObjectId() - << ": DHB::buildInternalCommand: Busy" << std::endl; - result = NOTHING_TO_SEND; //no need to report this - } - } - else if (mode == MODE_RAW) { - result = buildChildRawCommand(); - deviceCommandId = RAW_COMMAND_ID; - } - else if (mode & TRANSITION_MODE_CHILD_ACTION_MASK) { - result = buildTransitionDeviceCommand(&deviceCommandId); - } - else { - return; - } - - if (result == NOTHING_TO_SEND) { - return; - } - if (result == RETURN_OK) { - DeviceCommandMap::iterator iter = deviceCommandMap.find( - deviceCommandId); - if (iter == deviceCommandMap.end()) { - result = COMMAND_NOT_SUPPORTED; - } else if (iter->second.isExecuting) { - sif::debug << std::hex << getObjectId() - << ": DHB::buildInternalCommand: Command " - << deviceCommandId << " isExecuting" << std::endl; //so we can track misconfigurations - return; //this is an internal command, no need to report a failure here, missed reply will track if a reply is too late, otherwise, it's ok - } else { - iter->second.sendReplyTo = NO_COMMANDER; - iter->second.isExecuting = true; - cookieInfo.pendingCommand = iter; - cookieInfo.state = COOKIE_WRITE_READY; - } - } - if (result != RETURN_OK) { - triggerEvent(DEVICE_BUILDING_COMMAND_FAILED, result, deviceCommandId); - } -} - -ReturnValue_t DeviceHandlerBase::buildChildRawCommand() { - return NOTHING_TO_SEND; -} - -uint8_t DeviceHandlerBase::getReplyDelayCycles( - DeviceCommandId_t deviceCommand) { - DeviceReplyMap::iterator iter = deviceReplyMap.find(deviceCommand); - if (iter == deviceReplyMap.end()) { - return 0; - } - return iter->second.delayCycles; -} - -Mode_t DeviceHandlerBase::getTransitionSourceMode() const { - return transitionSourceMode; -} - -Submode_t DeviceHandlerBase::getTransitionSourceSubMode() const { - return transitionSourceSubMode; -} - -void DeviceHandlerBase::triggerEvent(Event event, uint32_t parameter1, - uint32_t parameter2) { - fdirInstance->triggerEvent(event, parameter1, parameter2); -} - -void DeviceHandlerBase::forwardEvent(Event event, uint32_t parameter1, - uint32_t parameter2) const { - fdirInstance->triggerEvent(event, parameter1, parameter2); -} - -void DeviceHandlerBase::doOffActivity() { -} - -ReturnValue_t DeviceHandlerBase::getParameter(uint8_t domainId, - uint16_t parameterId, ParameterWrapper* parameterWrapper, - const ParameterWrapper* newValues, uint16_t startAtIndex) { - ReturnValue_t result = fdirInstance->getParameter(domainId, parameterId, - parameterWrapper, newValues, startAtIndex); - if (result != INVALID_DOMAIN_ID) { - return result; - } - return INVALID_DOMAIN_ID; - -} - -bool DeviceHandlerBase::isTransitionalMode() { - return ((mode - & (TRANSITION_MODE_BASE_ACTION_MASK - | TRANSITION_MODE_CHILD_ACTION_MASK)) != 0); -} - -bool DeviceHandlerBase::commandIsExecuting(DeviceCommandId_t commandId) { - auto iter = deviceCommandMap.find(commandId); - if (iter != deviceCommandMap.end()) { - return iter->second.isExecuting; - } else { - return false; - } - -} - -void DeviceHandlerBase::changeHK(Mode_t mode, Submode_t submode, bool enable) { -} - -void DeviceHandlerBase::setTaskIF(PeriodicTaskIF* task_){ - executingTask = task_; -} - -// Default implementations empty. -void DeviceHandlerBase::debugInterface(uint8_t positionTracker, - object_id_t objectId, uint32_t parameter) {} - -void DeviceHandlerBase::performOperationHook() { -} - -ReturnValue_t DeviceHandlerBase::initializePoolEntries( - LocalDataPool &localDataPoolMap) { - return RETURN_OK; -} - -LocalDataPoolManager* DeviceHandlerBase::getHkManagerHandle() { - return &hkManager; -} - - -ReturnValue_t DeviceHandlerBase::initializeAfterTaskCreation() { - // In this function, the task handle should be valid if the task - // was implemented correctly. We still check to be 1000 % sure :-) - if(executingTask != nullptr) { - pstIntervalMs = executingTask->getPeriodMs(); - } - return HasReturnvaluesIF::RETURN_OK; -} - -DataSetIF* DeviceHandlerBase::getDataSetHandle(sid_t sid) { - auto iter = deviceReplyMap.find(sid.ownerSetId); - if(iter != deviceReplyMap.end()) { - return iter->second.dataSet; - } - else { - return nullptr; - } -} +#include "../devicehandlers/DeviceHandlerBase.h" +#include "../objectmanager/ObjectManager.h" +#include "../storagemanager/StorageManagerIF.h" +#include "../thermal/ThermalComponentIF.h" +#include "../devicehandlers/AcceptsDeviceResponsesIF.h" + +#include "../datapoolglob/GlobalDataSet.h" +#include "../datapoolglob/GlobalPoolVariable.h" +#include "../devicehandlers/DeviceTmReportingWrapper.h" +#include "../globalfunctions/CRC.h" +#include "../housekeeping/HousekeepingMessage.h" +#include "../ipc/MessageQueueMessage.h" +#include "../subsystem/SubsystemBase.h" +#include "../ipc/QueueFactory.h" +#include "../serviceinterface/ServiceInterfaceStream.h" + +#include + +object_id_t DeviceHandlerBase::powerSwitcherId = objects::NO_OBJECT; +object_id_t DeviceHandlerBase::rawDataReceiverId = objects::NO_OBJECT; +object_id_t DeviceHandlerBase::defaultFdirParentId = objects::NO_OBJECT; +object_id_t DeviceHandlerBase::defaultHkDestination = objects::NO_OBJECT; + +DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, + object_id_t deviceCommunication, CookieIF * comCookie, + FailureIsolationBase* fdirInstance, size_t cmdQueueSize) : + SystemObject(setObjectId), mode(MODE_OFF), submode(SUBMODE_NONE), + wiretappingMode(OFF), storedRawData(StorageManagerIF::INVALID_ADDRESS), + deviceCommunicationId(deviceCommunication), comCookie(comCookie), + healthHelper(this,setObjectId), modeHelper(this), parameterHelper(this), + actionHelper(this, nullptr), hkManager(this, nullptr), + childTransitionFailure(RETURN_OK), fdirInstance(fdirInstance), + hkSwitcher(this), defaultFDIRUsed(fdirInstance == nullptr), + switchOffWasReported(false), childTransitionDelay(5000), + transitionSourceMode(_MODE_POWER_DOWN), + transitionSourceSubMode(SUBMODE_NONE) { + commandQueue = QueueFactory::instance()->createMessageQueue(cmdQueueSize, + MessageQueueMessage::MAX_MESSAGE_SIZE); + insertInCommandMap(RAW_COMMAND_ID); + cookieInfo.state = COOKIE_UNUSED; + cookieInfo.pendingCommand = deviceCommandMap.end(); + if (comCookie == nullptr) { + sif::error << "DeviceHandlerBase: ObjectID 0x" << std::hex + << std::setw(8) << std::setfill('0') << this->getObjectId() + << std::dec << ": Do not pass nullptr as a cookie, consider " + << std::setfill(' ') << "passing a dummy cookie instead!" + << std::endl; + } + if (this->fdirInstance == nullptr) { + this->fdirInstance = new DeviceHandlerFailureIsolation(setObjectId, + defaultFdirParentId); + } +} + +void DeviceHandlerBase::setHkDestination(object_id_t hkDestination) { + this->hkDestination = hkDestination; +} + +void DeviceHandlerBase::setThermalStateRequestPoolIds( + uint32_t thermalStatePoolId, uint32_t thermalRequestPoolId) { + this->deviceThermalRequestPoolId = thermalStatePoolId; + this->deviceThermalRequestPoolId = thermalRequestPoolId; +} + + +DeviceHandlerBase::~DeviceHandlerBase() { + delete comCookie; + if (defaultFDIRUsed) { + delete fdirInstance; + } + QueueFactory::instance()->deleteMessageQueue(commandQueue); +} + +ReturnValue_t DeviceHandlerBase::performOperation(uint8_t counter) { + this->pstStep = counter; + + if (getComAction() == SEND_WRITE) { + cookieInfo.state = COOKIE_UNUSED; + readCommandQueue(); + doStateMachine(); + checkSwitchState(); + decrementDeviceReplyMap(); + fdirInstance->checkForFailures(); + hkSwitcher.performOperation(); + performOperationHook(); + } + if (mode == MODE_OFF) { + return RETURN_OK; + } + switch (getComAction()) { + case SEND_WRITE: + if ((cookieInfo.state == COOKIE_UNUSED)) { + buildInternalCommand(); + } + doSendWrite(); + break; + case GET_WRITE: + doGetWrite(); + break; + case SEND_READ: + doSendRead(); + break; + case GET_READ: + doGetRead(); + cookieInfo.state = COOKIE_UNUSED; + break; + default: + break; + } + return RETURN_OK; +} + +ReturnValue_t DeviceHandlerBase::initialize() { + ReturnValue_t result = SystemObject::initialize(); + if (result != RETURN_OK) { + return result; + } + + communicationInterface = objectManager->get( + deviceCommunicationId); + if (communicationInterface == nullptr) { + sif::error << "DeviceHandlerBase::initialize: Communication interface " + "invalid." << std::endl; + sif::error << "Make sure it is set up properly and implements" + " DeviceCommunicationIF" << std::endl; + return ObjectManagerIF::CHILD_INIT_FAILED; + } + + result = communicationInterface->initializeInterface(comCookie); + if (result != RETURN_OK) { + sif::error << "DeviceHandlerBase::initialize: Initializing " + "communication interface failed!" << std::endl; + return result; + } + + IPCStore = objectManager->get(objects::IPC_STORE); + if (IPCStore == nullptr) { + sif::error << "DeviceHandlerBase::initialize: IPC store not set up in " + "factory." << std::endl; + return ObjectManagerIF::CHILD_INIT_FAILED; + } + + if(rawDataReceiverId != objects::NO_OBJECT) { + AcceptsDeviceResponsesIF *rawReceiver = objectManager->get< + AcceptsDeviceResponsesIF>(rawDataReceiverId); + + if (rawReceiver == nullptr) { + sif::error << "DeviceHandlerBase::initialize: Raw receiver object " + "ID set but no valid object found." << std::endl; + sif::error << "Make sure the raw receiver object is set up properly" + " and implements AcceptsDeviceResponsesIF" << std::endl; + return ObjectManagerIF::CHILD_INIT_FAILED; + } + defaultRawReceiver = rawReceiver->getDeviceQueue(); + } + + if(powerSwitcherId != objects::NO_OBJECT) { + powerSwitcher = objectManager->get(powerSwitcherId); + if (powerSwitcher == nullptr) { + sif::error << "DeviceHandlerBase::initialize: Power switcher " + << "object ID set but no valid object found." << std::endl; + sif::error << "Make sure the raw receiver object is set up properly" + << " and implements PowerSwitchIF" << std::endl; + return ObjectManagerIF::CHILD_INIT_FAILED; + } + } + + result = healthHelper.initialize(); + if (result != RETURN_OK) { + return result; + } + + result = modeHelper.initialize(); + if (result != RETURN_OK) { + return result; + } + result = actionHelper.initialize(commandQueue); + if (result != RETURN_OK) { + return result; + } + result = fdirInstance->initialize(); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + result = parameterHelper.initialize(); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + result = hkSwitcher.initialize(); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + if(hkDestination == objects::NO_OBJECT) { + hkDestination = defaultHkDestination; + } + + result = hkManager.initialize(commandQueue, hkDestination); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + fillCommandAndReplyMap(); + + //Set temperature target state to NON_OP. + GlobDataSet mySet; + gp_uint8_t thermalRequest(deviceThermalRequestPoolId, &mySet, + PoolVariableIF::VAR_WRITE); + mySet.read(); + thermalRequest = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL; + mySet.commit(PoolVariableIF::VALID); + + return RETURN_OK; + +} + +void DeviceHandlerBase::decrementDeviceReplyMap() { + for (std::map::iterator iter = + deviceReplyMap.begin(); iter != deviceReplyMap.end(); iter++) { + if (iter->second.delayCycles != 0) { + iter->second.delayCycles--; + if (iter->second.delayCycles == 0) { + if (iter->second.periodic) { + iter->second.delayCycles = iter->second.maxDelayCycles; + } + replyToReply(iter, TIMEOUT); + missedReply(iter->first); + } + } + } +} + +void DeviceHandlerBase::readCommandQueue() { + + if (dontCheckQueue()) { + return; + } + + CommandMessage command; + ReturnValue_t result = commandQueue->receiveMessage(&command); + if (result != RETURN_OK) { + return; + } + + result = healthHelper.handleHealthCommand(&command); + if (result == RETURN_OK) { + return; + } + + result = modeHelper.handleModeCommand(&command); + if (result == RETURN_OK) { + return; + } + + result = actionHelper.handleActionMessage(&command); + if (result == RETURN_OK) { + return; + } + + result = parameterHelper.handleParameterMessage(&command); + if (result == RETURN_OK) { + return; + } + + result = hkManager.handleHousekeepingMessage(&command); + if (result == RETURN_OK) { + return; + } + + result = handleDeviceHandlerMessage(&command); + if (result == RETURN_OK) { + return; + } + + result = letChildHandleMessage(&command); + if (result == RETURN_OK) { + return; + } + + replyReturnvalueToCommand(CommandMessage::UNKNOWN_COMMAND); + +} + +void DeviceHandlerBase::doStateMachine() { + switch (mode) { + case _MODE_START_UP: + case _MODE_SHUT_DOWN: + case _MODE_TO_NORMAL: + case _MODE_TO_ON: + case _MODE_TO_RAW: { + Mode_t currentMode = mode; + callChildStatemachine(); + //Only do timeout if child did not change anything + if (mode != currentMode) { + break; + } + uint32_t currentUptime; + Clock::getUptime(¤tUptime); + if (currentUptime - timeoutStart >= childTransitionDelay) { + triggerEvent(MODE_TRANSITION_FAILED, childTransitionFailure, 0); + setMode(transitionSourceMode, transitionSourceSubMode); + break; + } + } + break; + case _MODE_POWER_DOWN: + commandSwitch(PowerSwitchIF::SWITCH_OFF); + setMode(_MODE_WAIT_OFF); + break; + case _MODE_POWER_ON: + commandSwitch(PowerSwitchIF::SWITCH_ON); + setMode(_MODE_WAIT_ON); + break; + case _MODE_WAIT_ON: { + uint32_t currentUptime; + Clock::getUptime(¤tUptime); + if (powerSwitcher != nullptr and currentUptime - timeoutStart >= + powerSwitcher->getSwitchDelayMs()) { + triggerEvent(MODE_TRANSITION_FAILED, PowerSwitchIF::SWITCH_TIMEOUT, + 0); + setMode(_MODE_POWER_DOWN); + callChildStatemachine(); + break; + } + ReturnValue_t switchState = getStateOfSwitches(); + if ((switchState == PowerSwitchIF::SWITCH_ON) + || (switchState == NO_SWITCH)) { + //NOTE: TransitionSourceMode and -SubMode are set by handleCommandedModeTransition + childTransitionFailure = CHILD_TIMEOUT; + setMode(_MODE_START_UP); + callChildStatemachine(); + } + } + break; + case _MODE_WAIT_OFF: { + uint32_t currentUptime; + Clock::getUptime(¤tUptime); + + if(powerSwitcher == nullptr) { + setMode(MODE_OFF); + break; + } + + if (currentUptime - timeoutStart >= powerSwitcher->getSwitchDelayMs()) { + triggerEvent(MODE_TRANSITION_FAILED, PowerSwitchIF::SWITCH_TIMEOUT, + 0); + setMode(MODE_ERROR_ON); + break; + } + ReturnValue_t switchState = getStateOfSwitches(); + if ((switchState == PowerSwitchIF::SWITCH_OFF) + || (switchState == NO_SWITCH)) { + setMode(_MODE_SWITCH_IS_OFF); + } + } + break; + case MODE_OFF: + doOffActivity(); + break; + case MODE_ON: + doOnActivity(); + break; + case MODE_RAW: + case MODE_NORMAL: + case MODE_ERROR_ON: + break; + case _MODE_SWITCH_IS_OFF: + setMode(MODE_OFF, SUBMODE_NONE); + break; + default: + triggerEvent(OBJECT_IN_INVALID_MODE, mode, submode); + setMode(_MODE_POWER_DOWN, 0); + break; + } +} + +ReturnValue_t DeviceHandlerBase::isModeCombinationValid(Mode_t mode, + Submode_t submode) { + switch (mode) { + case MODE_OFF: + case MODE_ON: + case MODE_NORMAL: + case MODE_RAW: + if (submode == SUBMODE_NONE) { + return RETURN_OK; + } else { + return INVALID_SUBMODE; + } + default: + return HasModesIF::INVALID_MODE; + } +} + +ReturnValue_t DeviceHandlerBase::insertInCommandAndReplyMap( + DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles, + size_t replyLen, bool periodic, bool hasDifferentReplyId, + DeviceCommandId_t replyId) { + //No need to check, as we may try to insert multiple times. + insertInCommandMap(deviceCommand); + if (hasDifferentReplyId) { + return insertInReplyMap(replyId, maxDelayCycles, replyLen, periodic); + } else { + return insertInReplyMap(deviceCommand, maxDelayCycles, replyLen, periodic); + } +} + +ReturnValue_t DeviceHandlerBase::insertInReplyMap(DeviceCommandId_t replyId, + uint16_t maxDelayCycles, size_t replyLen, bool periodic) { + DeviceReplyInfo info; + info.maxDelayCycles = maxDelayCycles; + info.periodic = periodic; + info.delayCycles = 0; + info.replyLen = replyLen; + info.command = deviceCommandMap.end(); + auto resultPair = deviceReplyMap.emplace(replyId, info); + if (resultPair.second) { + return RETURN_OK; + } else { + return RETURN_FAILED; + } +} + +ReturnValue_t DeviceHandlerBase::insertInCommandMap( + DeviceCommandId_t deviceCommand) { + DeviceCommandInfo info; + info.expectedReplies = 0; + info.isExecuting = false; + info.sendReplyTo = NO_COMMANDER; + auto resultPair = deviceCommandMap.emplace(deviceCommand, info); + if (resultPair.second) { + return RETURN_OK; + } else { + return RETURN_FAILED; + } +} + +ReturnValue_t DeviceHandlerBase::updateReplyMapEntry(DeviceCommandId_t deviceReply, + uint16_t delayCycles, uint16_t maxDelayCycles, bool periodic) { + std::map::iterator iter = + deviceReplyMap.find(deviceReply); + if (iter == deviceReplyMap.end()) { + triggerEvent(INVALID_DEVICE_COMMAND, deviceReply); + return RETURN_FAILED; + } else { + DeviceReplyInfo *info = &(iter->second); + if (maxDelayCycles != 0) { + info->maxDelayCycles = maxDelayCycles; + } + info->delayCycles = delayCycles; + info->periodic = periodic; + return RETURN_OK; + } +} + +void DeviceHandlerBase::callChildStatemachine() { + if (mode == _MODE_START_UP) { + doStartUp(); + } else if (mode == _MODE_SHUT_DOWN) { + doShutDown(); + } else if (mode & TRANSITION_MODE_CHILD_ACTION_MASK) { + doTransition(transitionSourceMode, transitionSourceSubMode); + } +} + +void DeviceHandlerBase::setTransition(Mode_t modeTo, Submode_t submodeTo) { + triggerEvent(CHANGING_MODE, modeTo, submodeTo); + childTransitionDelay = getTransitionDelayMs(mode, modeTo); + transitionSourceMode = mode; + transitionSourceSubMode = submode; + childTransitionFailure = CHILD_TIMEOUT; + + // transitionTargetMode is set by setMode + setMode((modeTo | TRANSITION_MODE_CHILD_ACTION_MASK), submodeTo); +} + +void DeviceHandlerBase::setMode(Mode_t newMode, uint8_t newSubmode) { + changeHK(mode, submode, false); + submode = newSubmode; + mode = newMode; + modeChanged(); + setNormalDatapoolEntriesInvalid(); + if (!isTransitionalMode()) { + modeHelper.modeChanged(newMode, newSubmode); + announceMode(false); + } + Clock::getUptime(&timeoutStart); + + if (mode == MODE_OFF) { + GlobDataSet mySet; + gp_uint8_t thermalRequest(deviceThermalRequestPoolId, &mySet, + PoolVariableIF::VAR_READ_WRITE); + mySet.read(); + if (thermalRequest != ThermalComponentIF::STATE_REQUEST_IGNORE) { + thermalRequest = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL; + } + mySet.commit(PoolVariableIF::VALID); + } + changeHK(mode, submode, true); +} + +void DeviceHandlerBase::setMode(Mode_t newMode) { + setMode(newMode, submode); +} + +void DeviceHandlerBase::replyReturnvalueToCommand(ReturnValue_t status, + uint32_t parameter) { + //This is actually the reply protocol for raw and misc DH commands. + if (status == RETURN_OK) { + CommandMessage reply(CommandMessage::REPLY_COMMAND_OK, 0, parameter); + commandQueue->reply(&reply); + } else { + CommandMessage reply(CommandMessage::REPLY_REJECTED, status, parameter); + commandQueue->reply(&reply); + } +} + +void DeviceHandlerBase::replyToCommand(ReturnValue_t status, + uint32_t parameter) { +//Check if we reply to a raw command. + if (cookieInfo.pendingCommand->first == RAW_COMMAND_ID) { + if (status == NO_REPLY_EXPECTED) { + status = RETURN_OK; + } + replyReturnvalueToCommand(status, parameter); + //Always delete data from a raw command. + IPCStore->deleteData(storedRawData); + return; + } +//Check if we were externally commanded. + if (cookieInfo.pendingCommand->second.sendReplyTo != NO_COMMANDER) { + MessageQueueId_t queueId = cookieInfo.pendingCommand->second.sendReplyTo; + if (status == NO_REPLY_EXPECTED) { + actionHelper.finish(queueId, cookieInfo.pendingCommand->first, + RETURN_OK); + } else { + actionHelper.step(1, queueId, cookieInfo.pendingCommand->first, + status); + } + } +} + +void DeviceHandlerBase::replyToReply(DeviceReplyMap::iterator iter, + ReturnValue_t status) { +//No need to check if iter exists, as this is checked by callers. If someone else uses the method, add check. + if (iter->second.command == deviceCommandMap.end()) { + //Is most likely periodic reply. Silent return. + return; + } +//Check if more replies are expected. If so, do nothing. + DeviceCommandInfo* info = &(iter->second.command->second); + if (--info->expectedReplies == 0) { + //Check if it was transition or internal command. Don't send any replies in that case. + if (info->sendReplyTo != NO_COMMANDER) { + actionHelper.finish(info->sendReplyTo, iter->first, status); + } + info->isExecuting = false; + } +} + +void DeviceHandlerBase::doSendWrite() { + if (cookieInfo.state == COOKIE_WRITE_READY) { + + ReturnValue_t result = communicationInterface->sendMessage(comCookie, + rawPacket, rawPacketLen); + + if (result == RETURN_OK) { + cookieInfo.state = COOKIE_WRITE_SENT; + } else { + //always generate a failure event, so that FDIR knows what's up + triggerEvent(DEVICE_SENDING_COMMAND_FAILED, result, + cookieInfo.pendingCommand->first); + replyToCommand(result); + cookieInfo.state = COOKIE_UNUSED; + cookieInfo.pendingCommand->second.isExecuting = false; + } + } +} + +void DeviceHandlerBase::doGetWrite() { + if (cookieInfo.state != COOKIE_WRITE_SENT) { + return; + } + cookieInfo.state = COOKIE_UNUSED; + ReturnValue_t result = communicationInterface->getSendSuccess(comCookie); + if (result == RETURN_OK) { + if (wiretappingMode == RAW) { + replyRawData(rawPacket, rawPacketLen, requestedRawTraffic, true); + } + + //We need to distinguish here, because a raw command never expects a reply. + //(Could be done in eRIRM, but then child implementations need to be careful. + result = enableReplyInReplyMap(cookieInfo.pendingCommand); + } else { + //always generate a failure event, so that FDIR knows what's up + triggerEvent(DEVICE_SENDING_COMMAND_FAILED, result, + cookieInfo.pendingCommand->first); + } + if (result != RETURN_OK) { + cookieInfo.pendingCommand->second.isExecuting = false; + } + replyToCommand(result); +} + +void DeviceHandlerBase::doSendRead() { + ReturnValue_t result; + + size_t requestLen = 0; + if(cookieInfo.pendingCommand != deviceCommandMap.end()) { + DeviceReplyIter iter = deviceReplyMap.find( + cookieInfo.pendingCommand->first); + if(iter != deviceReplyMap.end()) { + requestLen = iter->second.replyLen; + } + } + + result = communicationInterface->requestReceiveMessage(comCookie, requestLen); + + if (result == RETURN_OK) { + cookieInfo.state = COOKIE_READ_SENT; + } else { + triggerEvent(DEVICE_REQUESTING_REPLY_FAILED, result); + //We can't inform anyone, because we don't know which command was sent last. + //So, we need to wait for a timeout. + //but I think we can allow to ignore one missedReply. + ignoreMissedRepliesCount++; + cookieInfo.state = COOKIE_UNUSED; + } +} + +void DeviceHandlerBase::doGetRead() { + size_t receivedDataLen = 0; + uint8_t *receivedData = nullptr; + + if (cookieInfo.state != COOKIE_READ_SENT) { + cookieInfo.state = COOKIE_UNUSED; + return; + } + + cookieInfo.state = COOKIE_UNUSED; + + ReturnValue_t result = communicationInterface->readReceivedMessage( + comCookie, &receivedData, &receivedDataLen); + + if (result != RETURN_OK) { + triggerEvent(DEVICE_REQUESTING_REPLY_FAILED, result); + //I think we can allow to ignore one missedReply. + ignoreMissedRepliesCount++; + return; + } + + if (receivedDataLen == 0 or result == DeviceCommunicationIF::NO_REPLY_RECEIVED) + return; + + if (wiretappingMode == RAW) { + replyRawData(receivedData, receivedDataLen, requestedRawTraffic); + } + + if (mode == MODE_RAW and defaultRawReceiver != MessageQueueIF::NO_QUEUE) { + replyRawReplyIfnotWiretapped(receivedData, receivedDataLen); + } + else { + parseReply(receivedData, receivedDataLen); + } +} + +void DeviceHandlerBase::parseReply(const uint8_t* receivedData, + size_t receivedDataLen) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; + DeviceCommandId_t foundId = 0xFFFFFFFF; + size_t foundLen = 0; + // The loop may not execute more often than the number of received bytes + // (worst case). This approach avoids infinite loops due to buggy + // scanForReply routines. + uint32_t remainingLength = receivedDataLen; + for (uint32_t count = 0; count < receivedDataLen; count++) { + result = scanForReply(receivedData, remainingLength, &foundId, + &foundLen); + switch (result) { + case RETURN_OK: + handleReply(receivedData, foundId, foundLen); + if(foundLen == 0) { + sif::warning << "DeviceHandlerBase::parseReply: foundLen is 0!" + " Packet parsing will be stuck." << std::endl; + } + break; + case APERIODIC_REPLY: { + result = interpretDeviceReply(foundId, receivedData); + if (result != RETURN_OK) { + replyRawReplyIfnotWiretapped(receivedData, foundLen); + triggerEvent(DEVICE_INTERPRETING_REPLY_FAILED, result, + foundId); + } + if(foundLen == 0) { + sif::warning << "DeviceHandlerBase::parseReply: foundLen is 0!" + " Packet parsing will be stuck." << std::endl; + } + break; + } + case IGNORE_REPLY_DATA: + break; + case IGNORE_FULL_PACKET: + return; + default: + //We need to wait for timeout.. don't know what command failed and who sent it. + replyRawReplyIfnotWiretapped(receivedData, foundLen); + triggerEvent(DEVICE_READING_REPLY_FAILED, result, foundLen); + break; + } + receivedData += foundLen; + if (remainingLength > foundLen) { + remainingLength -= foundLen; + } else { + return; + } + } +} + +void DeviceHandlerBase::handleReply(const uint8_t* receivedData, + DeviceCommandId_t foundId, uint32_t foundLen) { + ReturnValue_t result; + DeviceReplyMap::iterator iter = deviceReplyMap.find(foundId); + + if (iter == deviceReplyMap.end()) { + replyRawReplyIfnotWiretapped(receivedData, foundLen); + triggerEvent(DEVICE_UNKNOWN_REPLY, foundId); + return; + } + + DeviceReplyInfo *info = &(iter->second); + + if (info->delayCycles != 0) { + + if (info->periodic != false) { + info->delayCycles = info->maxDelayCycles; + } + else { + info->delayCycles = 0; + } + + result = interpretDeviceReply(foundId, receivedData); + + if (result != RETURN_OK) { + // Report failed interpretation to FDIR. + replyRawReplyIfnotWiretapped(receivedData, foundLen); + triggerEvent(DEVICE_INTERPRETING_REPLY_FAILED, result, foundId); + } + replyToReply(iter, result); + } + else { + // Other completion failure messages are created by timeout. + // Powering down the device might take some time during which periodic + // replies may still come in. + if (mode != _MODE_WAIT_OFF) { + triggerEvent(DEVICE_UNREQUESTED_REPLY, foundId); + } + } +} + +ReturnValue_t DeviceHandlerBase::getStorageData(store_address_t storageAddress, + uint8_t** data, uint32_t * len) { + size_t lenTmp; + + if (IPCStore == nullptr) { + *data = nullptr; + *len = 0; + return RETURN_FAILED; + } + ReturnValue_t result = IPCStore->modifyData(storageAddress, data, &lenTmp); + if (result == RETURN_OK) { + *len = lenTmp; + return RETURN_OK; + } else { + triggerEvent(StorageManagerIF::GET_DATA_FAILED, result, + storageAddress.raw); + *data = nullptr; + *len = 0; + return result; + } +} + +void DeviceHandlerBase::replyRawData(const uint8_t *data, size_t len, + MessageQueueId_t sendTo, bool isCommand) { + if (IPCStore == nullptr or len == 0 or sendTo == MessageQueueIF::NO_QUEUE) { + return; + } + store_address_t address; + ReturnValue_t result = IPCStore->addData(&address, data, len); + + if (result != RETURN_OK) { + triggerEvent(StorageManagerIF::STORE_DATA_FAILED, result); + return; + } + + CommandMessage command; + + DeviceHandlerMessage::setDeviceHandlerRawReplyMessage(&command, + getObjectId(), address, isCommand); + + result = commandQueue->sendMessage(sendTo, &command); + + if (result != RETURN_OK) { + IPCStore->deleteData(address); + // Silently discard data, this indicates heavy TM traffic which + // should not be increased by additional events. + } +} + +//Default child implementations +DeviceHandlerIF::CommunicationAction_t DeviceHandlerBase::getComAction() { + switch (pstStep) { + case 0: + return SEND_WRITE; + break; + case 1: + return GET_WRITE; + break; + case 2: + return SEND_READ; + break; + case 3: + return GET_READ; + break; + default: + break; + } + return NOTHING; +} + +MessageQueueId_t DeviceHandlerBase::getCommandQueue() const { + return commandQueue->getId(); +} + +void DeviceHandlerBase::buildRawDeviceCommand(CommandMessage* commandMessage) { + storedRawData = DeviceHandlerMessage::getStoreAddress(commandMessage); + ReturnValue_t result = getStorageData(storedRawData, &rawPacket, + &rawPacketLen); + if (result != RETURN_OK) { + replyReturnvalueToCommand(result, RAW_COMMAND_ID); + storedRawData.raw = StorageManagerIF::INVALID_ADDRESS; + } else { + cookieInfo.pendingCommand = deviceCommandMap.find( + (DeviceCommandId_t) RAW_COMMAND_ID); + cookieInfo.pendingCommand->second.isExecuting = true; + cookieInfo.state = COOKIE_WRITE_READY; + } +} + +void DeviceHandlerBase::commandSwitch(ReturnValue_t onOff) { + if(powerSwitcher == nullptr) { + return; + } + const uint8_t *switches; + uint8_t numberOfSwitches = 0; + ReturnValue_t result = getSwitches(&switches, &numberOfSwitches); + if (result == RETURN_OK) { + while (numberOfSwitches > 0) { + powerSwitcher->sendSwitchCommand(switches[numberOfSwitches - 1], + onOff); + numberOfSwitches--; + } + } +} + +ReturnValue_t DeviceHandlerBase::getSwitches(const uint8_t **switches, + uint8_t *numberOfSwitches) { + return DeviceHandlerBase::NO_SWITCH; +} + +void DeviceHandlerBase::modeChanged(void) { +} + +ReturnValue_t DeviceHandlerBase::enableReplyInReplyMap( + DeviceCommandMap::iterator command, uint8_t expectedReplies, + bool useAlternativeId, DeviceCommandId_t alternativeReply) { + DeviceReplyMap::iterator iter; + if (useAlternativeId) { + iter = deviceReplyMap.find(alternativeReply); + } else { + iter = deviceReplyMap.find(command->first); + } + if (iter != deviceReplyMap.end()) { + DeviceReplyInfo *info = &(iter->second); + info->delayCycles = info->maxDelayCycles; + info->command = command; + command->second.expectedReplies = expectedReplies; + return RETURN_OK; + } else { + return NO_REPLY_EXPECTED; + } +} + +void DeviceHandlerBase::doTransition(Mode_t modeFrom, Submode_t subModeFrom) { + setMode(getBaseMode(mode)); +} + +uint32_t DeviceHandlerBase::getTransitionDelayMs(Mode_t modeFrom, + Mode_t modeTo) { + return 0; +} + +ReturnValue_t DeviceHandlerBase::getStateOfSwitches(void) { + if(powerSwitcher == nullptr) { + return NO_SWITCH; + } + uint8_t numberOfSwitches = 0; + const uint8_t *switches; + + ReturnValue_t result = getSwitches(&switches, &numberOfSwitches); + if ((result == RETURN_OK) && (numberOfSwitches != 0)) { + while (numberOfSwitches > 0) { + if (powerSwitcher->getSwitchState(switches[numberOfSwitches - 1]) + == PowerSwitchIF::SWITCH_OFF) { + return PowerSwitchIF::SWITCH_OFF; + } + numberOfSwitches--; + } + return PowerSwitchIF::SWITCH_ON; + } + + return NO_SWITCH; +} + +Mode_t DeviceHandlerBase::getBaseMode(Mode_t transitionMode) { +//only child action special modes are handled, as a child should never see any base action modes + if (transitionMode == _MODE_START_UP) { + return _MODE_TO_ON; + } + if (transitionMode == _MODE_SHUT_DOWN) { + return _MODE_POWER_DOWN; + } + return transitionMode + & ~(TRANSITION_MODE_BASE_ACTION_MASK + | TRANSITION_MODE_CHILD_ACTION_MASK); +} + +//SHOULDDO: Allow transition from OFF to NORMAL to reduce complexity in assemblies. And, by the way, throw away DHB and write a new one: +// - Include power and thermal completely, but more modular :-) +// - Don't use modes for state transitions, reduce FSM (Finte State Machine) complexity. +// - Modularization? +ReturnValue_t DeviceHandlerBase::checkModeCommand(Mode_t commandedMode, + Submode_t commandedSubmode, uint32_t* msToReachTheMode) { + if (isTransitionalMode()) { + return IN_TRANSITION; + } + if ((mode == MODE_ERROR_ON) && (commandedMode != MODE_OFF)) { + return TRANS_NOT_ALLOWED; + } + if ((commandedMode == MODE_NORMAL) && (mode == MODE_OFF)) { + return TRANS_NOT_ALLOWED; + } + + if ((commandedMode == MODE_ON) && (mode == MODE_OFF) + && (deviceThermalStatePoolId != PoolVariableIF::NO_PARAMETER)) { + GlobDataSet mySet; + gp_uint8_t thermalState(deviceThermalStatePoolId, &mySet, + PoolVariableIF::VAR_READ); + gp_uint8_t thermalRequest(deviceThermalRequestPoolId, &mySet, + PoolVariableIF::VAR_READ); + mySet.read(); + if (thermalRequest != ThermalComponentIF::STATE_REQUEST_IGNORE) { + if (!ThermalComponentIF::isOperational(thermalState)) { + triggerEvent(ThermalComponentIF::TEMP_NOT_IN_OP_RANGE, + thermalState); + return NON_OP_TEMPERATURE; + } + } + } + + return isModeCombinationValid(commandedMode, commandedSubmode); +} + +void DeviceHandlerBase::startTransition(Mode_t commandedMode, + Submode_t commandedSubmode) { + switch (commandedMode) { + case MODE_ON: + if (mode == MODE_OFF) { + transitionSourceMode = _MODE_POWER_DOWN; + transitionSourceSubMode = SUBMODE_NONE; + setMode(_MODE_POWER_ON, commandedSubmode); + //already set the delay for the child transition so we don't need to call it twice + childTransitionDelay = getTransitionDelayMs(_MODE_START_UP, + MODE_ON); + triggerEvent(CHANGING_MODE, commandedMode, commandedSubmode); + GlobDataSet mySet; + gp_int8_t thermalRequest(deviceThermalRequestPoolId, + &mySet, PoolVariableIF::VAR_READ_WRITE); + mySet.read(); + if (thermalRequest != ThermalComponentIF::STATE_REQUEST_IGNORE) { + thermalRequest = ThermalComponentIF::STATE_REQUEST_OPERATIONAL; + mySet.commit(PoolVariableIF::VALID); + } + } else { + setTransition(MODE_ON, commandedSubmode); + } + break; + case MODE_OFF: + if (mode == MODE_OFF) { + triggerEvent(CHANGING_MODE, commandedMode, commandedSubmode); + setMode(_MODE_POWER_DOWN, commandedSubmode); + } else { + //already set the delay for the child transition so we don't need to call it twice + childTransitionDelay = getTransitionDelayMs(mode, _MODE_POWER_DOWN); + transitionSourceMode = _MODE_POWER_DOWN; + transitionSourceSubMode = commandedSubmode; + childTransitionFailure = CHILD_TIMEOUT; + setMode(_MODE_SHUT_DOWN, commandedSubmode); + triggerEvent(CHANGING_MODE, commandedMode, commandedSubmode); + } + break; + case MODE_RAW: + if (mode != MODE_OFF) { + setTransition(MODE_RAW, commandedSubmode); + } else { + setMode(MODE_RAW, commandedSubmode); + } + break; + case MODE_NORMAL: + if (mode != MODE_OFF) { + setTransition(MODE_NORMAL, commandedSubmode); + } else { + replyReturnvalueToCommand(HasModesIF::TRANS_NOT_ALLOWED); + } + break; + } +} + +void DeviceHandlerBase::getMode(Mode_t* mode, Submode_t* submode) { + *mode = this->mode; + *submode = this->submode; +} + +void DeviceHandlerBase::setToExternalControl() { + healthHelper.setHealth(EXTERNAL_CONTROL); +} + +void DeviceHandlerBase::announceMode(bool recursive) { + triggerEvent(MODE_INFO, mode, submode); +} + +bool DeviceHandlerBase::dontCheckQueue() { + return false; +} + +void DeviceHandlerBase::missedReply(DeviceCommandId_t id) { + if (ignoreMissedRepliesCount > 0) { + ignoreMissedRepliesCount--; + } else { + triggerEvent(DEVICE_MISSED_REPLY, id); + } +} + +HasHealthIF::HealthState DeviceHandlerBase::getHealth() { + return healthHelper.getHealth(); +} + +ReturnValue_t DeviceHandlerBase::setHealth(HealthState health) { + healthHelper.setHealth(health); + return HasReturnvaluesIF::RETURN_OK; +} + +void DeviceHandlerBase::checkSwitchState() { + if ((mode == MODE_ON || mode == MODE_NORMAL)) { + //We only check in ON and NORMAL, ignore RAW and ERROR_ON. + ReturnValue_t result = getStateOfSwitches(); + if (result == PowerSwitchIF::SWITCH_OFF && !switchOffWasReported) { + triggerEvent(PowerSwitchIF::SWITCH_WENT_OFF); + switchOffWasReported = true; + } + } else { + switchOffWasReported = false; + } +} + +void DeviceHandlerBase::doOnActivity() { +} + +ReturnValue_t DeviceHandlerBase::acceptExternalDeviceCommands() { + if ((mode != MODE_ON) && (mode != MODE_NORMAL)) { + return WRONG_MODE_FOR_COMMAND; + } + return RETURN_OK; +} + +void DeviceHandlerBase::replyRawReplyIfnotWiretapped(const uint8_t* data, + size_t len) { + if ((wiretappingMode == RAW) + && (defaultRawReceiver == requestedRawTraffic)) { + //The raw packet was already sent by the wiretapping service + } else { + replyRawData(data, len, defaultRawReceiver); + } +} + +ReturnValue_t DeviceHandlerBase::handleDeviceHandlerMessage( + CommandMessage * message) { + switch (message->getCommand()) { + case DeviceHandlerMessage::CMD_WIRETAPPING: + switch (DeviceHandlerMessage::getWiretappingMode(message)) { + case RAW: + wiretappingMode = RAW; + requestedRawTraffic = commandQueue->getLastPartner(); + break; + case TM: + wiretappingMode = TM; + requestedRawTraffic = commandQueue->getLastPartner(); + break; + case OFF: + wiretappingMode = OFF; + break; + default: + replyReturnvalueToCommand(INVALID_COMMAND_PARAMETER); + wiretappingMode = OFF; + return RETURN_OK; + } + replyReturnvalueToCommand(RETURN_OK); + return RETURN_OK; +// case DeviceHandlerMessage::CMD_SWITCH_IOBOARD: +// if (mode != MODE_OFF) { +// replyReturnvalueToCommand(WRONG_MODE_FOR_COMMAND); +// } else { +// result = switchCookieChannel( +// DeviceHandlerMessage::getIoBoardObjectId(message)); +// if (result == RETURN_OK) { +// replyReturnvalueToCommand(RETURN_OK); +// } else { +// replyReturnvalueToCommand(CANT_SWITCH_IO_ADDRESS); +// } +// } +// return RETURN_OK; + case DeviceHandlerMessage::CMD_RAW: + if ((mode != MODE_RAW)) { + DeviceHandlerMessage::clear(message); + replyReturnvalueToCommand(WRONG_MODE_FOR_COMMAND); + } else { + buildRawDeviceCommand(message); + } + return RETURN_OK; + default: + return RETURN_FAILED; + } +} + +void DeviceHandlerBase::setParentQueue(MessageQueueId_t parentQueueId) { + modeHelper.setParentQueue(parentQueueId); + healthHelper.setParentQueue(parentQueueId); +} + +bool DeviceHandlerBase::isAwaitingReply() { + std::map::iterator iter; + for (iter = deviceReplyMap.begin(); iter != deviceReplyMap.end(); ++iter) { + if (iter->second.delayCycles != 0) { + return true; + } + } + return false; +} + +ReturnValue_t DeviceHandlerBase::letChildHandleMessage( + CommandMessage * message) { + return RETURN_FAILED; +} + +void DeviceHandlerBase::handleDeviceTM(SerializeIF* data, + DeviceCommandId_t replyId, bool neverInDataPool, bool forceDirectTm) { + DeviceReplyMap::iterator iter = deviceReplyMap.find(replyId); + if (iter == deviceReplyMap.end()) { + triggerEvent(DEVICE_UNKNOWN_REPLY, replyId); + return; + } + DeviceTmReportingWrapper wrapper(getObjectId(), replyId, data); + //replies to a command + if (iter->second.command != deviceCommandMap.end()) + { + MessageQueueId_t queueId = iter->second.command->second.sendReplyTo; + + if (queueId != NO_COMMANDER) { + //This may fail, but we'll ignore the fault. + actionHelper.reportData(queueId, replyId, data); + } + + //This check should make sure we get any TM but don't get anything doubled. + if (wiretappingMode == TM && (requestedRawTraffic != queueId)) { + actionHelper.reportData(requestedRawTraffic, replyId, &wrapper); + } + else if (forceDirectTm and (defaultRawReceiver != queueId) and + (defaultRawReceiver != MessageQueueIF::NO_QUEUE)) + { + // hiding of sender needed so the service will handle it as + // unexpected Data, no matter what state (progress or completed) + // it is in + actionHelper.reportData(defaultRawReceiver, replyId, &wrapper, + true); + } + } + //unrequested/aperiodic replies + else + { + if (wiretappingMode == TM) { + actionHelper.reportData(requestedRawTraffic, replyId, &wrapper); + } + else if (forceDirectTm and defaultRawReceiver != + MessageQueueIF::NO_QUEUE) + { + // hiding of sender needed so the service will handle it as + // unexpected Data, no matter what state (progress or completed) + // it is in + actionHelper.reportData(defaultRawReceiver, replyId, &wrapper, + true); + } + } + //Try to cast to GlobDataSet and commit data. + if (!neverInDataPool) { + GlobDataSet* dataSet = dynamic_cast(data); + if (dataSet != NULL) { + dataSet->commit(PoolVariableIF::VALID); + } + } +} + +ReturnValue_t DeviceHandlerBase::executeAction(ActionId_t actionId, + MessageQueueId_t commandedBy, const uint8_t* data, size_t size) { + ReturnValue_t result = acceptExternalDeviceCommands(); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + DeviceCommandMap::iterator iter = deviceCommandMap.find(actionId); + if (iter == deviceCommandMap.end()) { + result = COMMAND_NOT_SUPPORTED; + } else if (iter->second.isExecuting) { + result = COMMAND_ALREADY_SENT; + } else { + result = buildCommandFromCommand(actionId, data, size); + } + if (result == RETURN_OK) { + iter->second.sendReplyTo = commandedBy; + iter->second.isExecuting = true; + cookieInfo.pendingCommand = iter; + cookieInfo.state = COOKIE_WRITE_READY; + } + return result; +} + +void DeviceHandlerBase::buildInternalCommand(void) { +//Neither Raw nor Direct could build a command + ReturnValue_t result = NOTHING_TO_SEND; + DeviceCommandId_t deviceCommandId = NO_COMMAND_ID; + if (mode == MODE_NORMAL) { + result = buildNormalDeviceCommand(&deviceCommandId); + if (result == BUSY) { + //so we can track misconfigurations + sif::debug << std::hex << getObjectId() + << ": DHB::buildInternalCommand: Busy" << std::endl; + result = NOTHING_TO_SEND; //no need to report this + } + } + else if (mode == MODE_RAW) { + result = buildChildRawCommand(); + deviceCommandId = RAW_COMMAND_ID; + } + else if (mode & TRANSITION_MODE_CHILD_ACTION_MASK) { + result = buildTransitionDeviceCommand(&deviceCommandId); + } + else { + return; + } + + if (result == NOTHING_TO_SEND) { + return; + } + if (result == RETURN_OK) { + DeviceCommandMap::iterator iter = deviceCommandMap.find( + deviceCommandId); + if (iter == deviceCommandMap.end()) { + result = COMMAND_NOT_SUPPORTED; + } else if (iter->second.isExecuting) { + sif::debug << std::hex << getObjectId() + << ": DHB::buildInternalCommand: Command " + << deviceCommandId << " isExecuting" << std::endl; //so we can track misconfigurations + return; //this is an internal command, no need to report a failure here, missed reply will track if a reply is too late, otherwise, it's ok + } else { + iter->second.sendReplyTo = NO_COMMANDER; + iter->second.isExecuting = true; + cookieInfo.pendingCommand = iter; + cookieInfo.state = COOKIE_WRITE_READY; + } + } + if (result != RETURN_OK) { + triggerEvent(DEVICE_BUILDING_COMMAND_FAILED, result, deviceCommandId); + } +} + +ReturnValue_t DeviceHandlerBase::buildChildRawCommand() { + return NOTHING_TO_SEND; +} + +uint8_t DeviceHandlerBase::getReplyDelayCycles( + DeviceCommandId_t deviceCommand) { + DeviceReplyMap::iterator iter = deviceReplyMap.find(deviceCommand); + if (iter == deviceReplyMap.end()) { + return 0; + } + return iter->second.delayCycles; +} + +Mode_t DeviceHandlerBase::getTransitionSourceMode() const { + return transitionSourceMode; +} + +Submode_t DeviceHandlerBase::getTransitionSourceSubMode() const { + return transitionSourceSubMode; +} + +void DeviceHandlerBase::triggerEvent(Event event, uint32_t parameter1, + uint32_t parameter2) { + fdirInstance->triggerEvent(event, parameter1, parameter2); +} + +void DeviceHandlerBase::forwardEvent(Event event, uint32_t parameter1, + uint32_t parameter2) const { + fdirInstance->triggerEvent(event, parameter1, parameter2); +} + +void DeviceHandlerBase::doOffActivity() { +} + +ReturnValue_t DeviceHandlerBase::getParameter(uint8_t domainId, + uint16_t parameterId, ParameterWrapper* parameterWrapper, + const ParameterWrapper* newValues, uint16_t startAtIndex) { + ReturnValue_t result = fdirInstance->getParameter(domainId, parameterId, + parameterWrapper, newValues, startAtIndex); + if (result != INVALID_DOMAIN_ID) { + return result; + } + return INVALID_DOMAIN_ID; + +} + +bool DeviceHandlerBase::isTransitionalMode() { + return ((mode + & (TRANSITION_MODE_BASE_ACTION_MASK + | TRANSITION_MODE_CHILD_ACTION_MASK)) != 0); +} + +bool DeviceHandlerBase::commandIsExecuting(DeviceCommandId_t commandId) { + auto iter = deviceCommandMap.find(commandId); + if (iter != deviceCommandMap.end()) { + return iter->second.isExecuting; + } else { + return false; + } + +} + +void DeviceHandlerBase::changeHK(Mode_t mode, Submode_t submode, bool enable) { +} + +void DeviceHandlerBase::setTaskIF(PeriodicTaskIF* task_){ + executingTask = task_; +} + +// Default implementations empty. +void DeviceHandlerBase::debugInterface(uint8_t positionTracker, + object_id_t objectId, uint32_t parameter) {} + +void DeviceHandlerBase::performOperationHook() { +} + +ReturnValue_t DeviceHandlerBase::initializePoolEntries( + LocalDataPool &localDataPoolMap) { + return RETURN_OK; +} + +LocalDataPoolManager* DeviceHandlerBase::getHkManagerHandle() { + return &hkManager; +} + + +ReturnValue_t DeviceHandlerBase::initializeAfterTaskCreation() { + // In this function, the task handle should be valid if the task + // was implemented correctly. We still check to be 1000 % sure :-) + if(executingTask != nullptr) { + pstIntervalMs = executingTask->getPeriodMs(); + } + return HasReturnvaluesIF::RETURN_OK; +} + +DataSetIF* DeviceHandlerBase::getDataSetHandle(sid_t sid) { + auto iter = deviceReplyMap.find(sid.ownerSetId); + if(iter != deviceReplyMap.end()) { + return iter->second.dataSet; + } + else { + return nullptr; + } +} diff --git a/devicehandlers/DeviceHandlerBase.h b/devicehandlers/DeviceHandlerBase.h index 632db5e0..7add48e4 100644 --- a/devicehandlers/DeviceHandlerBase.h +++ b/devicehandlers/DeviceHandlerBase.h @@ -1,1207 +1,1207 @@ -#ifndef FRAMEWORK_DEVICEHANDLERS_DEVICEHANDLERBASE_H_ -#define FRAMEWORK_DEVICEHANDLERS_DEVICEHANDLERBASE_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Factory{ -void setStaticFrameworkObjectIds(); -} - -class StorageManagerIF; - -/** - * @defgroup devices Devices - * Contains all devices and the DeviceHandlerBase class. - */ - -/** - * @brief This is the abstract base class for device handlers. - * @details - * Documentation: Dissertation Baetz p.138,139, p.141-149 - * - * It features handling of @link DeviceHandlerIF::Mode_t Modes @endlink, - * communication with physical devices, using the @link DeviceCommunicationIF @endlink, - * and communication with commanding objects. - * It inherits SystemObject and thus can be created by the ObjectManagerIF. - * - * This class uses the opcode of ExecutableObjectIF to perform a step-wise execution. - * For each step an RMAP action is selected and executed. - * If data has been received (GET_READ), the data will be interpreted. - * The action for each step can be defined by the child class but as most - * device handlers share a 4-call (sendRead-getRead-sendWrite-getWrite) structure, - * a default implementation is provided. - * NOTE: RMAP is a standard which is used for FLP. - * RMAP communication is not mandatory for projects implementing the FSFW. - * However, the communication principles are similar to RMAP as there are - * two write and two send calls involved. - * - * Device handler instances should extend this class and implement the abstract - * functions. Components and drivers can send so called cookies which are used - * for communication and contain information about the communcation (e.g. slave - * address for I2C or RMAP structs). - * The following abstract methods must be implemented by a device handler: - * 1. doStartUp() - * 2. doShutDown() - * 3. buildTransitionDeviceCommand() - * 4. buildNormalDeviceCommand() - * 5. buildCommandFromCommand() - * 6. fillCommandAndReplyMap() - * 7. scanForReply() - * 8. interpretDeviceReply() - * - * Other important virtual methods with a default implementation - * are the getTransitionDelayMs() function and the getSwitches() function. - * Please ensure that getSwitches() returns DeviceHandlerIF::NO_SWITCHES if - * power switches are not implemented yet. Otherwise, the device handler will - * not transition to MODE_ON, even if setMode(MODE_ON) is called. - * If a transition to MODE_ON is desired without commanding, override the - * intialize() function and call setMode(_MODE_START_UP) before calling - * DeviceHandlerBase::initialize(). - * - * @ingroup devices - */ -class DeviceHandlerBase: public DeviceHandlerIF, - public HasReturnvaluesIF, - public ExecutableObjectIF, - public SystemObject, - public HasModesIF, - public HasHealthIF, - public HasActionsIF, - public ReceivesParameterMessagesIF, - public HasLocalDataPoolIF { - friend void (Factory::setStaticFrameworkObjectIds)(); -public: - /** - * The constructor passes the objectId to the SystemObject(). - * - * @param setObjectId the ObjectId to pass to the SystemObject() Constructor - * @param maxDeviceReplyLen the length the RMAP getRead call will be sent with - * @param setDeviceSwitch the switch the device is connected to, - * for devices using two switches, overwrite getSwitches() - * @param deviceCommuncation Communcation Interface object which is used - * to implement communication functions - * @param thermalStatePoolId - * @param thermalRequestPoolId - * @param fdirInstance - * @param cmdQueueSize - */ - DeviceHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication, - CookieIF * comCookie, FailureIsolationBase* fdirInstance = nullptr, - size_t cmdQueueSize = 20); - - void setHkDestination(object_id_t hkDestination); - void setThermalStateRequestPoolIds(uint32_t thermalStatePoolId, - uint32_t thermalRequestPoolId); - - /** - * @brief This function is the device handler base core component and is - * called periodically. - * @details - * General sequence, showing where abstract virtual functions are called: - * If the State is SEND_WRITE: - * 1. Set the cookie state to COOKIE_UNUSED and read the command queue - * 2. Handles Device State Modes by calling doStateMachine(). - * This function calls callChildStatemachine() which calls the - * abstract functions doStartUp() and doShutDown() - * 3. Check switch states by calling checkSwitchStates() - * 4. Decrements counter for timeout of replies by calling - * decrementDeviceReplyMap() - * 5. Performs FDIR check for failures - * 6. Calls hkSwitcher.performOperation() - * 7. If the device mode is MODE_OFF, return RETURN_OK. - * Otherwise, perform the Action property and performs depending - * on value specified by input value counter (incremented in PST). - * The child class tells base class what to do by setting this value. - * - SEND_WRITE: Send data or commands to device by calling - * doSendWrite() which calls sendMessage function - * of #communicationInterface - * and calls buildInternalCommand if the cookie state is COOKIE_UNUSED - * - GET_WRITE: Get ackknowledgement for sending by calling doGetWrite() - * which calls getSendSuccess of #communicationInterface. - * Calls abstract functions scanForReply() and interpretDeviceReply(). - * - SEND_READ: Request reading data from device by calling doSendRead() - * which calls requestReceiveMessage of #communcationInterface - * - GET_READ: Access requested reading data by calling doGetRead() - * which calls readReceivedMessage of #communicationInterface - * @param counter Specifies which Action to perform - * @return RETURN_OK for successful execution - */ - virtual ReturnValue_t performOperation(uint8_t counter); - - /** - * @brief Initializes the device handler - * @details - * Initialize Device Handler as system object and - * initializes all important helper classes. - * Calls fillCommandAndReplyMap(). - * @return - */ - virtual ReturnValue_t initialize(); - /** Destructor. */ - virtual ~DeviceHandlerBase(); - -protected: - /** - * @brief This is used to let the child class handle the transition from - * mode @c _MODE_START_UP to @c MODE_ON - * @details - * It is only called when the device handler is in mode @c _MODE_START_UP. - * That means, the device switch(es) are already set to on. - * Device handler commands are read and can be handled by the child class. - * If the child class handles a command, it should also send - * an reply accordingly. - * If an Command is not handled (ie #DeviceHandlerCommand is not @c CMD_NONE, - * the base class handles rejecting the command and sends a reply. - * The replies for mode transitions are handled by the base class. - * - * - If the device is started and ready for operation, the mode should be - * set to MODE_ON. It is possible to set the mode to _MODE_TO_ON to - * use the to on transition if available. - * - If the power-up fails, the mode should be set to _MODE_POWER_DOWN - * which will lead to the device being powered off. - * - If the device does not change the mode, the mode will be changed - * to _MODE_POWER_DOWN, after the timeout (from getTransitionDelay()) - * has passed. - * - * #transitionFailure can be set to a failure code indicating the reason - * for a failed transition - */ - virtual void doStartUp() = 0; - - /** - * @brief This is used to let the child class handle the transition - * from mode @c _MODE_SHUT_DOWN to @c _MODE_POWER_DOWN - * @details - * It is only called when the device handler is in mode @c _MODE_SHUT_DOWN. - * Device handler commands are read and can be handled by the child class. - * If the child class handles a command, it should also send an reply - * accordingly. - * If an Command is not handled (ie #DeviceHandlerCommand is not - * @c CMD_NONE, the base class handles rejecting the command and sends a - * reply. The replies for mode transitions are handled by the base class. - * - * - If the device ready to be switched off, - * the mode should be set to _MODE_POWER_DOWN. - * - If the device should not be switched off, the mode can be changed to - * _MODE_TO_ON (or MODE_ON if no transition is needed). - * - If the device does not change the mode, the mode will be changed to - * _MODE_POWER_DOWN, when the timeout (from getTransitionDelay()) - * has passed. - * - * #transitionFailure can be set to a failure code indicating the reason - * for a failed transition - */ - virtual void doShutDown() = 0; - - /** - * Build the device command to send for normal mode. - * - * This is only called in @c MODE_NORMAL. If multiple submodes for - * @c MODE_NORMAL are supported, different commands can built, - * depending on the submode. - * - * #rawPacket and #rawPacketLen must be set by this method to the - * packet to be sent. If variable command frequence is required, a counter - * can be used and the frequency in the reply map has to be set manually - * by calling updateReplyMap(). - * - * @param[out] id the device command id that has been built - * @return - * - @c RETURN_OK to send command after setting #rawPacket and #rawPacketLen. - * - @c NOTHING_TO_SEND when no command is to be sent. - * - Anything else triggers an even with the returnvalue as a parameter. - */ - virtual ReturnValue_t buildNormalDeviceCommand(DeviceCommandId_t * id) = 0; - - /** - * Build the device command to send for a transitional mode. - * - * This is only called in @c _MODE_TO_NORMAL, @c _MODE_TO_ON, @c _MODE_TO_RAW, - * @c _MODE_START_UP and @c _MODE_SHUT_DOWN. So it is used by doStartUp() - * and doShutDown() as well as doTransition(), by setting those - * modes in the respective functions. - * - * A good idea is to implement a flag indicating a command has to be built - * and a variable containing the command number to be built - * and filling them in doStartUp(), doShutDown() and doTransition() so no - * modes have to be checked here. - * - * #rawPacket and #rawPacketLen must be set by this method to the packet to be sent. - * - * @param[out] id the device command id built - * @return - * - @c RETURN_OK when a command is to be sent - * - @c NOTHING_TO_SEND when no command is to be sent - * - Anything else triggers an even with the returnvalue as a parameter - */ - virtual ReturnValue_t buildTransitionDeviceCommand(DeviceCommandId_t * id) = 0; - - /** - * @brief Build a device command packet from data supplied by a direct command. - * - * @details - * #rawPacket and #rawPacketLen should be set by this method to the packet to be sent. - * The existence of the command in the command map and the command size check - * against 0 are done by the base class. - * - * @param deviceCommand the command to build, already checked against deviceCommandMap - * @param commandData pointer to the data from the direct command - * @param commandDataLen length of commandData - * @return - * - @c RETURN_OK to send command after #rawPacket and #rawPacketLen have been set. - * - Anything else triggers an event with the returnvalue as a parameter - */ - virtual ReturnValue_t buildCommandFromCommand(DeviceCommandId_t deviceCommand, - const uint8_t * commandData, size_t commandDataLen) = 0; - - /** - * @brief Scans a buffer for a valid reply. - * @details - * This is used by the base class to check the data received for valid packets. - * It only checks if a valid packet starts at @c start. - * It also only checks the structural validy of the packet, - * e.g. checksums lengths and protocol data. No information check is done, - * e.g. range checks etc. - * - * Errors should be reported directly, the base class does NOT report any - * errors based on the return value of this function. - * - * @param start start of remaining buffer to be scanned - * @param len length of remaining buffer to be scanned - * @param[out] foundId the id of the data found in the buffer. - * @param[out] foundLen length of the data found. Is to be set in function, - * buffer is scanned at previous position + foundLen. - * @return - * - @c RETURN_OK a valid packet was found at @c start, @c foundLen is valid - * - @c RETURN_FAILED no reply could be found starting at @c start, - * implies @c foundLen is not valid, base class will call scanForReply() - * again with ++start - * - @c DeviceHandlerIF::INVALID_DATA a packet was found but it is invalid, - * e.g. checksum error, implies @c foundLen is valid, can be used to - * skip some bytes - * - @c DeviceHandlerIF::LENGTH_MISSMATCH @c len is invalid - * - @c DeviceHandlerIF::IGNORE_REPLY_DATA Ignore this specific part of - * the packet - * - @c DeviceHandlerIF::IGNORE_FULL_PACKET Ignore the packet - * - @c APERIODIC_REPLY if a valid reply is received that has not been - * requested by a command, but should be handled anyway - * (@see also fillCommandAndCookieMap() ) - */ - virtual ReturnValue_t scanForReply(const uint8_t *start, size_t len, - DeviceCommandId_t *foundId, size_t *foundLen) = 0; - - /** - * @brief Interpret a reply from the device. - * @details - * This is called after scanForReply() found a valid packet, it can be - * assumed that the length and structure is valid. - * This routine extracts the data from the packet into a DataSet and then - * calls handleDeviceTM(), which either sends a TM packet or stores the - * data in the DataPool depending on whether it was an external command. - * No packet length is given, as it should be defined implicitly by the id. - * - * @param id the id found by scanForReply() - * @param packet - * @return - * - @c RETURN_OK when the reply was interpreted. - * - @c RETURN_FAILED when the reply could not be interpreted, - * e.g. logical errors or range violations occurred - */ - virtual ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, - const uint8_t *packet) = 0; - - /** - * @brief fill the #DeviceCommandMap and #DeviceReplyMap - * called by the initialize() of the base class - * @details - * This is used to let the base class know which replies are expected. - * There are different scenarios regarding this: - * - * - "Normal" commands. These are commands, that trigger a direct reply - * from the device. In this case, the id of the command should be added - * to the command map with a commandData_t where maxDelayCycles is set - * to the maximum expected number of PST cycles the reply will take. - * Then, scanForReply returns the id of the command and the base class - * can handle time-out and missing replies. - * - * - Periodic, unrequested replies. These are replies that, once enabled, - * are sent by the device on its own in a defined interval. - * In this case, the id of the reply or a placeholder id should be added - * to the deviceCommandMap with a commandData_t where maxDelayCycles is - * set to the maximum expected number of PST cycles between two replies - * (also a tolerance should be added, as an FDIR message will be - * generated if it is missed). - * - * (Robin) This part confuses me. "must do as soon as" implies that - * the developer must do something somewhere else in the code. Is - * that really the case? If I understood correctly, DHB performs - * almost everything (e.g. in erirm function) as long as the commands - * are inserted correctly. - * - * As soon as the replies are enabled, DeviceCommandInfo.periodic must - * be set to true, DeviceCommandInfo.delayCycles to - * DeviceCommandInfo.maxDelayCycles. - * From then on, the base class handles the reception. - * Then, scanForReply returns the id of the reply or the placeholder id - * and the base class will take care of checking that all replies are - * received and the interval is correct. - * When the replies are disabled, DeviceCommandInfo.periodic must be set - * to 0, DeviceCommandInfo.delayCycles to 0; - * - * - Aperiodic, unrequested replies. These are replies that are sent - * by the device without any preceding command and not in a defined - * interval. These are not entered in the deviceCommandMap but - * handled by returning @c APERIODIC_REPLY in scanForReply(). - */ - virtual void fillCommandAndReplyMap() = 0; - - /** - * This is a helper method to facilitate inserting entries in the command map. - * @param deviceCommand Identifier of the command to add. - * @param maxDelayCycles The maximum number of delay cycles the command - * waits until it times out. - * @param replyLen Will be supplied to the requestReceiveMessage call of - * the communication interface. - * @param periodic Indicates if the command is periodic (i.e. it is sent - * by the device repeatedly without request) or not. Default is aperiodic (0) - * @return - @c RETURN_OK when the command was successfully inserted, - * - @c RETURN_FAILED else. - */ - ReturnValue_t insertInCommandAndReplyMap(DeviceCommandId_t deviceCommand, - uint16_t maxDelayCycles, size_t replyLen = 0, bool periodic = false, - bool hasDifferentReplyId = false, DeviceCommandId_t replyId = 0); - - /** - * @brief This is a helper method to insert replies in the reply map. - * @param deviceCommand Identifier of the reply to add. - * @param maxDelayCycles The maximum number of delay cycles the reply waits - * until it times out. - * @param periodic Indicates if the command is periodic (i.e. it is sent - * by the device repeatedly without request) or not. Default is aperiodic (0) - * @return - @c RETURN_OK when the command was successfully inserted, - * - @c RETURN_FAILED else. - */ - ReturnValue_t insertInReplyMap(DeviceCommandId_t deviceCommand, - uint16_t maxDelayCycles, size_t replyLen = 0, bool periodic = false); - - /** - * @brief A simple command to add a command to the commandList. - * @param deviceCommand The command to add - * @return - @c RETURN_OK when the command was successfully inserted, - * - @c RETURN_FAILED else. - */ - ReturnValue_t insertInCommandMap(DeviceCommandId_t deviceCommand); - /** - * @brief This is a helper method to facilitate updating entries - * in the reply map. - * @param deviceCommand Identifier of the reply to update. - * @param delayCycles The current number of delay cycles to wait. - * As stated in #fillCommandAndCookieMap, to disable periodic commands, - * this is set to zero. - * @param maxDelayCycles The maximum number of delay cycles the reply waits - * until it times out. By passing 0 the entry remains untouched. - * @param periodic Indicates if the command is periodic (i.e. it is sent - * by the device repeatedly without request) or not.Default is aperiodic (0). - * Warning: The setting always overrides the value that was entered in the map. - * @return - @c RETURN_OK when the command was successfully inserted, - * - @c RETURN_FAILED else. - */ - ReturnValue_t updateReplyMapEntry(DeviceCommandId_t deviceReply, - uint16_t delayCycles, uint16_t maxDelayCycles, - bool periodic = false); - - /** - * @brief Can be implemented by child handler to - * perform debugging - * @details Example: Calling this in performOperation - * to track values like mode. - * @param positionTracker Provide the child handler a way to know - * where the debugInterface was called - * @param objectId Provide the child handler object Id to - * specify actions for spefic devices - * @param parameter Supply a parameter of interest - * Please delete all debugInterface calls in DHB after debugging is finished ! - */ - virtual void debugInterface(uint8_t positionTracker = 0, - object_id_t objectId = 0, uint32_t parameter = 0); - - /** - * Get the time needed to transit from modeFrom to modeTo. - * - * Used for the following transitions: - * modeFrom -> modeTo: - * MODE_ON -> [MODE_ON, MODE_NORMAL, MODE_RAW, _MODE_POWER_DOWN] - * MODE_NORMAL -> [MODE_ON, MODE_NORMAL, MODE_RAW, _MODE_POWER_DOWN] - * MODE_RAW -> [MODE_ON, MODE_NORMAL, MODE_RAW, _MODE_POWER_DOWN] - * _MODE_START_UP -> MODE_ON (do not include time to set the switches, - * the base class got you covered) - * - * The default implementation returns 0 ! - * @param modeFrom - * @param modeTo - * @return time in ms - */ - virtual uint32_t getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo); - - /** - * Return the switches connected to the device. - * - * The default implementation returns one switch set in the ctor. - * - * @param[out] switches pointer to an array of switches - * @param[out] numberOfSwitches length of returned array - * @return - * - @c RETURN_OK if the parameters were set - * - @c RETURN_FAILED if no switches exist - */ - virtual ReturnValue_t getSwitches(const uint8_t **switches, - uint8_t *numberOfSwitches); - - /** - * This function is used to initialize the local housekeeping pool - * entries. The default implementation leaves the pool empty. - * @param localDataPoolMap - * @return - */ - virtual ReturnValue_t initializePoolEntries( - LocalDataPool& localDataPoolMap) override; - - /** Get the HK manager object handle */ - virtual LocalDataPoolManager* getHkManagerHandle() override; - - /** - * @brief Hook function for child handlers which is called once per - * performOperation(). Default implementation is empty. - */ - virtual void performOperationHook(); -public: - /** - * @param parentQueueId - */ - virtual void setParentQueue(MessageQueueId_t parentQueueId); - - /** @brief Implementation required for HasActionIF */ - ReturnValue_t executeAction(ActionId_t actionId, - MessageQueueId_t commandedBy, const uint8_t* data, - size_t size) override; - - Mode_t getTransitionSourceMode() const; - Submode_t getTransitionSourceSubMode() const; - virtual void getMode(Mode_t *mode, Submode_t *submode); - HealthState getHealth(); - ReturnValue_t setHealth(HealthState health); - virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, - ParameterWrapper *parameterWrapper, - const ParameterWrapper *newValues, uint16_t startAtIndex) override; - /** - * Implementation of ExecutableObjectIF function - * - * Used to setup the reference of the task, that executes this component - * @param task_ Pointer to the taskIF of this task - */ - virtual void setTaskIF(PeriodicTaskIF* task_); - virtual MessageQueueId_t getCommandQueue(void) const; - -protected: - /** - * The Returnvalues id of this class, required by HasReturnvaluesIF - */ - static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_BASE; - - static const ReturnValue_t INVALID_CHANNEL = MAKE_RETURN_CODE(0xA0); - // Returnvalues for scanForReply() - static const ReturnValue_t APERIODIC_REPLY = MAKE_RETURN_CODE(0xB0); //!< This is used to specify for replies from a device which are not replies to requests - static const ReturnValue_t IGNORE_REPLY_DATA = MAKE_RETURN_CODE(0xB1); //!< Ignore parts of the received packet - static const ReturnValue_t IGNORE_FULL_PACKET = MAKE_RETURN_CODE(0xB2); //!< Ignore full received packet - // Returnvalues for command building - static const ReturnValue_t NOTHING_TO_SEND = MAKE_RETURN_CODE(0xC0); //!< Return this if no command sending in required - static const ReturnValue_t COMMAND_MAP_ERROR = MAKE_RETURN_CODE(0xC2); - // Returnvalues for getSwitches() - static const ReturnValue_t NO_SWITCH = MAKE_RETURN_CODE(0xD0); - // Mode handling error Codes - static const ReturnValue_t CHILD_TIMEOUT = MAKE_RETURN_CODE(0xE0); - static const ReturnValue_t SWITCH_FAILED = MAKE_RETURN_CODE(0xE1); - - static const DeviceCommandId_t RAW_COMMAND_ID = -1; - static const DeviceCommandId_t NO_COMMAND_ID = -2; - static const MessageQueueId_t NO_COMMANDER = 0; - - /** Pointer to the raw packet that will be sent.*/ - uint8_t *rawPacket = nullptr; - /** Size of the #rawPacket. */ - uint32_t rawPacketLen = 0; - - /** - * The mode the device handler is currently in. - * This should never be changed directly but only with setMode() - */ - Mode_t mode; - /** - * The submode the device handler is currently in. - * This should never be changed directly but only with setMode() - */ - Submode_t submode; - - /** This is the counter value from performOperation(). */ - uint8_t pstStep = 0; - uint32_t pstIntervalMs = 0; - - /** - * Wiretapping flag: - * - * indicates either that all raw messages to and from the device should be - * sent to #defaultRawReceiver - * or that all device TM should be downlinked to #defaultRawReceiver. - */ - enum WiretappingMode { - OFF = 0, RAW = 1, TM = 2 - } wiretappingMode; - /** - * @brief A message queue that accepts raw replies - * - * Statically initialized in initialize() to a configurable object. - * Used when there is no method of finding a recipient, ie raw mode and - * reporting erroneous replies - */ - MessageQueueId_t defaultRawReceiver = MessageQueueIF::NO_QUEUE; - store_address_t storedRawData; - - /** - * @brief The message queue which wants to read all raw traffic - * If #isWiretappingActive all raw communication from and to the device - * will be sent to this queue - */ - MessageQueueId_t requestedRawTraffic = 0; - - /** - * Pointer to the IPCStore. - * This caches the pointer received from the objectManager in the constructor. - */ - StorageManagerIF *IPCStore = nullptr; - /** The comIF object ID is cached for the intialize() function */ - object_id_t deviceCommunicationId; - /** Communication object used for device communication */ - DeviceCommunicationIF * communicationInterface = nullptr; - /** Cookie used for communication */ - CookieIF * comCookie; - - /** Health helper for HasHealthIF */ - HealthHelper healthHelper; - /** Mode helper for HasModesIF */ - ModeHelper modeHelper; - /** Parameter helper for ReceivesParameterMessagesIF */ - ParameterHelper parameterHelper; - /** Action helper for HasActionsIF */ - ActionHelper actionHelper; - /** Housekeeping Manager */ - LocalDataPoolManager hkManager; - - /** - * @brief Information about commands - */ - struct DeviceCommandInfo { - //! Indicates if the command is already executing. - bool isExecuting; - //! Dynamic value to indicate how many replies are expected. - //! Inititated with 0. - uint8_t expectedReplies; - //! if this is != NO_COMMANDER, DHB was commanded externally and shall - //! report everything to commander. - MessageQueueId_t sendReplyTo; - }; - using DeviceCommandMap = std::map ; - /** - * Information about commands - */ - DeviceCommandMap deviceCommandMap; - - /** - * @brief Information about expected replies - * This is used to keep track of pending replies. - */ - struct DeviceReplyInfo { - //! The maximum number of cycles the handler should wait for a reply - //! to this command. - uint16_t maxDelayCycles; - //! The currently remaining cycles the handler should wait for a reply, - //! 0 means there is no reply expected - uint16_t delayCycles; - size_t replyLen = 0; //!< Expected size of the reply. - //! if this is !=0, the delayCycles will not be reset to 0 but to - //! maxDelayCycles - bool periodic = false; - //! The dataset used to access housekeeping data related to the - //! respective device reply. Will point to a dataset held by - //! the child handler (if one is specified) - DataSetIF* dataSet = nullptr; - float collectionInterval = 0.0; - uint32_t intervalCounter = 0; - //! The command that expects this reply. - DeviceCommandMap::iterator command; - }; - - using DeviceReplyMap = std::map ; - using DeviceReplyIter = DeviceReplyMap::iterator; - /** - * This map is used to check and track correct reception of all replies. - * - * It has multiple use: - * - It stores the information on pending replies. If a command is sent, - * the DeviceCommandInfo.count is incremented. - * - It is used to time-out missing replies. If a command is sent, the - * DeviceCommandInfo.DelayCycles is set to MaxDelayCycles. - * - It is queried to check if a reply from the device can be interpreted. - * scanForReply() returns the id of the command a reply was found for. - * The reply is ignored in the following cases: - * - No entry for the returned id was found - * - The deviceReplyInfo.delayCycles is == 0 - */ - DeviceReplyMap deviceReplyMap; - - //! The MessageQueue used to receive device handler commands - //! and to send replies. - MessageQueueIF* commandQueue = nullptr; - - /** - * this is the datapool variable with the thermal state of the device - * - * can be set to PoolVariableIF::NO_PARAMETER to deactivate thermal checking - */ - uint32_t deviceThermalStatePoolId = PoolVariableIF::NO_PARAMETER; - - /** - * this is the datapool variable with the thermal request of the device - * - * can be set to PoolVariableIF::NO_PARAMETER to deactivate thermal checking - */ - uint32_t deviceThermalRequestPoolId = PoolVariableIF::NO_PARAMETER; - - /** - * Optional Error code - * Can be set in doStartUp(), doShutDown() and doTransition() to signal cause for Transition failure. - */ - ReturnValue_t childTransitionFailure; - - uint32_t ignoreMissedRepliesCount = 0; //!< Counts if communication channel lost a reply, so some missed replys can be ignored. - - FailureIsolationBase* fdirInstance; //!< Pointer to the used FDIR instance. If not provided by child, default class is instantiated. - - HkSwitchHelper hkSwitcher; - - bool defaultFDIRUsed; //!< To correctly delete the default instance. - - bool switchOffWasReported; //!< Indicates if SWITCH_WENT_OFF was already thrown. - - //! Pointer to the task which executes this component, is invalid - //! before setTaskIF was called. - PeriodicTaskIF* executingTask = nullptr; - - static object_id_t powerSwitcherId; //!< Object which switches power on and off. - - static object_id_t rawDataReceiverId; //!< Object which receives RAW data by default. - - static object_id_t defaultFdirParentId; //!< Object which may be the root cause of an identified fault. - /** - * Helper function to report a missed reply - * - * Can be overwritten by children to act on missed replies or to fake reporting Id. - * - * @param id of the missed reply - */ - virtual void missedReply(DeviceCommandId_t id); - - /** - * Send a reply to a received device handler command. - * - * This also resets #DeviceHandlerCommand to 0. - * - * @param reply the reply type - * @param parameter parameter for the reply - */ - void replyReturnvalueToCommand(ReturnValue_t status, - uint32_t parameter = 0); - - void replyToCommand(ReturnValue_t status, uint32_t parameter = 0); - - /** - * Set the device handler mode - * - * Sets #timeoutStart with every call. - * - * Sets #transitionTargetMode if necessary so transitional states can be - * entered from everywhere without breaking the state machine - * (which relies on a correct #transitionTargetMode). - * - * The submode is left unchanged. - * - * - * @param newMode - */ - void setMode(Mode_t newMode); - - /** - * @overload - * @param submode - */ - void setMode(Mode_t newMode, Submode_t submode); - - /** - * Do the transition to the main modes (MODE_ON, MODE_NORMAL and MODE_RAW). - * - * If the transition is complete, the mode should be set to the target mode, - * which can be deduced from the current mode which is - * [_MODE_TO_ON, _MODE_TO_NORMAL, _MODE_TO_RAW] - * - * The intended target submode is already set. - * The origin submode can be read in subModeFrom. - * - * If the transition can not be completed, the child class can try to reach - * an working mode by setting the mode either directly - * or setting the mode to an transitional mode (TO_ON, TO_NORMAL, TO_RAW) - * if the device needs to be reconfigured. - * - * If nothing works, the child class can wait for the timeout and the base - * class will reset the mode to the mode where the transition - * originated from (the child should report the reason for the failed transition). - * - * The intended way to send commands is to set a flag (enum) indicating - * which command is to be sent here and then to check in - * buildTransitionCommand() for the flag. This flag can also be used by - * doStartUp() and doShutDown() to get a nice and clean implementation of - * buildTransitionCommand() without switching through modes. - * - * When the the condition for the completion of the transition is met, the - * mode can be set, for example in the scanForReply() function. - * - * The default implementation goes into the target mode directly. - * - * #transitionFailure can be set to a failure code indicating the reason - * for a failed transition - * - * @param modeFrom - * The mode the transition originated from: - * [MODE_ON, MODE_NORMAL, MODE_RAW and _MODE_POWER_DOWN (if the mode changed - * from _MODE_START_UP to _MODE_TO_ON)] - * @param subModeFrom the subMode of modeFrom - */ - virtual void doTransition(Mode_t modeFrom, Submode_t subModeFrom); - - /** - * Is the combination of mode and submode valid? - * - * @param mode - * @param submode - * @return - * - @c RETURN_OK if valid - * - @c RETURN_FAILED if invalid - */ - virtual ReturnValue_t isModeCombinationValid(Mode_t mode, - Submode_t submode); - - /** - * Get the Rmap action for the current step. - * - * The step number can be read from #pstStep. - * - * @return The Rmap action to execute in this step - */ - - virtual CommunicationAction_t getComAction(); - - /** - * Build the device command to send for raw mode. - * - * This is only called in @c MODE_RAW. It is for the rare case that in raw mode packets - * are to be sent by the handler itself. It is NOT needed for the raw commanding service. - * Its only current use is in the STR handler which gets its raw packets from a different - * source. - * Also it can be used for transitional commands, to get the device ready for @c MODE_RAW - * - * As it is almost never used, there is a default implementation returning @c NOTHING_TO_SEND. - * - * #rawPacket and #rawPacketLen must be set by this method to the packet to be sent. - * - * @param[out] id the device command id built - * @return - * - @c RETURN_OK when a command is to be sent - * - not @c NOTHING_TO_SEND when no command is to be sent - */ - virtual ReturnValue_t buildChildRawCommand(); - - /** - * Returns the delay cycle count of a reply. - * A count != 0 indicates that the command is already executed. - * @param deviceCommand The command to look for - * @return The current delay count. If the command does not exist (should never happen) it returns 0. - */ - uint8_t getReplyDelayCycles(DeviceCommandId_t deviceCommand); - - /** - * Construct a command reply containing a raw reply. - * - * It gets space in the #IPCStore, copies data there, then sends a raw reply - * containing the store address. - * - * This method is virtual, as the STR has a different channel to send raw replies - * and overwrites it accordingly. - * - * @param data data to send - * @param len length of @c data - * @param sendTo the messageQueueId of the one to send to - * @param isCommand marks the raw data as a command, the message then will be of type raw_command - */ - virtual void replyRawData(const uint8_t *data, size_t len, - MessageQueueId_t sendTo, bool isCommand = false); - - /** - * Calls replyRawData() with #defaultRawReceiver, but checks if wiretapping is active and if so, - * does not send the Data as the wiretapping will have sent it already - */ - void replyRawReplyIfnotWiretapped(const uint8_t *data, size_t len); - - /** - * notify child about mode change - */ - virtual void modeChanged(void); - - /** - * Enable the reply checking for a command - * - * Is only called, if the command was sent (ie the getWriteReply was successful). - * Must ensure that all replies are activated and correctly linked to the command that initiated it. - * The default implementation looks for a reply with the same id as the command id in the replyMap or - * uses the alternativeReplyId if flagged so. - * When found, copies maxDelayCycles to delayCycles in the reply information and sets the command to - * expect one reply. - * - * Can be overwritten by the child, if a command activates multiple replies - * or replyId differs from commandId. - * Notes for child implementations: - * - If the command was not found in the reply map, NO_REPLY_EXPECTED MUST be returned. - * - A failure code may be returned if something went fundamentally wrong. - * - * @param deviceCommand - * @return - RETURN_OK if a reply was activated. - * - NO_REPLY_EXPECTED if there was no reply found. This is not an - * error case as many commands do not expect a reply. - */ - virtual ReturnValue_t enableReplyInReplyMap(DeviceCommandMap::iterator cmd, - uint8_t expectedReplies = 1, bool useAlternateId = false, - DeviceCommandId_t alternateReplyID = 0); - - /** - * get the state of the PCDU switches in the datapool - * - * @return - * - @c PowerSwitchIF::SWITCH_ON if all switches specified by #switches are on - * - @c PowerSwitchIF::SWITCH_OFF one of the switches specified by #switches are off - * - @c PowerSwitchIF::RETURN_FAILED if an error occured - */ - ReturnValue_t getStateOfSwitches(void); - - /** - * set all datapool variables that are update periodically in normal mode invalid - * - * Child classes should provide an implementation which sets all those variables invalid - * which are set periodically during any normal mode. - */ - virtual void setNormalDatapoolEntriesInvalid() = 0; - - /** - * build a list of sids and pass it to the #hkSwitcher - */ - virtual void changeHK(Mode_t mode, Submode_t submode, bool enable); - - /** - * Children can overwrite this function to suppress checking of the command Queue - * - * This can be used when the child does not want to receive a command in a certain - * situation. Care must be taken that checking is not permanentely disabled as this - * would render the handler unusable. - * - * @return whether checking the queue should NOT be done - */ - virtual bool dontCheckQueue(); - - Mode_t getBaseMode(Mode_t transitionMode); - - bool isAwaitingReply(); - - void handleDeviceTM(SerializeIF *dataSet, DeviceCommandId_t commandId, - bool neverInDataPool = false, bool forceDirectTm = false); - - virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, - uint32_t *msToReachTheMode); - virtual void startTransition(Mode_t mode, Submode_t submode); - virtual void setToExternalControl(); - virtual void announceMode(bool recursive); - - virtual ReturnValue_t letChildHandleMessage(CommandMessage *message); - - /** - * Overwrites SystemObject::triggerEvent in order to inform FDIR"Helper" faster about executed events. - * This is a bit sneaky, but improves responsiveness of the device FDIR. - * @param event The event to be thrown - * @param parameter1 Optional parameter 1 - * @param parameter2 Optional parameter 2 - */ - void triggerEvent(Event event, uint32_t parameter1 = 0, - uint32_t parameter2 = 0); - /** - * Same as triggerEvent, but for forwarding if object is used as proxy. - */ - virtual void forwardEvent(Event event, uint32_t parameter1 = 0, - uint32_t parameter2 = 0) const; - /** - * Checks state of switches in conjunction with mode and triggers an event if they don't fit. - */ - virtual void checkSwitchState(); - - /** - * Reserved for the rare case where a device needs to perform additional operation cyclically in OFF mode. - */ - virtual void doOffActivity(); - - /** - * Reserved for the rare case where a device needs to perform additional operation cyclically in ON mode. - */ - virtual void doOnActivity(); - - /** - * Checks if current mode is transitional mode. - * @return true if mode is transitional, false else. - */ - bool isTransitionalMode(); - - /** - * Checks if current handler state allows reception of external device commands. - * Default implementation allows commands only in plain MODE_ON and MODE_NORMAL. - * @return RETURN_OK if commands are accepted, anything else otherwise. - */ - virtual ReturnValue_t acceptExternalDeviceCommands(); - - bool commandIsExecuting(DeviceCommandId_t commandId); - - /** - * set all switches returned by getSwitches() - * - * @param onOff on == @c SWITCH_ON; off != @c SWITCH_ON - */ - void commandSwitch(ReturnValue_t onOff); -private: - - /** - * State a cookie is in. - * - * Used to keep track of the state of the RMAP communication. - */ - enum CookieState_t { - COOKIE_UNUSED, //!< The Cookie is unused - COOKIE_WRITE_READY, //!< There's data available to send. - COOKIE_READ_SENT, //!< A sendRead command was sent with this cookie - COOKIE_WRITE_SENT //!< A sendWrite command was sent with this cookie - }; - /** - * Information about a cookie. - * - * This is stored in a map for each cookie, to not only track the state, but also information - * about the sent command. Tracking this information is needed as - * the state of a commandId (waiting for reply) is done when a RMAP write reply is received. - */ - struct CookieInfo { - CookieState_t state; - DeviceCommandMap::iterator pendingCommand; - }; - - /** - * @brief Info about the #cookie - * Used to track the state of the communication - */ - CookieInfo cookieInfo; - - /** the object used to set power switches */ - PowerSwitchIF *powerSwitcher = nullptr; - - /** Cached for initialize() */ - static object_id_t defaultHkDestination; - /** HK destination can also be set individually */ - object_id_t hkDestination = objects::NO_OBJECT; - - /** - * @brief Used for timing out mode transitions. - * Set when setMode() is called. - */ - uint32_t timeoutStart = 0; - - /** - * Delay for the current mode transition, used for time out - */ - uint32_t childTransitionDelay; - - /** - * @brief The mode the current transition originated from - * - * This is private so the child can not change it and fuck up the timeouts - * - * IMPORTANT: This is not valid during _MODE_SHUT_DOWN and _MODE_START_UP!! - * (it is _MODE_POWER_DOWN during this modes) - * - * is element of [MODE_ON, MODE_NORMAL, MODE_RAW] - */ - Mode_t transitionSourceMode; - - /** - * the submode of the source mode during a transition - */ - Submode_t transitionSourceSubMode; - - /** - * read the command queue - */ - void readCommandQueue(void); - - /** - * Handle the device handler mode. - * - * - checks whether commands are valid for the current mode, rejects them accordingly - * - checks whether commanded mode transitions are required and calls handleCommandedModeTransition() - * - does the necessary action for the current mode or calls doChildStateMachine in modes @c MODE_TO_ON and @c MODE_TO_OFF - * - actions that happen in transitions (eg setting a timeout) are handled in setMode() - */ - void doStateMachine(void); - - void buildRawDeviceCommand(CommandMessage* message); - void buildInternalCommand(void); - -// /** -// * Send a reply with the current mode and submode. -// */ -// void announceMode(void); - - /** - * Decrement the counter for the timout of replies. - * - * This is called at the beginning of each cycle. It checks whether a reply has timed out (that means a reply was expected - * but not received). - */ - void decrementDeviceReplyMap(void); - - /** - * Convenience function to handle a reply. - * - * Called after scanForReply() has found a packet. Checks if the found id is in the #deviceCommandMap, if so, - * calls interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) for further action. - * - * It also resets the timeout counter for the command id. - * - * @param data the found packet - * @param id the found id - * @foundLen the length of the packet - */ - void handleReply(const uint8_t *data, DeviceCommandId_t id, uint32_t foundLen); - - void replyToReply(DeviceReplyMap::iterator iter, ReturnValue_t status); - /** - * Build and send a command to the device. - * - * This routine checks whether a raw or direct command has been received, checks the content of the received command and - * calls buildCommandFromCommand() for direct commands or sets #rawpacket to the received raw packet. - * If no external command is received or the received command is invalid and the current mode is @c MODE_NORMAL or a transitional mode, - * it asks the child class to build a command (via getNormalDeviceCommand() or getTransitionalDeviceCommand() and buildCommand()) and - * sends the command via RMAP. - */ - void doSendWrite(void); - - /** - * Check if the RMAP sendWrite action was successful. - * - * Depending on the result, the following is done - * - if the device command was external commanded, a reply is sent indicating the result - * - if the action was successful, the reply timout counter is initialized - */ - void doGetWrite(void); - - /** - * Send a RMAP getRead command. - * - * The size of the getRead command is #maxDeviceReplyLen. - * This is always executed, independently from the current mode. - */ - void doSendRead(void); - - /** - * Check the getRead reply and the contained data. - * - * If data was received scanForReply() and, if successful, handleReply() are called. - * If the current mode is @c MODE_RAW, the received packet is sent to the commanding object - * via commandQueue. - */ - void doGetRead(void); - - /** - * Retrive data from the #IPCStore. - * - * @param storageAddress - * @param[out] data - * @param[out] len - * @return - * - @c RETURN_OK @c data is valid - * - @c RETURN_FAILED IPCStore is NULL - * - the return value from the IPCStore if it was not @c RETURN_OK - */ - ReturnValue_t getStorageData(store_address_t storageAddress, uint8_t **data, - uint32_t *len); - - - /** - * @param modeTo either @c MODE_ON, MODE_NORMAL or MODE_RAW NOTHING ELSE!!! - */ - void setTransition(Mode_t modeTo, Submode_t submodeTo); - - /** - * calls the right child function for the transitional submodes - */ - void callChildStatemachine(); - - /** - * Switches the channel of the cookie used for the communication - * - * - * @param newChannel the object Id of the channel to switch to - * @return - * - @c RETURN_OK when cookie was changed - * - @c RETURN_FAILED when cookies could not be changed, eg because the newChannel is not enabled - * - @c returnvalues of RMAPChannelIF::isActive() - */ - ReturnValue_t switchCookieChannel(object_id_t newChannelId); - - ReturnValue_t handleDeviceHandlerMessage(CommandMessage *message); - - virtual ReturnValue_t initializeAfterTaskCreation() override; - DataSetIF* getDataSetHandle(sid_t sid) override; - - void parseReply(const uint8_t* receivedData, - size_t receivedDataLen); -}; - -#endif /* FRAMEWORK_DEVICEHANDLERS_DEVICEHANDLERBASE_H_ */ - +#ifndef FRAMEWORK_DEVICEHANDLERS_DEVICEHANDLERBASE_H_ +#define FRAMEWORK_DEVICEHANDLERS_DEVICEHANDLERBASE_H_ + +#include "../objectmanager/SystemObject.h" +#include "../tasks/ExecutableObjectIF.h" +#include "../devicehandlers/DeviceHandlerIF.h" +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../action/HasActionsIF.h" +#include "../datapool/PoolVariableIF.h" +#include "../devicehandlers/DeviceCommunicationIF.h" +#include "../modes/HasModesIF.h" +#include "../power/PowerSwitchIF.h" +#include "../ipc/MessageQueueIF.h" +#include "../tasks/PeriodicTaskIF.h" + +#include "../action/ActionHelper.h" +#include "../health/HealthHelper.h" +#include "../parameters/ParameterHelper.h" +#include "../datapool/HkSwitchHelper.h" +#include "../datapoollocal/HasLocalDataPoolIF.h" +#include "../datapoollocal/LocalDataPoolManager.h" +#include "../devicehandlers/DeviceHandlerFailureIsolation.h" +#include + +namespace Factory{ +void setStaticFrameworkObjectIds(); +} + +class StorageManagerIF; + +/** + * @defgroup devices Devices + * Contains all devices and the DeviceHandlerBase class. + */ + +/** + * @brief This is the abstract base class for device handlers. + * @details + * Documentation: Dissertation Baetz p.138,139, p.141-149 + * + * It features handling of @link DeviceHandlerIF::Mode_t Modes @endlink, + * communication with physical devices, using the @link DeviceCommunicationIF @endlink, + * and communication with commanding objects. + * It inherits SystemObject and thus can be created by the ObjectManagerIF. + * + * This class uses the opcode of ExecutableObjectIF to perform a step-wise execution. + * For each step an RMAP action is selected and executed. + * If data has been received (GET_READ), the data will be interpreted. + * The action for each step can be defined by the child class but as most + * device handlers share a 4-call (sendRead-getRead-sendWrite-getWrite) structure, + * a default implementation is provided. + * NOTE: RMAP is a standard which is used for FLP. + * RMAP communication is not mandatory for projects implementing the FSFW. + * However, the communication principles are similar to RMAP as there are + * two write and two send calls involved. + * + * Device handler instances should extend this class and implement the abstract + * functions. Components and drivers can send so called cookies which are used + * for communication and contain information about the communcation (e.g. slave + * address for I2C or RMAP structs). + * The following abstract methods must be implemented by a device handler: + * 1. doStartUp() + * 2. doShutDown() + * 3. buildTransitionDeviceCommand() + * 4. buildNormalDeviceCommand() + * 5. buildCommandFromCommand() + * 6. fillCommandAndReplyMap() + * 7. scanForReply() + * 8. interpretDeviceReply() + * + * Other important virtual methods with a default implementation + * are the getTransitionDelayMs() function and the getSwitches() function. + * Please ensure that getSwitches() returns DeviceHandlerIF::NO_SWITCHES if + * power switches are not implemented yet. Otherwise, the device handler will + * not transition to MODE_ON, even if setMode(MODE_ON) is called. + * If a transition to MODE_ON is desired without commanding, override the + * intialize() function and call setMode(_MODE_START_UP) before calling + * DeviceHandlerBase::initialize(). + * + * @ingroup devices + */ +class DeviceHandlerBase: public DeviceHandlerIF, + public HasReturnvaluesIF, + public ExecutableObjectIF, + public SystemObject, + public HasModesIF, + public HasHealthIF, + public HasActionsIF, + public ReceivesParameterMessagesIF, + public HasLocalDataPoolIF { + friend void (Factory::setStaticFrameworkObjectIds)(); +public: + /** + * The constructor passes the objectId to the SystemObject(). + * + * @param setObjectId the ObjectId to pass to the SystemObject() Constructor + * @param maxDeviceReplyLen the length the RMAP getRead call will be sent with + * @param setDeviceSwitch the switch the device is connected to, + * for devices using two switches, overwrite getSwitches() + * @param deviceCommuncation Communcation Interface object which is used + * to implement communication functions + * @param thermalStatePoolId + * @param thermalRequestPoolId + * @param fdirInstance + * @param cmdQueueSize + */ + DeviceHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication, + CookieIF * comCookie, FailureIsolationBase* fdirInstance = nullptr, + size_t cmdQueueSize = 20); + + void setHkDestination(object_id_t hkDestination); + void setThermalStateRequestPoolIds(uint32_t thermalStatePoolId, + uint32_t thermalRequestPoolId); + + /** + * @brief This function is the device handler base core component and is + * called periodically. + * @details + * General sequence, showing where abstract virtual functions are called: + * If the State is SEND_WRITE: + * 1. Set the cookie state to COOKIE_UNUSED and read the command queue + * 2. Handles Device State Modes by calling doStateMachine(). + * This function calls callChildStatemachine() which calls the + * abstract functions doStartUp() and doShutDown() + * 3. Check switch states by calling checkSwitchStates() + * 4. Decrements counter for timeout of replies by calling + * decrementDeviceReplyMap() + * 5. Performs FDIR check for failures + * 6. Calls hkSwitcher.performOperation() + * 7. If the device mode is MODE_OFF, return RETURN_OK. + * Otherwise, perform the Action property and performs depending + * on value specified by input value counter (incremented in PST). + * The child class tells base class what to do by setting this value. + * - SEND_WRITE: Send data or commands to device by calling + * doSendWrite() which calls sendMessage function + * of #communicationInterface + * and calls buildInternalCommand if the cookie state is COOKIE_UNUSED + * - GET_WRITE: Get ackknowledgement for sending by calling doGetWrite() + * which calls getSendSuccess of #communicationInterface. + * Calls abstract functions scanForReply() and interpretDeviceReply(). + * - SEND_READ: Request reading data from device by calling doSendRead() + * which calls requestReceiveMessage of #communcationInterface + * - GET_READ: Access requested reading data by calling doGetRead() + * which calls readReceivedMessage of #communicationInterface + * @param counter Specifies which Action to perform + * @return RETURN_OK for successful execution + */ + virtual ReturnValue_t performOperation(uint8_t counter); + + /** + * @brief Initializes the device handler + * @details + * Initialize Device Handler as system object and + * initializes all important helper classes. + * Calls fillCommandAndReplyMap(). + * @return + */ + virtual ReturnValue_t initialize(); + /** Destructor. */ + virtual ~DeviceHandlerBase(); + +protected: + /** + * @brief This is used to let the child class handle the transition from + * mode @c _MODE_START_UP to @c MODE_ON + * @details + * It is only called when the device handler is in mode @c _MODE_START_UP. + * That means, the device switch(es) are already set to on. + * Device handler commands are read and can be handled by the child class. + * If the child class handles a command, it should also send + * an reply accordingly. + * If an Command is not handled (ie #DeviceHandlerCommand is not @c CMD_NONE, + * the base class handles rejecting the command and sends a reply. + * The replies for mode transitions are handled by the base class. + * + * - If the device is started and ready for operation, the mode should be + * set to MODE_ON. It is possible to set the mode to _MODE_TO_ON to + * use the to on transition if available. + * - If the power-up fails, the mode should be set to _MODE_POWER_DOWN + * which will lead to the device being powered off. + * - If the device does not change the mode, the mode will be changed + * to _MODE_POWER_DOWN, after the timeout (from getTransitionDelay()) + * has passed. + * + * #transitionFailure can be set to a failure code indicating the reason + * for a failed transition + */ + virtual void doStartUp() = 0; + + /** + * @brief This is used to let the child class handle the transition + * from mode @c _MODE_SHUT_DOWN to @c _MODE_POWER_DOWN + * @details + * It is only called when the device handler is in mode @c _MODE_SHUT_DOWN. + * Device handler commands are read and can be handled by the child class. + * If the child class handles a command, it should also send an reply + * accordingly. + * If an Command is not handled (ie #DeviceHandlerCommand is not + * @c CMD_NONE, the base class handles rejecting the command and sends a + * reply. The replies for mode transitions are handled by the base class. + * + * - If the device ready to be switched off, + * the mode should be set to _MODE_POWER_DOWN. + * - If the device should not be switched off, the mode can be changed to + * _MODE_TO_ON (or MODE_ON if no transition is needed). + * - If the device does not change the mode, the mode will be changed to + * _MODE_POWER_DOWN, when the timeout (from getTransitionDelay()) + * has passed. + * + * #transitionFailure can be set to a failure code indicating the reason + * for a failed transition + */ + virtual void doShutDown() = 0; + + /** + * Build the device command to send for normal mode. + * + * This is only called in @c MODE_NORMAL. If multiple submodes for + * @c MODE_NORMAL are supported, different commands can built, + * depending on the submode. + * + * #rawPacket and #rawPacketLen must be set by this method to the + * packet to be sent. If variable command frequence is required, a counter + * can be used and the frequency in the reply map has to be set manually + * by calling updateReplyMap(). + * + * @param[out] id the device command id that has been built + * @return + * - @c RETURN_OK to send command after setting #rawPacket and #rawPacketLen. + * - @c NOTHING_TO_SEND when no command is to be sent. + * - Anything else triggers an even with the returnvalue as a parameter. + */ + virtual ReturnValue_t buildNormalDeviceCommand(DeviceCommandId_t * id) = 0; + + /** + * Build the device command to send for a transitional mode. + * + * This is only called in @c _MODE_TO_NORMAL, @c _MODE_TO_ON, @c _MODE_TO_RAW, + * @c _MODE_START_UP and @c _MODE_SHUT_DOWN. So it is used by doStartUp() + * and doShutDown() as well as doTransition(), by setting those + * modes in the respective functions. + * + * A good idea is to implement a flag indicating a command has to be built + * and a variable containing the command number to be built + * and filling them in doStartUp(), doShutDown() and doTransition() so no + * modes have to be checked here. + * + * #rawPacket and #rawPacketLen must be set by this method to the packet to be sent. + * + * @param[out] id the device command id built + * @return + * - @c RETURN_OK when a command is to be sent + * - @c NOTHING_TO_SEND when no command is to be sent + * - Anything else triggers an even with the returnvalue as a parameter + */ + virtual ReturnValue_t buildTransitionDeviceCommand(DeviceCommandId_t * id) = 0; + + /** + * @brief Build a device command packet from data supplied by a direct command. + * + * @details + * #rawPacket and #rawPacketLen should be set by this method to the packet to be sent. + * The existence of the command in the command map and the command size check + * against 0 are done by the base class. + * + * @param deviceCommand the command to build, already checked against deviceCommandMap + * @param commandData pointer to the data from the direct command + * @param commandDataLen length of commandData + * @return + * - @c RETURN_OK to send command after #rawPacket and #rawPacketLen have been set. + * - Anything else triggers an event with the returnvalue as a parameter + */ + virtual ReturnValue_t buildCommandFromCommand(DeviceCommandId_t deviceCommand, + const uint8_t * commandData, size_t commandDataLen) = 0; + + /** + * @brief Scans a buffer for a valid reply. + * @details + * This is used by the base class to check the data received for valid packets. + * It only checks if a valid packet starts at @c start. + * It also only checks the structural validy of the packet, + * e.g. checksums lengths and protocol data. No information check is done, + * e.g. range checks etc. + * + * Errors should be reported directly, the base class does NOT report any + * errors based on the return value of this function. + * + * @param start start of remaining buffer to be scanned + * @param len length of remaining buffer to be scanned + * @param[out] foundId the id of the data found in the buffer. + * @param[out] foundLen length of the data found. Is to be set in function, + * buffer is scanned at previous position + foundLen. + * @return + * - @c RETURN_OK a valid packet was found at @c start, @c foundLen is valid + * - @c RETURN_FAILED no reply could be found starting at @c start, + * implies @c foundLen is not valid, base class will call scanForReply() + * again with ++start + * - @c DeviceHandlerIF::INVALID_DATA a packet was found but it is invalid, + * e.g. checksum error, implies @c foundLen is valid, can be used to + * skip some bytes + * - @c DeviceHandlerIF::LENGTH_MISSMATCH @c len is invalid + * - @c DeviceHandlerIF::IGNORE_REPLY_DATA Ignore this specific part of + * the packet + * - @c DeviceHandlerIF::IGNORE_FULL_PACKET Ignore the packet + * - @c APERIODIC_REPLY if a valid reply is received that has not been + * requested by a command, but should be handled anyway + * (@see also fillCommandAndCookieMap() ) + */ + virtual ReturnValue_t scanForReply(const uint8_t *start, size_t len, + DeviceCommandId_t *foundId, size_t *foundLen) = 0; + + /** + * @brief Interpret a reply from the device. + * @details + * This is called after scanForReply() found a valid packet, it can be + * assumed that the length and structure is valid. + * This routine extracts the data from the packet into a DataSet and then + * calls handleDeviceTM(), which either sends a TM packet or stores the + * data in the DataPool depending on whether it was an external command. + * No packet length is given, as it should be defined implicitly by the id. + * + * @param id the id found by scanForReply() + * @param packet + * @return + * - @c RETURN_OK when the reply was interpreted. + * - @c RETURN_FAILED when the reply could not be interpreted, + * e.g. logical errors or range violations occurred + */ + virtual ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, + const uint8_t *packet) = 0; + + /** + * @brief fill the #DeviceCommandMap and #DeviceReplyMap + * called by the initialize() of the base class + * @details + * This is used to let the base class know which replies are expected. + * There are different scenarios regarding this: + * + * - "Normal" commands. These are commands, that trigger a direct reply + * from the device. In this case, the id of the command should be added + * to the command map with a commandData_t where maxDelayCycles is set + * to the maximum expected number of PST cycles the reply will take. + * Then, scanForReply returns the id of the command and the base class + * can handle time-out and missing replies. + * + * - Periodic, unrequested replies. These are replies that, once enabled, + * are sent by the device on its own in a defined interval. + * In this case, the id of the reply or a placeholder id should be added + * to the deviceCommandMap with a commandData_t where maxDelayCycles is + * set to the maximum expected number of PST cycles between two replies + * (also a tolerance should be added, as an FDIR message will be + * generated if it is missed). + * + * (Robin) This part confuses me. "must do as soon as" implies that + * the developer must do something somewhere else in the code. Is + * that really the case? If I understood correctly, DHB performs + * almost everything (e.g. in erirm function) as long as the commands + * are inserted correctly. + * + * As soon as the replies are enabled, DeviceCommandInfo.periodic must + * be set to true, DeviceCommandInfo.delayCycles to + * DeviceCommandInfo.maxDelayCycles. + * From then on, the base class handles the reception. + * Then, scanForReply returns the id of the reply or the placeholder id + * and the base class will take care of checking that all replies are + * received and the interval is correct. + * When the replies are disabled, DeviceCommandInfo.periodic must be set + * to 0, DeviceCommandInfo.delayCycles to 0; + * + * - Aperiodic, unrequested replies. These are replies that are sent + * by the device without any preceding command and not in a defined + * interval. These are not entered in the deviceCommandMap but + * handled by returning @c APERIODIC_REPLY in scanForReply(). + */ + virtual void fillCommandAndReplyMap() = 0; + + /** + * This is a helper method to facilitate inserting entries in the command map. + * @param deviceCommand Identifier of the command to add. + * @param maxDelayCycles The maximum number of delay cycles the command + * waits until it times out. + * @param replyLen Will be supplied to the requestReceiveMessage call of + * the communication interface. + * @param periodic Indicates if the command is periodic (i.e. it is sent + * by the device repeatedly without request) or not. Default is aperiodic (0) + * @return - @c RETURN_OK when the command was successfully inserted, + * - @c RETURN_FAILED else. + */ + ReturnValue_t insertInCommandAndReplyMap(DeviceCommandId_t deviceCommand, + uint16_t maxDelayCycles, size_t replyLen = 0, bool periodic = false, + bool hasDifferentReplyId = false, DeviceCommandId_t replyId = 0); + + /** + * @brief This is a helper method to insert replies in the reply map. + * @param deviceCommand Identifier of the reply to add. + * @param maxDelayCycles The maximum number of delay cycles the reply waits + * until it times out. + * @param periodic Indicates if the command is periodic (i.e. it is sent + * by the device repeatedly without request) or not. Default is aperiodic (0) + * @return - @c RETURN_OK when the command was successfully inserted, + * - @c RETURN_FAILED else. + */ + ReturnValue_t insertInReplyMap(DeviceCommandId_t deviceCommand, + uint16_t maxDelayCycles, size_t replyLen = 0, bool periodic = false); + + /** + * @brief A simple command to add a command to the commandList. + * @param deviceCommand The command to add + * @return - @c RETURN_OK when the command was successfully inserted, + * - @c RETURN_FAILED else. + */ + ReturnValue_t insertInCommandMap(DeviceCommandId_t deviceCommand); + /** + * @brief This is a helper method to facilitate updating entries + * in the reply map. + * @param deviceCommand Identifier of the reply to update. + * @param delayCycles The current number of delay cycles to wait. + * As stated in #fillCommandAndCookieMap, to disable periodic commands, + * this is set to zero. + * @param maxDelayCycles The maximum number of delay cycles the reply waits + * until it times out. By passing 0 the entry remains untouched. + * @param periodic Indicates if the command is periodic (i.e. it is sent + * by the device repeatedly without request) or not.Default is aperiodic (0). + * Warning: The setting always overrides the value that was entered in the map. + * @return - @c RETURN_OK when the command was successfully inserted, + * - @c RETURN_FAILED else. + */ + ReturnValue_t updateReplyMapEntry(DeviceCommandId_t deviceReply, + uint16_t delayCycles, uint16_t maxDelayCycles, + bool periodic = false); + + /** + * @brief Can be implemented by child handler to + * perform debugging + * @details Example: Calling this in performOperation + * to track values like mode. + * @param positionTracker Provide the child handler a way to know + * where the debugInterface was called + * @param objectId Provide the child handler object Id to + * specify actions for spefic devices + * @param parameter Supply a parameter of interest + * Please delete all debugInterface calls in DHB after debugging is finished ! + */ + virtual void debugInterface(uint8_t positionTracker = 0, + object_id_t objectId = 0, uint32_t parameter = 0); + + /** + * Get the time needed to transit from modeFrom to modeTo. + * + * Used for the following transitions: + * modeFrom -> modeTo: + * MODE_ON -> [MODE_ON, MODE_NORMAL, MODE_RAW, _MODE_POWER_DOWN] + * MODE_NORMAL -> [MODE_ON, MODE_NORMAL, MODE_RAW, _MODE_POWER_DOWN] + * MODE_RAW -> [MODE_ON, MODE_NORMAL, MODE_RAW, _MODE_POWER_DOWN] + * _MODE_START_UP -> MODE_ON (do not include time to set the switches, + * the base class got you covered) + * + * The default implementation returns 0 ! + * @param modeFrom + * @param modeTo + * @return time in ms + */ + virtual uint32_t getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo); + + /** + * Return the switches connected to the device. + * + * The default implementation returns one switch set in the ctor. + * + * @param[out] switches pointer to an array of switches + * @param[out] numberOfSwitches length of returned array + * @return + * - @c RETURN_OK if the parameters were set + * - @c RETURN_FAILED if no switches exist + */ + virtual ReturnValue_t getSwitches(const uint8_t **switches, + uint8_t *numberOfSwitches); + + /** + * This function is used to initialize the local housekeeping pool + * entries. The default implementation leaves the pool empty. + * @param localDataPoolMap + * @return + */ + virtual ReturnValue_t initializePoolEntries( + LocalDataPool& localDataPoolMap) override; + + /** Get the HK manager object handle */ + virtual LocalDataPoolManager* getHkManagerHandle() override; + + /** + * @brief Hook function for child handlers which is called once per + * performOperation(). Default implementation is empty. + */ + virtual void performOperationHook(); +public: + /** + * @param parentQueueId + */ + virtual void setParentQueue(MessageQueueId_t parentQueueId); + + /** @brief Implementation required for HasActionIF */ + ReturnValue_t executeAction(ActionId_t actionId, + MessageQueueId_t commandedBy, const uint8_t* data, + size_t size) override; + + Mode_t getTransitionSourceMode() const; + Submode_t getTransitionSourceSubMode() const; + virtual void getMode(Mode_t *mode, Submode_t *submode); + HealthState getHealth(); + ReturnValue_t setHealth(HealthState health); + virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, + ParameterWrapper *parameterWrapper, + const ParameterWrapper *newValues, uint16_t startAtIndex) override; + /** + * Implementation of ExecutableObjectIF function + * + * Used to setup the reference of the task, that executes this component + * @param task_ Pointer to the taskIF of this task + */ + virtual void setTaskIF(PeriodicTaskIF* task_); + virtual MessageQueueId_t getCommandQueue(void) const; + +protected: + /** + * The Returnvalues id of this class, required by HasReturnvaluesIF + */ + static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_BASE; + + static const ReturnValue_t INVALID_CHANNEL = MAKE_RETURN_CODE(0xA0); + // Returnvalues for scanForReply() + static const ReturnValue_t APERIODIC_REPLY = MAKE_RETURN_CODE(0xB0); //!< This is used to specify for replies from a device which are not replies to requests + static const ReturnValue_t IGNORE_REPLY_DATA = MAKE_RETURN_CODE(0xB1); //!< Ignore parts of the received packet + static const ReturnValue_t IGNORE_FULL_PACKET = MAKE_RETURN_CODE(0xB2); //!< Ignore full received packet + // Returnvalues for command building + static const ReturnValue_t NOTHING_TO_SEND = MAKE_RETURN_CODE(0xC0); //!< Return this if no command sending in required + static const ReturnValue_t COMMAND_MAP_ERROR = MAKE_RETURN_CODE(0xC2); + // Returnvalues for getSwitches() + static const ReturnValue_t NO_SWITCH = MAKE_RETURN_CODE(0xD0); + // Mode handling error Codes + static const ReturnValue_t CHILD_TIMEOUT = MAKE_RETURN_CODE(0xE0); + static const ReturnValue_t SWITCH_FAILED = MAKE_RETURN_CODE(0xE1); + + static const DeviceCommandId_t RAW_COMMAND_ID = -1; + static const DeviceCommandId_t NO_COMMAND_ID = -2; + static const MessageQueueId_t NO_COMMANDER = 0; + + /** Pointer to the raw packet that will be sent.*/ + uint8_t *rawPacket = nullptr; + /** Size of the #rawPacket. */ + uint32_t rawPacketLen = 0; + + /** + * The mode the device handler is currently in. + * This should never be changed directly but only with setMode() + */ + Mode_t mode; + /** + * The submode the device handler is currently in. + * This should never be changed directly but only with setMode() + */ + Submode_t submode; + + /** This is the counter value from performOperation(). */ + uint8_t pstStep = 0; + uint32_t pstIntervalMs = 0; + + /** + * Wiretapping flag: + * + * indicates either that all raw messages to and from the device should be + * sent to #defaultRawReceiver + * or that all device TM should be downlinked to #defaultRawReceiver. + */ + enum WiretappingMode { + OFF = 0, RAW = 1, TM = 2 + } wiretappingMode; + /** + * @brief A message queue that accepts raw replies + * + * Statically initialized in initialize() to a configurable object. + * Used when there is no method of finding a recipient, ie raw mode and + * reporting erroneous replies + */ + MessageQueueId_t defaultRawReceiver = MessageQueueIF::NO_QUEUE; + store_address_t storedRawData; + + /** + * @brief The message queue which wants to read all raw traffic + * If #isWiretappingActive all raw communication from and to the device + * will be sent to this queue + */ + MessageQueueId_t requestedRawTraffic = 0; + + /** + * Pointer to the IPCStore. + * This caches the pointer received from the objectManager in the constructor. + */ + StorageManagerIF *IPCStore = nullptr; + /** The comIF object ID is cached for the intialize() function */ + object_id_t deviceCommunicationId; + /** Communication object used for device communication */ + DeviceCommunicationIF * communicationInterface = nullptr; + /** Cookie used for communication */ + CookieIF * comCookie; + + /** Health helper for HasHealthIF */ + HealthHelper healthHelper; + /** Mode helper for HasModesIF */ + ModeHelper modeHelper; + /** Parameter helper for ReceivesParameterMessagesIF */ + ParameterHelper parameterHelper; + /** Action helper for HasActionsIF */ + ActionHelper actionHelper; + /** Housekeeping Manager */ + LocalDataPoolManager hkManager; + + /** + * @brief Information about commands + */ + struct DeviceCommandInfo { + //! Indicates if the command is already executing. + bool isExecuting; + //! Dynamic value to indicate how many replies are expected. + //! Inititated with 0. + uint8_t expectedReplies; + //! if this is != NO_COMMANDER, DHB was commanded externally and shall + //! report everything to commander. + MessageQueueId_t sendReplyTo; + }; + using DeviceCommandMap = std::map ; + /** + * Information about commands + */ + DeviceCommandMap deviceCommandMap; + + /** + * @brief Information about expected replies + * This is used to keep track of pending replies. + */ + struct DeviceReplyInfo { + //! The maximum number of cycles the handler should wait for a reply + //! to this command. + uint16_t maxDelayCycles; + //! The currently remaining cycles the handler should wait for a reply, + //! 0 means there is no reply expected + uint16_t delayCycles; + size_t replyLen = 0; //!< Expected size of the reply. + //! if this is !=0, the delayCycles will not be reset to 0 but to + //! maxDelayCycles + bool periodic = false; + //! The dataset used to access housekeeping data related to the + //! respective device reply. Will point to a dataset held by + //! the child handler (if one is specified) + DataSetIF* dataSet = nullptr; + float collectionInterval = 0.0; + uint32_t intervalCounter = 0; + //! The command that expects this reply. + DeviceCommandMap::iterator command; + }; + + using DeviceReplyMap = std::map ; + using DeviceReplyIter = DeviceReplyMap::iterator; + /** + * This map is used to check and track correct reception of all replies. + * + * It has multiple use: + * - It stores the information on pending replies. If a command is sent, + * the DeviceCommandInfo.count is incremented. + * - It is used to time-out missing replies. If a command is sent, the + * DeviceCommandInfo.DelayCycles is set to MaxDelayCycles. + * - It is queried to check if a reply from the device can be interpreted. + * scanForReply() returns the id of the command a reply was found for. + * The reply is ignored in the following cases: + * - No entry for the returned id was found + * - The deviceReplyInfo.delayCycles is == 0 + */ + DeviceReplyMap deviceReplyMap; + + //! The MessageQueue used to receive device handler commands + //! and to send replies. + MessageQueueIF* commandQueue = nullptr; + + /** + * this is the datapool variable with the thermal state of the device + * + * can be set to PoolVariableIF::NO_PARAMETER to deactivate thermal checking + */ + uint32_t deviceThermalStatePoolId = PoolVariableIF::NO_PARAMETER; + + /** + * this is the datapool variable with the thermal request of the device + * + * can be set to PoolVariableIF::NO_PARAMETER to deactivate thermal checking + */ + uint32_t deviceThermalRequestPoolId = PoolVariableIF::NO_PARAMETER; + + /** + * Optional Error code + * Can be set in doStartUp(), doShutDown() and doTransition() to signal cause for Transition failure. + */ + ReturnValue_t childTransitionFailure; + + uint32_t ignoreMissedRepliesCount = 0; //!< Counts if communication channel lost a reply, so some missed replys can be ignored. + + FailureIsolationBase* fdirInstance; //!< Pointer to the used FDIR instance. If not provided by child, default class is instantiated. + + HkSwitchHelper hkSwitcher; + + bool defaultFDIRUsed; //!< To correctly delete the default instance. + + bool switchOffWasReported; //!< Indicates if SWITCH_WENT_OFF was already thrown. + + //! Pointer to the task which executes this component, is invalid + //! before setTaskIF was called. + PeriodicTaskIF* executingTask = nullptr; + + static object_id_t powerSwitcherId; //!< Object which switches power on and off. + + static object_id_t rawDataReceiverId; //!< Object which receives RAW data by default. + + static object_id_t defaultFdirParentId; //!< Object which may be the root cause of an identified fault. + /** + * Helper function to report a missed reply + * + * Can be overwritten by children to act on missed replies or to fake reporting Id. + * + * @param id of the missed reply + */ + virtual void missedReply(DeviceCommandId_t id); + + /** + * Send a reply to a received device handler command. + * + * This also resets #DeviceHandlerCommand to 0. + * + * @param reply the reply type + * @param parameter parameter for the reply + */ + void replyReturnvalueToCommand(ReturnValue_t status, + uint32_t parameter = 0); + + void replyToCommand(ReturnValue_t status, uint32_t parameter = 0); + + /** + * Set the device handler mode + * + * Sets #timeoutStart with every call. + * + * Sets #transitionTargetMode if necessary so transitional states can be + * entered from everywhere without breaking the state machine + * (which relies on a correct #transitionTargetMode). + * + * The submode is left unchanged. + * + * + * @param newMode + */ + void setMode(Mode_t newMode); + + /** + * @overload + * @param submode + */ + void setMode(Mode_t newMode, Submode_t submode); + + /** + * Do the transition to the main modes (MODE_ON, MODE_NORMAL and MODE_RAW). + * + * If the transition is complete, the mode should be set to the target mode, + * which can be deduced from the current mode which is + * [_MODE_TO_ON, _MODE_TO_NORMAL, _MODE_TO_RAW] + * + * The intended target submode is already set. + * The origin submode can be read in subModeFrom. + * + * If the transition can not be completed, the child class can try to reach + * an working mode by setting the mode either directly + * or setting the mode to an transitional mode (TO_ON, TO_NORMAL, TO_RAW) + * if the device needs to be reconfigured. + * + * If nothing works, the child class can wait for the timeout and the base + * class will reset the mode to the mode where the transition + * originated from (the child should report the reason for the failed transition). + * + * The intended way to send commands is to set a flag (enum) indicating + * which command is to be sent here and then to check in + * buildTransitionCommand() for the flag. This flag can also be used by + * doStartUp() and doShutDown() to get a nice and clean implementation of + * buildTransitionCommand() without switching through modes. + * + * When the the condition for the completion of the transition is met, the + * mode can be set, for example in the scanForReply() function. + * + * The default implementation goes into the target mode directly. + * + * #transitionFailure can be set to a failure code indicating the reason + * for a failed transition + * + * @param modeFrom + * The mode the transition originated from: + * [MODE_ON, MODE_NORMAL, MODE_RAW and _MODE_POWER_DOWN (if the mode changed + * from _MODE_START_UP to _MODE_TO_ON)] + * @param subModeFrom the subMode of modeFrom + */ + virtual void doTransition(Mode_t modeFrom, Submode_t subModeFrom); + + /** + * Is the combination of mode and submode valid? + * + * @param mode + * @param submode + * @return + * - @c RETURN_OK if valid + * - @c RETURN_FAILED if invalid + */ + virtual ReturnValue_t isModeCombinationValid(Mode_t mode, + Submode_t submode); + + /** + * Get the Rmap action for the current step. + * + * The step number can be read from #pstStep. + * + * @return The Rmap action to execute in this step + */ + + virtual CommunicationAction_t getComAction(); + + /** + * Build the device command to send for raw mode. + * + * This is only called in @c MODE_RAW. It is for the rare case that in raw mode packets + * are to be sent by the handler itself. It is NOT needed for the raw commanding service. + * Its only current use is in the STR handler which gets its raw packets from a different + * source. + * Also it can be used for transitional commands, to get the device ready for @c MODE_RAW + * + * As it is almost never used, there is a default implementation returning @c NOTHING_TO_SEND. + * + * #rawPacket and #rawPacketLen must be set by this method to the packet to be sent. + * + * @param[out] id the device command id built + * @return + * - @c RETURN_OK when a command is to be sent + * - not @c NOTHING_TO_SEND when no command is to be sent + */ + virtual ReturnValue_t buildChildRawCommand(); + + /** + * Returns the delay cycle count of a reply. + * A count != 0 indicates that the command is already executed. + * @param deviceCommand The command to look for + * @return The current delay count. If the command does not exist (should never happen) it returns 0. + */ + uint8_t getReplyDelayCycles(DeviceCommandId_t deviceCommand); + + /** + * Construct a command reply containing a raw reply. + * + * It gets space in the #IPCStore, copies data there, then sends a raw reply + * containing the store address. + * + * This method is virtual, as the STR has a different channel to send raw replies + * and overwrites it accordingly. + * + * @param data data to send + * @param len length of @c data + * @param sendTo the messageQueueId of the one to send to + * @param isCommand marks the raw data as a command, the message then will be of type raw_command + */ + virtual void replyRawData(const uint8_t *data, size_t len, + MessageQueueId_t sendTo, bool isCommand = false); + + /** + * Calls replyRawData() with #defaultRawReceiver, but checks if wiretapping is active and if so, + * does not send the Data as the wiretapping will have sent it already + */ + void replyRawReplyIfnotWiretapped(const uint8_t *data, size_t len); + + /** + * notify child about mode change + */ + virtual void modeChanged(void); + + /** + * Enable the reply checking for a command + * + * Is only called, if the command was sent (ie the getWriteReply was successful). + * Must ensure that all replies are activated and correctly linked to the command that initiated it. + * The default implementation looks for a reply with the same id as the command id in the replyMap or + * uses the alternativeReplyId if flagged so. + * When found, copies maxDelayCycles to delayCycles in the reply information and sets the command to + * expect one reply. + * + * Can be overwritten by the child, if a command activates multiple replies + * or replyId differs from commandId. + * Notes for child implementations: + * - If the command was not found in the reply map, NO_REPLY_EXPECTED MUST be returned. + * - A failure code may be returned if something went fundamentally wrong. + * + * @param deviceCommand + * @return - RETURN_OK if a reply was activated. + * - NO_REPLY_EXPECTED if there was no reply found. This is not an + * error case as many commands do not expect a reply. + */ + virtual ReturnValue_t enableReplyInReplyMap(DeviceCommandMap::iterator cmd, + uint8_t expectedReplies = 1, bool useAlternateId = false, + DeviceCommandId_t alternateReplyID = 0); + + /** + * get the state of the PCDU switches in the datapool + * + * @return + * - @c PowerSwitchIF::SWITCH_ON if all switches specified by #switches are on + * - @c PowerSwitchIF::SWITCH_OFF one of the switches specified by #switches are off + * - @c PowerSwitchIF::RETURN_FAILED if an error occured + */ + ReturnValue_t getStateOfSwitches(void); + + /** + * set all datapool variables that are update periodically in normal mode invalid + * + * Child classes should provide an implementation which sets all those variables invalid + * which are set periodically during any normal mode. + */ + virtual void setNormalDatapoolEntriesInvalid() = 0; + + /** + * build a list of sids and pass it to the #hkSwitcher + */ + virtual void changeHK(Mode_t mode, Submode_t submode, bool enable); + + /** + * Children can overwrite this function to suppress checking of the command Queue + * + * This can be used when the child does not want to receive a command in a certain + * situation. Care must be taken that checking is not permanentely disabled as this + * would render the handler unusable. + * + * @return whether checking the queue should NOT be done + */ + virtual bool dontCheckQueue(); + + Mode_t getBaseMode(Mode_t transitionMode); + + bool isAwaitingReply(); + + void handleDeviceTM(SerializeIF *dataSet, DeviceCommandId_t commandId, + bool neverInDataPool = false, bool forceDirectTm = false); + + virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, + uint32_t *msToReachTheMode); + virtual void startTransition(Mode_t mode, Submode_t submode); + virtual void setToExternalControl(); + virtual void announceMode(bool recursive); + + virtual ReturnValue_t letChildHandleMessage(CommandMessage *message); + + /** + * Overwrites SystemObject::triggerEvent in order to inform FDIR"Helper" faster about executed events. + * This is a bit sneaky, but improves responsiveness of the device FDIR. + * @param event The event to be thrown + * @param parameter1 Optional parameter 1 + * @param parameter2 Optional parameter 2 + */ + void triggerEvent(Event event, uint32_t parameter1 = 0, + uint32_t parameter2 = 0); + /** + * Same as triggerEvent, but for forwarding if object is used as proxy. + */ + virtual void forwardEvent(Event event, uint32_t parameter1 = 0, + uint32_t parameter2 = 0) const; + /** + * Checks state of switches in conjunction with mode and triggers an event if they don't fit. + */ + virtual void checkSwitchState(); + + /** + * Reserved for the rare case where a device needs to perform additional operation cyclically in OFF mode. + */ + virtual void doOffActivity(); + + /** + * Reserved for the rare case where a device needs to perform additional operation cyclically in ON mode. + */ + virtual void doOnActivity(); + + /** + * Checks if current mode is transitional mode. + * @return true if mode is transitional, false else. + */ + bool isTransitionalMode(); + + /** + * Checks if current handler state allows reception of external device commands. + * Default implementation allows commands only in plain MODE_ON and MODE_NORMAL. + * @return RETURN_OK if commands are accepted, anything else otherwise. + */ + virtual ReturnValue_t acceptExternalDeviceCommands(); + + bool commandIsExecuting(DeviceCommandId_t commandId); + + /** + * set all switches returned by getSwitches() + * + * @param onOff on == @c SWITCH_ON; off != @c SWITCH_ON + */ + void commandSwitch(ReturnValue_t onOff); +private: + + /** + * State a cookie is in. + * + * Used to keep track of the state of the RMAP communication. + */ + enum CookieState_t { + COOKIE_UNUSED, //!< The Cookie is unused + COOKIE_WRITE_READY, //!< There's data available to send. + COOKIE_READ_SENT, //!< A sendRead command was sent with this cookie + COOKIE_WRITE_SENT //!< A sendWrite command was sent with this cookie + }; + /** + * Information about a cookie. + * + * This is stored in a map for each cookie, to not only track the state, but also information + * about the sent command. Tracking this information is needed as + * the state of a commandId (waiting for reply) is done when a RMAP write reply is received. + */ + struct CookieInfo { + CookieState_t state; + DeviceCommandMap::iterator pendingCommand; + }; + + /** + * @brief Info about the #cookie + * Used to track the state of the communication + */ + CookieInfo cookieInfo; + + /** the object used to set power switches */ + PowerSwitchIF *powerSwitcher = nullptr; + + /** Cached for initialize() */ + static object_id_t defaultHkDestination; + /** HK destination can also be set individually */ + object_id_t hkDestination = objects::NO_OBJECT; + + /** + * @brief Used for timing out mode transitions. + * Set when setMode() is called. + */ + uint32_t timeoutStart = 0; + + /** + * Delay for the current mode transition, used for time out + */ + uint32_t childTransitionDelay; + + /** + * @brief The mode the current transition originated from + * + * This is private so the child can not change it and fuck up the timeouts + * + * IMPORTANT: This is not valid during _MODE_SHUT_DOWN and _MODE_START_UP!! + * (it is _MODE_POWER_DOWN during this modes) + * + * is element of [MODE_ON, MODE_NORMAL, MODE_RAW] + */ + Mode_t transitionSourceMode; + + /** + * the submode of the source mode during a transition + */ + Submode_t transitionSourceSubMode; + + /** + * read the command queue + */ + void readCommandQueue(void); + + /** + * Handle the device handler mode. + * + * - checks whether commands are valid for the current mode, rejects them accordingly + * - checks whether commanded mode transitions are required and calls handleCommandedModeTransition() + * - does the necessary action for the current mode or calls doChildStateMachine in modes @c MODE_TO_ON and @c MODE_TO_OFF + * - actions that happen in transitions (eg setting a timeout) are handled in setMode() + */ + void doStateMachine(void); + + void buildRawDeviceCommand(CommandMessage* message); + void buildInternalCommand(void); + +// /** +// * Send a reply with the current mode and submode. +// */ +// void announceMode(void); + + /** + * Decrement the counter for the timout of replies. + * + * This is called at the beginning of each cycle. It checks whether a reply has timed out (that means a reply was expected + * but not received). + */ + void decrementDeviceReplyMap(void); + + /** + * Convenience function to handle a reply. + * + * Called after scanForReply() has found a packet. Checks if the found id is in the #deviceCommandMap, if so, + * calls interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) for further action. + * + * It also resets the timeout counter for the command id. + * + * @param data the found packet + * @param id the found id + * @foundLen the length of the packet + */ + void handleReply(const uint8_t *data, DeviceCommandId_t id, uint32_t foundLen); + + void replyToReply(DeviceReplyMap::iterator iter, ReturnValue_t status); + /** + * Build and send a command to the device. + * + * This routine checks whether a raw or direct command has been received, checks the content of the received command and + * calls buildCommandFromCommand() for direct commands or sets #rawpacket to the received raw packet. + * If no external command is received or the received command is invalid and the current mode is @c MODE_NORMAL or a transitional mode, + * it asks the child class to build a command (via getNormalDeviceCommand() or getTransitionalDeviceCommand() and buildCommand()) and + * sends the command via RMAP. + */ + void doSendWrite(void); + + /** + * Check if the RMAP sendWrite action was successful. + * + * Depending on the result, the following is done + * - if the device command was external commanded, a reply is sent indicating the result + * - if the action was successful, the reply timout counter is initialized + */ + void doGetWrite(void); + + /** + * Send a RMAP getRead command. + * + * The size of the getRead command is #maxDeviceReplyLen. + * This is always executed, independently from the current mode. + */ + void doSendRead(void); + + /** + * Check the getRead reply and the contained data. + * + * If data was received scanForReply() and, if successful, handleReply() are called. + * If the current mode is @c MODE_RAW, the received packet is sent to the commanding object + * via commandQueue. + */ + void doGetRead(void); + + /** + * Retrive data from the #IPCStore. + * + * @param storageAddress + * @param[out] data + * @param[out] len + * @return + * - @c RETURN_OK @c data is valid + * - @c RETURN_FAILED IPCStore is NULL + * - the return value from the IPCStore if it was not @c RETURN_OK + */ + ReturnValue_t getStorageData(store_address_t storageAddress, uint8_t **data, + uint32_t *len); + + + /** + * @param modeTo either @c MODE_ON, MODE_NORMAL or MODE_RAW NOTHING ELSE!!! + */ + void setTransition(Mode_t modeTo, Submode_t submodeTo); + + /** + * calls the right child function for the transitional submodes + */ + void callChildStatemachine(); + + /** + * Switches the channel of the cookie used for the communication + * + * + * @param newChannel the object Id of the channel to switch to + * @return + * - @c RETURN_OK when cookie was changed + * - @c RETURN_FAILED when cookies could not be changed, eg because the newChannel is not enabled + * - @c returnvalues of RMAPChannelIF::isActive() + */ + ReturnValue_t switchCookieChannel(object_id_t newChannelId); + + ReturnValue_t handleDeviceHandlerMessage(CommandMessage *message); + + virtual ReturnValue_t initializeAfterTaskCreation() override; + DataSetIF* getDataSetHandle(sid_t sid) override; + + void parseReply(const uint8_t* receivedData, + size_t receivedDataLen); +}; + +#endif /* FRAMEWORK_DEVICEHANDLERS_DEVICEHANDLERBASE_H_ */ + diff --git a/devicehandlers/DeviceHandlerFailureIsolation.cpp b/devicehandlers/DeviceHandlerFailureIsolation.cpp index 46e73cd8..54788600 100644 --- a/devicehandlers/DeviceHandlerFailureIsolation.cpp +++ b/devicehandlers/DeviceHandlerFailureIsolation.cpp @@ -1,251 +1,251 @@ -#include -#include -#include -#include -#include -#include - -object_id_t DeviceHandlerFailureIsolation::powerConfirmationId = 0; - -DeviceHandlerFailureIsolation::DeviceHandlerFailureIsolation(object_id_t owner, - object_id_t parent) : - FailureIsolationBase(owner, parent), - strangeReplyCount(MAX_STRANGE_REPLIES, STRANGE_REPLIES_TIME_MS, - parameterDomainBase++), - missedReplyCount( MAX_MISSED_REPLY_COUNT, MISSED_REPLY_TIME_MS, - parameterDomainBase++), - recoveryCounter(MAX_REBOOT, REBOOT_TIME_MS, parameterDomainBase++), - fdirState(NONE), powerConfirmation(0) { -} - -DeviceHandlerFailureIsolation::~DeviceHandlerFailureIsolation() { -} - -ReturnValue_t DeviceHandlerFailureIsolation::eventReceived(EventMessage* event) { - if(isFdirInActionOrAreWeFaulty(event)) { - return RETURN_OK; - } - ReturnValue_t result = RETURN_FAILED; - switch (event->getEvent()) { - case HasModesIF::MODE_TRANSITION_FAILED: - case HasModesIF::OBJECT_IN_INVALID_MODE: - //We'll try a recovery as long as defined in MAX_REBOOT. - //Might cause some AssemblyBase cycles, so keep number low. - handleRecovery(event->getEvent()); - break; - case DeviceHandlerIF::DEVICE_INTERPRETING_REPLY_FAILED: - case DeviceHandlerIF::DEVICE_READING_REPLY_FAILED: - case DeviceHandlerIF::DEVICE_UNREQUESTED_REPLY: - case DeviceHandlerIF::DEVICE_UNKNOWN_REPLY: //Some DH's generate generic reply-ids. - case DeviceHandlerIF::DEVICE_BUILDING_COMMAND_FAILED: - //These faults all mean that there were stupid replies from a device. - if (strangeReplyCount.incrementAndCheck()) { - handleRecovery(event->getEvent()); - } - break; - case DeviceHandlerIF::DEVICE_SENDING_COMMAND_FAILED: - case DeviceHandlerIF::DEVICE_REQUESTING_REPLY_FAILED: - //The two above should never be confirmed. - case DeviceHandlerIF::DEVICE_MISSED_REPLY: - result = sendConfirmationRequest(event); - if (result == HasReturnvaluesIF::RETURN_OK) { - break; - } - //else - if (missedReplyCount.incrementAndCheck()) { - handleRecovery(event->getEvent()); - } - break; - case StorageManagerIF::GET_DATA_FAILED: - case StorageManagerIF::STORE_DATA_FAILED: - //Rather strange bugs, occur in RAW mode only. Ignore. - break; - case DeviceHandlerIF::INVALID_DEVICE_COMMAND: - //Ignore, is bad configuration. We can't do anything in flight. - break; - case HasHealthIF::HEALTH_INFO: - case HasModesIF::MODE_INFO: - case HasModesIF::CHANGING_MODE: - //Do nothing, but mark as handled. - break; - //****Power***** - case PowerSwitchIF::SWITCH_WENT_OFF: - if(hasPowerConfirmation) { - result = sendConfirmationRequest(event, powerConfirmation); - if (result == RETURN_OK) { - setFdirState(DEVICE_MIGHT_BE_OFF); - } - } - break; - case Fuse::FUSE_WENT_OFF: - //Not so good, because PCDU reacted. - case Fuse::POWER_ABOVE_HIGH_LIMIT: - //Better, because software detected over-current. - setFaulty(event->getEvent()); - break; - case Fuse::POWER_BELOW_LOW_LIMIT: - //Device might got stuck during boot, retry. - handleRecovery(event->getEvent()); - break; - //****Thermal***** - case ThermalComponentIF::COMPONENT_TEMP_LOW: - case ThermalComponentIF::COMPONENT_TEMP_HIGH: - case ThermalComponentIF::COMPONENT_TEMP_OOL_LOW: - case ThermalComponentIF::COMPONENT_TEMP_OOL_HIGH: - //Well, the device is not really faulty, but it is required to stay off as long as possible. - setFaulty(event->getEvent()); - break; - case ThermalComponentIF::TEMP_NOT_IN_OP_RANGE: - //Ignore, is information only. - break; - //*******Default monitoring variables. Are currently not used.***** -// case DeviceHandlerIF::MONITORING_LIMIT_EXCEEDED: -// setFaulty(event->getEvent()); -// break; -// case DeviceHandlerIF::MONITORING_AMBIGUOUS: -// break; - default: - //We don't know the event, someone else should handle it. - return RETURN_FAILED; - } - return RETURN_OK; -} - -void DeviceHandlerFailureIsolation::eventConfirmed(EventMessage* event) { - switch (event->getEvent()) { - case DeviceHandlerIF::DEVICE_SENDING_COMMAND_FAILED: - case DeviceHandlerIF::DEVICE_REQUESTING_REPLY_FAILED: - case DeviceHandlerIF::DEVICE_MISSED_REPLY: - if (missedReplyCount.incrementAndCheck()) { - handleRecovery(event->getEvent()); - } - break; - case PowerSwitchIF::SWITCH_WENT_OFF: - //This means the switch went off only for one device. - handleRecovery(event->getEvent()); - break; - default: - break; - } -} - -void DeviceHandlerFailureIsolation::decrementFaultCounters() { - strangeReplyCount.checkForDecrement(); - missedReplyCount.checkForDecrement(); - recoveryCounter.checkForDecrement(); -} - -void DeviceHandlerFailureIsolation::handleRecovery(Event reason) { - clearFaultCounters(); - if (not recoveryCounter.incrementAndCheck()) { - startRecovery(reason); - } else { - setFaulty(reason); - } -} - -void DeviceHandlerFailureIsolation::wasParentsFault(EventMessage* event) { - //We'll better ignore the SWITCH_WENT_OFF event and await a system-wide reset. - //This means, no fault message will come through until a MODE_ or - //HEALTH_INFO message comes through -> Is that ok? - //Same issue in TxFailureIsolation! -// if ((event->getEvent() == PowerSwitchIF::SWITCH_WENT_OFF) -// && (fdirState != RECOVERY_ONGOING)) { -// setFdirState(NONE); -// } -} - -void DeviceHandlerFailureIsolation::clearFaultCounters() { - strangeReplyCount.clear(); - missedReplyCount.clear(); -} - -ReturnValue_t DeviceHandlerFailureIsolation::initialize() { - ReturnValue_t result = FailureIsolationBase::initialize(); - if (result != HasReturnvaluesIF::RETURN_OK) { - sif::error << "DeviceHandlerFailureIsolation::initialize: Could not" - " initialize FailureIsolationBase." << std::endl; - return result; - } - ConfirmsFailuresIF* power = objectManager->get( - powerConfirmationId); - if (power != nullptr) { - powerConfirmation = power->getEventReceptionQueue(); - hasPowerConfirmation = true; - } - - return RETURN_OK; -} - -void DeviceHandlerFailureIsolation::setFdirState(FDIRState state) { - FailureIsolationBase::throwFdirEvent(FDIR_CHANGED_STATE, state, fdirState); - fdirState = state; -} - -void DeviceHandlerFailureIsolation::triggerEvent(Event event, uint32_t parameter1, - uint32_t parameter2) { - //Do not throw error events if fdirState != none. - //This will still forward MODE and HEALTH INFO events in any case. - if (fdirState == NONE || EVENT::getSeverity(event) == SEVERITY::INFO) { - FailureIsolationBase::triggerEvent(event, parameter1, parameter2); - } -} - -bool DeviceHandlerFailureIsolation::isFdirActionInProgress() { - return (fdirState != NONE); -} - -void DeviceHandlerFailureIsolation::startRecovery(Event reason) { - throwFdirEvent(FDIR_STARTS_RECOVERY, EVENT::getEventId(reason)); - setOwnerHealth(HasHealthIF::NEEDS_RECOVERY); - setFdirState(RECOVERY_ONGOING); -} - -ReturnValue_t DeviceHandlerFailureIsolation::getParameter(uint8_t domainId, - uint16_t parameterId, ParameterWrapper* parameterWrapper, - const ParameterWrapper* newValues, uint16_t startAtIndex) { - ReturnValue_t result = strangeReplyCount.getParameter(domainId, parameterId, - parameterWrapper, newValues, startAtIndex); - if (result != INVALID_DOMAIN_ID) { - return result; - } - result = missedReplyCount.getParameter(domainId, parameterId, - parameterWrapper, newValues, startAtIndex); - if (result != INVALID_DOMAIN_ID) { - return result; - } - result = recoveryCounter.getParameter(domainId, parameterId, - parameterWrapper, newValues, startAtIndex); - if (result != INVALID_DOMAIN_ID) { - return result; - } - return INVALID_DOMAIN_ID; -} - -void DeviceHandlerFailureIsolation::setFaulty(Event reason) { - throwFdirEvent(FDIR_TURNS_OFF_DEVICE, EVENT::getEventId(reason)); - setOwnerHealth(HasHealthIF::FAULTY); - setFdirState(AWAIT_SHUTDOWN); -} - -bool DeviceHandlerFailureIsolation::isFdirInActionOrAreWeFaulty( - EventMessage* event) { - if (fdirState != NONE) { - //Only wait for those events, ignore all others. - if (event->getParameter1() == HasHealthIF::HEALTHY - && event->getEvent() == HasHealthIF::HEALTH_INFO) { - setFdirState(NONE); - } - if (event->getEvent() == HasModesIF::MODE_INFO - && fdirState != RECOVERY_ONGOING) { - setFdirState(NONE); - } - return true; - } - if (owner->getHealth() == HasHealthIF::FAULTY - || owner->getHealth() == HasHealthIF::PERMANENT_FAULTY) { - //Ignore all events in case device is already faulty. - return true; - } - return false; -} +#include "../devicehandlers/DeviceHandlerBase.h" +#include "../devicehandlers/DeviceHandlerFailureIsolation.h" +#include "../health/HealthTableIF.h" +#include "../power/Fuse.h" +#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../thermal/ThermalComponentIF.h" + +object_id_t DeviceHandlerFailureIsolation::powerConfirmationId = 0; + +DeviceHandlerFailureIsolation::DeviceHandlerFailureIsolation(object_id_t owner, + object_id_t parent) : + FailureIsolationBase(owner, parent), + strangeReplyCount(MAX_STRANGE_REPLIES, STRANGE_REPLIES_TIME_MS, + parameterDomainBase++), + missedReplyCount( MAX_MISSED_REPLY_COUNT, MISSED_REPLY_TIME_MS, + parameterDomainBase++), + recoveryCounter(MAX_REBOOT, REBOOT_TIME_MS, parameterDomainBase++), + fdirState(NONE), powerConfirmation(0) { +} + +DeviceHandlerFailureIsolation::~DeviceHandlerFailureIsolation() { +} + +ReturnValue_t DeviceHandlerFailureIsolation::eventReceived(EventMessage* event) { + if(isFdirInActionOrAreWeFaulty(event)) { + return RETURN_OK; + } + ReturnValue_t result = RETURN_FAILED; + switch (event->getEvent()) { + case HasModesIF::MODE_TRANSITION_FAILED: + case HasModesIF::OBJECT_IN_INVALID_MODE: + //We'll try a recovery as long as defined in MAX_REBOOT. + //Might cause some AssemblyBase cycles, so keep number low. + handleRecovery(event->getEvent()); + break; + case DeviceHandlerIF::DEVICE_INTERPRETING_REPLY_FAILED: + case DeviceHandlerIF::DEVICE_READING_REPLY_FAILED: + case DeviceHandlerIF::DEVICE_UNREQUESTED_REPLY: + case DeviceHandlerIF::DEVICE_UNKNOWN_REPLY: //Some DH's generate generic reply-ids. + case DeviceHandlerIF::DEVICE_BUILDING_COMMAND_FAILED: + //These faults all mean that there were stupid replies from a device. + if (strangeReplyCount.incrementAndCheck()) { + handleRecovery(event->getEvent()); + } + break; + case DeviceHandlerIF::DEVICE_SENDING_COMMAND_FAILED: + case DeviceHandlerIF::DEVICE_REQUESTING_REPLY_FAILED: + //The two above should never be confirmed. + case DeviceHandlerIF::DEVICE_MISSED_REPLY: + result = sendConfirmationRequest(event); + if (result == HasReturnvaluesIF::RETURN_OK) { + break; + } + //else + if (missedReplyCount.incrementAndCheck()) { + handleRecovery(event->getEvent()); + } + break; + case StorageManagerIF::GET_DATA_FAILED: + case StorageManagerIF::STORE_DATA_FAILED: + //Rather strange bugs, occur in RAW mode only. Ignore. + break; + case DeviceHandlerIF::INVALID_DEVICE_COMMAND: + //Ignore, is bad configuration. We can't do anything in flight. + break; + case HasHealthIF::HEALTH_INFO: + case HasModesIF::MODE_INFO: + case HasModesIF::CHANGING_MODE: + //Do nothing, but mark as handled. + break; + //****Power***** + case PowerSwitchIF::SWITCH_WENT_OFF: + if(hasPowerConfirmation) { + result = sendConfirmationRequest(event, powerConfirmation); + if (result == RETURN_OK) { + setFdirState(DEVICE_MIGHT_BE_OFF); + } + } + break; + case Fuse::FUSE_WENT_OFF: + //Not so good, because PCDU reacted. + case Fuse::POWER_ABOVE_HIGH_LIMIT: + //Better, because software detected over-current. + setFaulty(event->getEvent()); + break; + case Fuse::POWER_BELOW_LOW_LIMIT: + //Device might got stuck during boot, retry. + handleRecovery(event->getEvent()); + break; + //****Thermal***** + case ThermalComponentIF::COMPONENT_TEMP_LOW: + case ThermalComponentIF::COMPONENT_TEMP_HIGH: + case ThermalComponentIF::COMPONENT_TEMP_OOL_LOW: + case ThermalComponentIF::COMPONENT_TEMP_OOL_HIGH: + //Well, the device is not really faulty, but it is required to stay off as long as possible. + setFaulty(event->getEvent()); + break; + case ThermalComponentIF::TEMP_NOT_IN_OP_RANGE: + //Ignore, is information only. + break; + //*******Default monitoring variables. Are currently not used.***** +// case DeviceHandlerIF::MONITORING_LIMIT_EXCEEDED: +// setFaulty(event->getEvent()); +// break; +// case DeviceHandlerIF::MONITORING_AMBIGUOUS: +// break; + default: + //We don't know the event, someone else should handle it. + return RETURN_FAILED; + } + return RETURN_OK; +} + +void DeviceHandlerFailureIsolation::eventConfirmed(EventMessage* event) { + switch (event->getEvent()) { + case DeviceHandlerIF::DEVICE_SENDING_COMMAND_FAILED: + case DeviceHandlerIF::DEVICE_REQUESTING_REPLY_FAILED: + case DeviceHandlerIF::DEVICE_MISSED_REPLY: + if (missedReplyCount.incrementAndCheck()) { + handleRecovery(event->getEvent()); + } + break; + case PowerSwitchIF::SWITCH_WENT_OFF: + //This means the switch went off only for one device. + handleRecovery(event->getEvent()); + break; + default: + break; + } +} + +void DeviceHandlerFailureIsolation::decrementFaultCounters() { + strangeReplyCount.checkForDecrement(); + missedReplyCount.checkForDecrement(); + recoveryCounter.checkForDecrement(); +} + +void DeviceHandlerFailureIsolation::handleRecovery(Event reason) { + clearFaultCounters(); + if (not recoveryCounter.incrementAndCheck()) { + startRecovery(reason); + } else { + setFaulty(reason); + } +} + +void DeviceHandlerFailureIsolation::wasParentsFault(EventMessage* event) { + //We'll better ignore the SWITCH_WENT_OFF event and await a system-wide reset. + //This means, no fault message will come through until a MODE_ or + //HEALTH_INFO message comes through -> Is that ok? + //Same issue in TxFailureIsolation! +// if ((event->getEvent() == PowerSwitchIF::SWITCH_WENT_OFF) +// && (fdirState != RECOVERY_ONGOING)) { +// setFdirState(NONE); +// } +} + +void DeviceHandlerFailureIsolation::clearFaultCounters() { + strangeReplyCount.clear(); + missedReplyCount.clear(); +} + +ReturnValue_t DeviceHandlerFailureIsolation::initialize() { + ReturnValue_t result = FailureIsolationBase::initialize(); + if (result != HasReturnvaluesIF::RETURN_OK) { + sif::error << "DeviceHandlerFailureIsolation::initialize: Could not" + " initialize FailureIsolationBase." << std::endl; + return result; + } + ConfirmsFailuresIF* power = objectManager->get( + powerConfirmationId); + if (power != nullptr) { + powerConfirmation = power->getEventReceptionQueue(); + hasPowerConfirmation = true; + } + + return RETURN_OK; +} + +void DeviceHandlerFailureIsolation::setFdirState(FDIRState state) { + FailureIsolationBase::throwFdirEvent(FDIR_CHANGED_STATE, state, fdirState); + fdirState = state; +} + +void DeviceHandlerFailureIsolation::triggerEvent(Event event, uint32_t parameter1, + uint32_t parameter2) { + //Do not throw error events if fdirState != none. + //This will still forward MODE and HEALTH INFO events in any case. + if (fdirState == NONE || EVENT::getSeverity(event) == SEVERITY::INFO) { + FailureIsolationBase::triggerEvent(event, parameter1, parameter2); + } +} + +bool DeviceHandlerFailureIsolation::isFdirActionInProgress() { + return (fdirState != NONE); +} + +void DeviceHandlerFailureIsolation::startRecovery(Event reason) { + throwFdirEvent(FDIR_STARTS_RECOVERY, EVENT::getEventId(reason)); + setOwnerHealth(HasHealthIF::NEEDS_RECOVERY); + setFdirState(RECOVERY_ONGOING); +} + +ReturnValue_t DeviceHandlerFailureIsolation::getParameter(uint8_t domainId, + uint16_t parameterId, ParameterWrapper* parameterWrapper, + const ParameterWrapper* newValues, uint16_t startAtIndex) { + ReturnValue_t result = strangeReplyCount.getParameter(domainId, parameterId, + parameterWrapper, newValues, startAtIndex); + if (result != INVALID_DOMAIN_ID) { + return result; + } + result = missedReplyCount.getParameter(domainId, parameterId, + parameterWrapper, newValues, startAtIndex); + if (result != INVALID_DOMAIN_ID) { + return result; + } + result = recoveryCounter.getParameter(domainId, parameterId, + parameterWrapper, newValues, startAtIndex); + if (result != INVALID_DOMAIN_ID) { + return result; + } + return INVALID_DOMAIN_ID; +} + +void DeviceHandlerFailureIsolation::setFaulty(Event reason) { + throwFdirEvent(FDIR_TURNS_OFF_DEVICE, EVENT::getEventId(reason)); + setOwnerHealth(HasHealthIF::FAULTY); + setFdirState(AWAIT_SHUTDOWN); +} + +bool DeviceHandlerFailureIsolation::isFdirInActionOrAreWeFaulty( + EventMessage* event) { + if (fdirState != NONE) { + //Only wait for those events, ignore all others. + if (event->getParameter1() == HasHealthIF::HEALTHY + && event->getEvent() == HasHealthIF::HEALTH_INFO) { + setFdirState(NONE); + } + if (event->getEvent() == HasModesIF::MODE_INFO + && fdirState != RECOVERY_ONGOING) { + setFdirState(NONE); + } + return true; + } + if (owner->getHealth() == HasHealthIF::FAULTY + || owner->getHealth() == HasHealthIF::PERMANENT_FAULTY) { + //Ignore all events in case device is already faulty. + return true; + } + return false; +} diff --git a/devicehandlers/DeviceHandlerFailureIsolation.h b/devicehandlers/DeviceHandlerFailureIsolation.h index 4343d88b..25247a8d 100644 --- a/devicehandlers/DeviceHandlerFailureIsolation.h +++ b/devicehandlers/DeviceHandlerFailureIsolation.h @@ -1,54 +1,54 @@ -#ifndef FRAMEWORK_DEVICEHANDLERS_DEVICEHANDLERFAILUREISOLATION_H_ -#define FRAMEWORK_DEVICEHANDLERS_DEVICEHANDLERFAILUREISOLATION_H_ - -#include -#include -namespace Factory{ -void setStaticFrameworkObjectIds(); -} - - -class DeviceHandlerFailureIsolation: public FailureIsolationBase { - friend void (Factory::setStaticFrameworkObjectIds)(); - friend class Heater; -public: - DeviceHandlerFailureIsolation(object_id_t owner, object_id_t parent); - ~DeviceHandlerFailureIsolation(); - ReturnValue_t initialize(); - void triggerEvent(Event event, uint32_t parameter1 = 0, - uint32_t parameter2 = 0);bool isFdirActionInProgress(); - virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, - ParameterWrapper *parameterWrapper, - const ParameterWrapper *newValues, uint16_t startAtIndex); -protected: - FaultCounter strangeReplyCount; - FaultCounter missedReplyCount; - FaultCounter recoveryCounter; - enum FDIRState { - NONE, RECOVERY_ONGOING, DEVICE_MIGHT_BE_OFF, AWAIT_SHUTDOWN - }; - FDIRState fdirState; - bool hasPowerConfirmation = false; - MessageQueueId_t powerConfirmation; - static object_id_t powerConfirmationId; - // TODO: Are those hardcoded value? How can they be changed. - static const uint32_t MAX_REBOOT = 1; - static const uint32_t REBOOT_TIME_MS = 180000; - static const uint32_t MAX_STRANGE_REPLIES = 10; - static const uint32_t STRANGE_REPLIES_TIME_MS = 10000; - static const uint32_t MAX_MISSED_REPLY_COUNT = 5; - static const uint32_t MISSED_REPLY_TIME_MS = 10000; - virtual ReturnValue_t eventReceived(EventMessage* event); - virtual void eventConfirmed(EventMessage* event); - void wasParentsFault(EventMessage* event); - void decrementFaultCounters(); - void handleRecovery(Event reason); - virtual void clearFaultCounters(); - void setFdirState(FDIRState state); - void startRecovery(Event reason); - void setFaulty(Event reason); - - bool isFdirInActionOrAreWeFaulty(EventMessage* event); -}; - -#endif /* FRAMEWORK_DEVICEHANDLERS_DEVICEHANDLERFAILUREISOLATION_H_ */ +#ifndef FRAMEWORK_DEVICEHANDLERS_DEVICEHANDLERFAILUREISOLATION_H_ +#define FRAMEWORK_DEVICEHANDLERS_DEVICEHANDLERFAILUREISOLATION_H_ + +#include "../fdir/FaultCounter.h" +#include "../fdir/FailureIsolationBase.h" +namespace Factory{ +void setStaticFrameworkObjectIds(); +} + + +class DeviceHandlerFailureIsolation: public FailureIsolationBase { + friend void (Factory::setStaticFrameworkObjectIds)(); + friend class Heater; +public: + DeviceHandlerFailureIsolation(object_id_t owner, object_id_t parent); + ~DeviceHandlerFailureIsolation(); + ReturnValue_t initialize(); + void triggerEvent(Event event, uint32_t parameter1 = 0, + uint32_t parameter2 = 0);bool isFdirActionInProgress(); + virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, + ParameterWrapper *parameterWrapper, + const ParameterWrapper *newValues, uint16_t startAtIndex); +protected: + FaultCounter strangeReplyCount; + FaultCounter missedReplyCount; + FaultCounter recoveryCounter; + enum FDIRState { + NONE, RECOVERY_ONGOING, DEVICE_MIGHT_BE_OFF, AWAIT_SHUTDOWN + }; + FDIRState fdirState; + bool hasPowerConfirmation = false; + MessageQueueId_t powerConfirmation; + static object_id_t powerConfirmationId; + // TODO: Are those hardcoded value? How can they be changed. + static const uint32_t MAX_REBOOT = 1; + static const uint32_t REBOOT_TIME_MS = 180000; + static const uint32_t MAX_STRANGE_REPLIES = 10; + static const uint32_t STRANGE_REPLIES_TIME_MS = 10000; + static const uint32_t MAX_MISSED_REPLY_COUNT = 5; + static const uint32_t MISSED_REPLY_TIME_MS = 10000; + virtual ReturnValue_t eventReceived(EventMessage* event); + virtual void eventConfirmed(EventMessage* event); + void wasParentsFault(EventMessage* event); + void decrementFaultCounters(); + void handleRecovery(Event reason); + virtual void clearFaultCounters(); + void setFdirState(FDIRState state); + void startRecovery(Event reason); + void setFaulty(Event reason); + + bool isFdirInActionOrAreWeFaulty(EventMessage* event); +}; + +#endif /* FRAMEWORK_DEVICEHANDLERS_DEVICEHANDLERFAILUREISOLATION_H_ */ diff --git a/devicehandlers/DeviceHandlerIF.h b/devicehandlers/DeviceHandlerIF.h index 59302080..67ab37f7 100644 --- a/devicehandlers/DeviceHandlerIF.h +++ b/devicehandlers/DeviceHandlerIF.h @@ -1,155 +1,155 @@ -#ifndef DEVICEHANDLERIF_H_ -#define DEVICEHANDLERIF_H_ - -#include -#include -#include -#include -#include - -/** - * @brief This is the Interface used to communicate with a device handler. - * @details Includes all expected return values, events and modes. - * - */ -class DeviceHandlerIF { -public: - - static const uint8_t TRANSITION_MODE_CHILD_ACTION_MASK = 0x20; - static const uint8_t TRANSITION_MODE_BASE_ACTION_MASK = 0x10; - - /** - * @brief This is the mode the device handler is in. - * - * @details The mode of the device handler must not be confused with the mode the device is in. - * The mode of the device itself is transparent to the user but related to the mode of the handler. - * MODE_ON and MODE_OFF are included in hasModesIF.h - */ - - // MODE_ON = 0, //!< The device is powered and ready to perform operations. In this mode, no commands are sent by the device handler itself, but direct commands van be commanded and will be interpreted - // MODE_OFF = 1, //!< The device is powered off. The only command accepted in this mode is a mode change to on. - //! The device is powered on and the device handler periodically sends - //! commands. The commands to be sent are selected by the handler - //! according to the submode. - static const Mode_t MODE_NORMAL = 2; - //! The device is powered on and ready to perform operations. In this mode, - //! raw commands can be sent. The device handler will send all replies - //! received from the command back to the commanding object. - static const Mode_t MODE_RAW = 3; - //! The device is shut down but the switch could not be turned off, so the - //! device still is powered. In this mode, only a mode change to @c MODE_OFF - //! can be commanded, which tries to switch off the device again. - static const Mode_t MODE_ERROR_ON = 4; - //! This is a transitional state which can not be commanded. The device - //! handler performs all commands to get the device in a state ready to - //! perform commands. When this is completed, the mode changes to @c MODE_ON. - static const Mode_t _MODE_START_UP = TRANSITION_MODE_CHILD_ACTION_MASK | 5; - //! This is a transitional state which can not be commanded. - //! The device handler performs all actions and commands to get the device - //! shut down. When the device is off, the mode changes to @c MODE_OFF. - //! It is possible to set the mode to _MODE_SHUT_DOWN to use the to off - //! transition if available. - static const Mode_t _MODE_SHUT_DOWN = TRANSITION_MODE_CHILD_ACTION_MASK | 6; - //! It is possible to set the mode to _MODE_TO_ON to use the to on - //! transition if available. - static const Mode_t _MODE_TO_ON = TRANSITION_MODE_CHILD_ACTION_MASK | HasModesIF::MODE_ON; - //! It is possible to set the mode to _MODE_TO_RAW to use the to raw - //! transition if available. - static const Mode_t _MODE_TO_RAW = TRANSITION_MODE_CHILD_ACTION_MASK | MODE_RAW; - //! It is possible to set the mode to _MODE_TO_NORMAL to use the to normal - //! transition if available. - static const Mode_t _MODE_TO_NORMAL = TRANSITION_MODE_CHILD_ACTION_MASK | MODE_NORMAL; - //! This is a transitional state which can not be commanded. - //! The device is shut down and ready to be switched off. - //! After the command to set the switch off has been sent, - //! the mode changes to @c MODE_WAIT_OFF - static const Mode_t _MODE_POWER_DOWN = TRANSITION_MODE_BASE_ACTION_MASK | 1; - //! This is a transitional state which can not be commanded. The device - //! will be switched on in this state. After the command to set the switch - //! on has been sent, the mode changes to @c MODE_WAIT_ON. - static const Mode_t _MODE_POWER_ON = TRANSITION_MODE_BASE_ACTION_MASK | 2; - //! This is a transitional state which can not be commanded. The switch has - //! been commanded off and the handler waits for it to be off. - //! When the switch is off, the mode changes to @c MODE_OFF. - static const Mode_t _MODE_WAIT_OFF = TRANSITION_MODE_BASE_ACTION_MASK | 3; - //! This is a transitional state which can not be commanded. The switch - //! has been commanded on and the handler waits for it to be on. - //! When the switch is on, the mode changes to @c MODE_TO_ON. - static const Mode_t _MODE_WAIT_ON = TRANSITION_MODE_BASE_ACTION_MASK | 4; - //! This is a transitional state which can not be commanded. The switch has - //! been commanded off and is off now. This state is only to do an RMAP - //! cycle once more where the doSendRead() function will set the mode to - //! MODE_OFF. The reason to do this is to get rid of stuck packets in the IO Board. - static const Mode_t _MODE_SWITCH_IS_OFF = TRANSITION_MODE_BASE_ACTION_MASK | 5; - - static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::CDH; - static const Event DEVICE_BUILDING_COMMAND_FAILED = MAKE_EVENT(0, SEVERITY::LOW); - static const Event DEVICE_SENDING_COMMAND_FAILED = MAKE_EVENT(1, SEVERITY::LOW); - static const Event DEVICE_REQUESTING_REPLY_FAILED = MAKE_EVENT(2, SEVERITY::LOW); - static const Event DEVICE_READING_REPLY_FAILED = MAKE_EVENT(3, SEVERITY::LOW); - static const Event DEVICE_INTERPRETING_REPLY_FAILED = MAKE_EVENT(4, SEVERITY::LOW); - static const Event DEVICE_MISSED_REPLY = MAKE_EVENT(5, SEVERITY::LOW); - static const Event DEVICE_UNKNOWN_REPLY = MAKE_EVENT(6, SEVERITY::LOW); - static const Event DEVICE_UNREQUESTED_REPLY = MAKE_EVENT(7, SEVERITY::LOW); - static const Event INVALID_DEVICE_COMMAND = MAKE_EVENT(8, SEVERITY::LOW); //!< Indicates a SW bug in child class. - static const Event MONITORING_LIMIT_EXCEEDED = MAKE_EVENT(9, SEVERITY::LOW); - static const Event MONITORING_AMBIGUOUS = MAKE_EVENT(10, SEVERITY::HIGH); - - static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_IF; - - // Standard codes used when building commands. - static const ReturnValue_t NO_COMMAND_DATA = MAKE_RETURN_CODE(0xA0); //!< If no command data was given when expected. - static const ReturnValue_t COMMAND_NOT_SUPPORTED = MAKE_RETURN_CODE(0xA1); //!< Command ID not in commandMap. Checked in DHB - static const ReturnValue_t COMMAND_ALREADY_SENT = MAKE_RETURN_CODE(0xA2); //!< Command was already executed. Checked in DHB - static const ReturnValue_t COMMAND_WAS_NOT_SENT = MAKE_RETURN_CODE(0xA3); - static const ReturnValue_t CANT_SWITCH_ADDRESS = MAKE_RETURN_CODE(0xA4); - static const ReturnValue_t WRONG_MODE_FOR_COMMAND = MAKE_RETURN_CODE(0xA5); - static const ReturnValue_t TIMEOUT = MAKE_RETURN_CODE(0xA6); - static const ReturnValue_t BUSY = MAKE_RETURN_CODE(0xA7); - static const ReturnValue_t NO_REPLY_EXPECTED = MAKE_RETURN_CODE(0xA8); //!< Used to indicate that this is a command-only command. - static const ReturnValue_t NON_OP_TEMPERATURE = MAKE_RETURN_CODE(0xA9); - static const ReturnValue_t COMMAND_NOT_IMPLEMENTED = MAKE_RETURN_CODE(0xAA); - - // Standard codes used in scanForReply - static const ReturnValue_t CHECKSUM_ERROR = MAKE_RETURN_CODE(0xB0); - static const ReturnValue_t LENGTH_MISSMATCH = MAKE_RETURN_CODE(0xB1); - static const ReturnValue_t INVALID_DATA = MAKE_RETURN_CODE(0xB2); - static const ReturnValue_t PROTOCOL_ERROR = MAKE_RETURN_CODE(0xB3); - - // Standard codes used in interpretDeviceReply - static const ReturnValue_t DEVICE_DID_NOT_EXECUTE = MAKE_RETURN_CODE(0xC0); //the device reported, that it did not execute the command - static const ReturnValue_t DEVICE_REPORTED_ERROR = MAKE_RETURN_CODE(0xC1); - static const ReturnValue_t UNKNOW_DEVICE_REPLY = MAKE_RETURN_CODE(0xC2); //the deviceCommandId reported by scanforReply is unknown - static const ReturnValue_t DEVICE_REPLY_INVALID = MAKE_RETURN_CODE(0xC3); //syntax etc is correct but still not ok, eg parameters where none are expected - - // Standard codes used in buildCommandFromCommand - static const ReturnValue_t INVALID_COMMAND_PARAMETER = MAKE_RETURN_CODE(0xD0); - static const ReturnValue_t INVALID_NUMBER_OR_LENGTH_OF_PARAMETERS = MAKE_RETURN_CODE(0xD1); - - /** - * Communication action that will be executed. - * - * This is used by the child class to tell the base class what to do. - */ - enum CommunicationAction_t: uint8_t { - SEND_WRITE,//!< Send write - GET_WRITE, //!< Get write - SEND_READ, //!< Send read - GET_READ, //!< Get read - NOTHING //!< Do nothing. - }; - - /** - * Default Destructor - */ - virtual ~DeviceHandlerIF() {} - - /** - * This MessageQueue is used to command the device handler. - * @return the id of the MessageQueue - */ - virtual MessageQueueId_t getCommandQueue() const = 0; - -}; - -#endif /* DEVICEHANDLERIF_H_ */ +#ifndef DEVICEHANDLERIF_H_ +#define DEVICEHANDLERIF_H_ + +#include "../action/HasActionsIF.h" +#include "../devicehandlers/DeviceHandlerMessage.h" +#include "../events/Event.h" +#include "../modes/HasModesIF.h" +#include "../ipc/MessageQueueSenderIF.h" + +/** + * @brief This is the Interface used to communicate with a device handler. + * @details Includes all expected return values, events and modes. + * + */ +class DeviceHandlerIF { +public: + + static const uint8_t TRANSITION_MODE_CHILD_ACTION_MASK = 0x20; + static const uint8_t TRANSITION_MODE_BASE_ACTION_MASK = 0x10; + + /** + * @brief This is the mode the device handler is in. + * + * @details The mode of the device handler must not be confused with the mode the device is in. + * The mode of the device itself is transparent to the user but related to the mode of the handler. + * MODE_ON and MODE_OFF are included in hasModesIF.h + */ + + // MODE_ON = 0, //!< The device is powered and ready to perform operations. In this mode, no commands are sent by the device handler itself, but direct commands van be commanded and will be interpreted + // MODE_OFF = 1, //!< The device is powered off. The only command accepted in this mode is a mode change to on. + //! The device is powered on and the device handler periodically sends + //! commands. The commands to be sent are selected by the handler + //! according to the submode. + static const Mode_t MODE_NORMAL = 2; + //! The device is powered on and ready to perform operations. In this mode, + //! raw commands can be sent. The device handler will send all replies + //! received from the command back to the commanding object. + static const Mode_t MODE_RAW = 3; + //! The device is shut down but the switch could not be turned off, so the + //! device still is powered. In this mode, only a mode change to @c MODE_OFF + //! can be commanded, which tries to switch off the device again. + static const Mode_t MODE_ERROR_ON = 4; + //! This is a transitional state which can not be commanded. The device + //! handler performs all commands to get the device in a state ready to + //! perform commands. When this is completed, the mode changes to @c MODE_ON. + static const Mode_t _MODE_START_UP = TRANSITION_MODE_CHILD_ACTION_MASK | 5; + //! This is a transitional state which can not be commanded. + //! The device handler performs all actions and commands to get the device + //! shut down. When the device is off, the mode changes to @c MODE_OFF. + //! It is possible to set the mode to _MODE_SHUT_DOWN to use the to off + //! transition if available. + static const Mode_t _MODE_SHUT_DOWN = TRANSITION_MODE_CHILD_ACTION_MASK | 6; + //! It is possible to set the mode to _MODE_TO_ON to use the to on + //! transition if available. + static const Mode_t _MODE_TO_ON = TRANSITION_MODE_CHILD_ACTION_MASK | HasModesIF::MODE_ON; + //! It is possible to set the mode to _MODE_TO_RAW to use the to raw + //! transition if available. + static const Mode_t _MODE_TO_RAW = TRANSITION_MODE_CHILD_ACTION_MASK | MODE_RAW; + //! It is possible to set the mode to _MODE_TO_NORMAL to use the to normal + //! transition if available. + static const Mode_t _MODE_TO_NORMAL = TRANSITION_MODE_CHILD_ACTION_MASK | MODE_NORMAL; + //! This is a transitional state which can not be commanded. + //! The device is shut down and ready to be switched off. + //! After the command to set the switch off has been sent, + //! the mode changes to @c MODE_WAIT_OFF + static const Mode_t _MODE_POWER_DOWN = TRANSITION_MODE_BASE_ACTION_MASK | 1; + //! This is a transitional state which can not be commanded. The device + //! will be switched on in this state. After the command to set the switch + //! on has been sent, the mode changes to @c MODE_WAIT_ON. + static const Mode_t _MODE_POWER_ON = TRANSITION_MODE_BASE_ACTION_MASK | 2; + //! This is a transitional state which can not be commanded. The switch has + //! been commanded off and the handler waits for it to be off. + //! When the switch is off, the mode changes to @c MODE_OFF. + static const Mode_t _MODE_WAIT_OFF = TRANSITION_MODE_BASE_ACTION_MASK | 3; + //! This is a transitional state which can not be commanded. The switch + //! has been commanded on and the handler waits for it to be on. + //! When the switch is on, the mode changes to @c MODE_TO_ON. + static const Mode_t _MODE_WAIT_ON = TRANSITION_MODE_BASE_ACTION_MASK | 4; + //! This is a transitional state which can not be commanded. The switch has + //! been commanded off and is off now. This state is only to do an RMAP + //! cycle once more where the doSendRead() function will set the mode to + //! MODE_OFF. The reason to do this is to get rid of stuck packets in the IO Board. + static const Mode_t _MODE_SWITCH_IS_OFF = TRANSITION_MODE_BASE_ACTION_MASK | 5; + + static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::CDH; + static const Event DEVICE_BUILDING_COMMAND_FAILED = MAKE_EVENT(0, SEVERITY::LOW); + static const Event DEVICE_SENDING_COMMAND_FAILED = MAKE_EVENT(1, SEVERITY::LOW); + static const Event DEVICE_REQUESTING_REPLY_FAILED = MAKE_EVENT(2, SEVERITY::LOW); + static const Event DEVICE_READING_REPLY_FAILED = MAKE_EVENT(3, SEVERITY::LOW); + static const Event DEVICE_INTERPRETING_REPLY_FAILED = MAKE_EVENT(4, SEVERITY::LOW); + static const Event DEVICE_MISSED_REPLY = MAKE_EVENT(5, SEVERITY::LOW); + static const Event DEVICE_UNKNOWN_REPLY = MAKE_EVENT(6, SEVERITY::LOW); + static const Event DEVICE_UNREQUESTED_REPLY = MAKE_EVENT(7, SEVERITY::LOW); + static const Event INVALID_DEVICE_COMMAND = MAKE_EVENT(8, SEVERITY::LOW); //!< Indicates a SW bug in child class. + static const Event MONITORING_LIMIT_EXCEEDED = MAKE_EVENT(9, SEVERITY::LOW); + static const Event MONITORING_AMBIGUOUS = MAKE_EVENT(10, SEVERITY::HIGH); + + static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_IF; + + // Standard codes used when building commands. + static const ReturnValue_t NO_COMMAND_DATA = MAKE_RETURN_CODE(0xA0); //!< If no command data was given when expected. + static const ReturnValue_t COMMAND_NOT_SUPPORTED = MAKE_RETURN_CODE(0xA1); //!< Command ID not in commandMap. Checked in DHB + static const ReturnValue_t COMMAND_ALREADY_SENT = MAKE_RETURN_CODE(0xA2); //!< Command was already executed. Checked in DHB + static const ReturnValue_t COMMAND_WAS_NOT_SENT = MAKE_RETURN_CODE(0xA3); + static const ReturnValue_t CANT_SWITCH_ADDRESS = MAKE_RETURN_CODE(0xA4); + static const ReturnValue_t WRONG_MODE_FOR_COMMAND = MAKE_RETURN_CODE(0xA5); + static const ReturnValue_t TIMEOUT = MAKE_RETURN_CODE(0xA6); + static const ReturnValue_t BUSY = MAKE_RETURN_CODE(0xA7); + static const ReturnValue_t NO_REPLY_EXPECTED = MAKE_RETURN_CODE(0xA8); //!< Used to indicate that this is a command-only command. + static const ReturnValue_t NON_OP_TEMPERATURE = MAKE_RETURN_CODE(0xA9); + static const ReturnValue_t COMMAND_NOT_IMPLEMENTED = MAKE_RETURN_CODE(0xAA); + + // Standard codes used in scanForReply + static const ReturnValue_t CHECKSUM_ERROR = MAKE_RETURN_CODE(0xB0); + static const ReturnValue_t LENGTH_MISSMATCH = MAKE_RETURN_CODE(0xB1); + static const ReturnValue_t INVALID_DATA = MAKE_RETURN_CODE(0xB2); + static const ReturnValue_t PROTOCOL_ERROR = MAKE_RETURN_CODE(0xB3); + + // Standard codes used in interpretDeviceReply + static const ReturnValue_t DEVICE_DID_NOT_EXECUTE = MAKE_RETURN_CODE(0xC0); //the device reported, that it did not execute the command + static const ReturnValue_t DEVICE_REPORTED_ERROR = MAKE_RETURN_CODE(0xC1); + static const ReturnValue_t UNKNOW_DEVICE_REPLY = MAKE_RETURN_CODE(0xC2); //the deviceCommandId reported by scanforReply is unknown + static const ReturnValue_t DEVICE_REPLY_INVALID = MAKE_RETURN_CODE(0xC3); //syntax etc is correct but still not ok, eg parameters where none are expected + + // Standard codes used in buildCommandFromCommand + static const ReturnValue_t INVALID_COMMAND_PARAMETER = MAKE_RETURN_CODE(0xD0); + static const ReturnValue_t INVALID_NUMBER_OR_LENGTH_OF_PARAMETERS = MAKE_RETURN_CODE(0xD1); + + /** + * Communication action that will be executed. + * + * This is used by the child class to tell the base class what to do. + */ + enum CommunicationAction_t: uint8_t { + SEND_WRITE,//!< Send write + GET_WRITE, //!< Get write + SEND_READ, //!< Send read + GET_READ, //!< Get read + NOTHING //!< Do nothing. + }; + + /** + * Default Destructor + */ + virtual ~DeviceHandlerIF() {} + + /** + * This MessageQueue is used to command the device handler. + * @return the id of the MessageQueue + */ + virtual MessageQueueId_t getCommandQueue() const = 0; + +}; + +#endif /* DEVICEHANDLERIF_H_ */ diff --git a/devicehandlers/DeviceHandlerMessage.cpp b/devicehandlers/DeviceHandlerMessage.cpp index 97abcac5..95e5ae0c 100644 --- a/devicehandlers/DeviceHandlerMessage.cpp +++ b/devicehandlers/DeviceHandlerMessage.cpp @@ -1,101 +1,101 @@ -#include -#include -#include - -DeviceHandlerMessage::DeviceHandlerMessage() { -} - -store_address_t DeviceHandlerMessage::getStoreAddress( - const CommandMessage* message) { - return store_address_t(message->getParameter2()); -} - -uint32_t DeviceHandlerMessage::getDeviceCommandId( - const CommandMessage* message) { - return message->getParameter(); -} - -object_id_t DeviceHandlerMessage::getIoBoardObjectId( - const CommandMessage* message) { - return message->getParameter(); -} - -uint8_t DeviceHandlerMessage::getWiretappingMode( - const CommandMessage* message) { - return message->getParameter(); -} - -//void DeviceHandlerMessage::setDeviceHandlerDirectCommandMessage( -// CommandMessage* message, DeviceCommandId_t deviceCommand, -// store_address_t commandParametersStoreId) { -// message->setCommand(CMD_DIRECT); -// message->setParameter(deviceCommand); -// message->setParameter2(commandParametersStoreId.raw); -//} - -void DeviceHandlerMessage::setDeviceHandlerRawCommandMessage( - CommandMessage* message, store_address_t rawPacketStoreId) { - message->setCommand(CMD_RAW); - message->setParameter2(rawPacketStoreId.raw); -} - -void DeviceHandlerMessage::setDeviceHandlerWiretappingMessage( - CommandMessage* message, uint8_t wiretappingMode) { - message->setCommand(CMD_WIRETAPPING); - message->setParameter(wiretappingMode); -} - -void DeviceHandlerMessage::setDeviceHandlerSwitchIoBoardMessage( - CommandMessage* message, uint32_t ioBoardIdentifier) { - message->setCommand(CMD_SWITCH_ADDRESS); - message->setParameter(ioBoardIdentifier); -} - -object_id_t DeviceHandlerMessage::getDeviceObjectId( - const CommandMessage* message) { - return message->getParameter(); -} - -void DeviceHandlerMessage::setDeviceHandlerRawReplyMessage( - CommandMessage* message, object_id_t deviceObjectid, - store_address_t rawPacketStoreId, bool isCommand) { - if (isCommand) { - message->setCommand(REPLY_RAW_COMMAND); - } else { - message->setCommand(REPLY_RAW_REPLY); - } - message->setParameter(deviceObjectid); - message->setParameter2(rawPacketStoreId.raw); -} - -void DeviceHandlerMessage::setDeviceHandlerDirectCommandReply( - CommandMessage* message, object_id_t deviceObjectid, - store_address_t commandParametersStoreId) { - message->setCommand(REPLY_DIRECT_COMMAND_DATA); - message->setParameter(deviceObjectid); - message->setParameter2(commandParametersStoreId.raw); -} - -void DeviceHandlerMessage::clear(CommandMessage* message) { - switch (message->getCommand()) { - case CMD_RAW: -// case CMD_DIRECT: - case REPLY_RAW_COMMAND: - case REPLY_RAW_REPLY: - case REPLY_DIRECT_COMMAND_DATA: { - StorageManagerIF *ipcStore = objectManager->get( - objects::IPC_STORE); - if (ipcStore != NULL) { - ipcStore->deleteData(getStoreAddress(message)); - } - } - /* NO BREAK falls through*/ - case CMD_SWITCH_ADDRESS: - case CMD_WIRETAPPING: - message->setCommand(CommandMessage::CMD_NONE); - message->setParameter(0); - message->setParameter2(0); - break; - } - -} +#include "../objectmanager/ObjectManagerIF.h" +#include "../devicehandlers/DeviceHandlerMessage.h" +#include "../objectmanager/ObjectManagerIF.h" + +DeviceHandlerMessage::DeviceHandlerMessage() { +} + +store_address_t DeviceHandlerMessage::getStoreAddress( + const CommandMessage* message) { + return store_address_t(message->getParameter2()); +} + +uint32_t DeviceHandlerMessage::getDeviceCommandId( + const CommandMessage* message) { + return message->getParameter(); +} + +object_id_t DeviceHandlerMessage::getIoBoardObjectId( + const CommandMessage* message) { + return message->getParameter(); +} + +uint8_t DeviceHandlerMessage::getWiretappingMode( + const CommandMessage* message) { + return message->getParameter(); +} + +//void DeviceHandlerMessage::setDeviceHandlerDirectCommandMessage( +// CommandMessage* message, DeviceCommandId_t deviceCommand, +// store_address_t commandParametersStoreId) { +// message->setCommand(CMD_DIRECT); +// message->setParameter(deviceCommand); +// message->setParameter2(commandParametersStoreId.raw); +//} + +void DeviceHandlerMessage::setDeviceHandlerRawCommandMessage( + CommandMessage* message, store_address_t rawPacketStoreId) { + message->setCommand(CMD_RAW); + message->setParameter2(rawPacketStoreId.raw); +} + +void DeviceHandlerMessage::setDeviceHandlerWiretappingMessage( + CommandMessage* message, uint8_t wiretappingMode) { + message->setCommand(CMD_WIRETAPPING); + message->setParameter(wiretappingMode); +} + +void DeviceHandlerMessage::setDeviceHandlerSwitchIoBoardMessage( + CommandMessage* message, uint32_t ioBoardIdentifier) { + message->setCommand(CMD_SWITCH_ADDRESS); + message->setParameter(ioBoardIdentifier); +} + +object_id_t DeviceHandlerMessage::getDeviceObjectId( + const CommandMessage* message) { + return message->getParameter(); +} + +void DeviceHandlerMessage::setDeviceHandlerRawReplyMessage( + CommandMessage* message, object_id_t deviceObjectid, + store_address_t rawPacketStoreId, bool isCommand) { + if (isCommand) { + message->setCommand(REPLY_RAW_COMMAND); + } else { + message->setCommand(REPLY_RAW_REPLY); + } + message->setParameter(deviceObjectid); + message->setParameter2(rawPacketStoreId.raw); +} + +void DeviceHandlerMessage::setDeviceHandlerDirectCommandReply( + CommandMessage* message, object_id_t deviceObjectid, + store_address_t commandParametersStoreId) { + message->setCommand(REPLY_DIRECT_COMMAND_DATA); + message->setParameter(deviceObjectid); + message->setParameter2(commandParametersStoreId.raw); +} + +void DeviceHandlerMessage::clear(CommandMessage* message) { + switch (message->getCommand()) { + case CMD_RAW: +// case CMD_DIRECT: + case REPLY_RAW_COMMAND: + case REPLY_RAW_REPLY: + case REPLY_DIRECT_COMMAND_DATA: { + StorageManagerIF *ipcStore = objectManager->get( + objects::IPC_STORE); + if (ipcStore != NULL) { + ipcStore->deleteData(getStoreAddress(message)); + } + } + /* NO BREAK falls through*/ + case CMD_SWITCH_ADDRESS: + case CMD_WIRETAPPING: + message->setCommand(CommandMessage::CMD_NONE); + message->setParameter(0); + message->setParameter2(0); + break; + } + +} diff --git a/devicehandlers/DeviceHandlerMessage.h b/devicehandlers/DeviceHandlerMessage.h index 2bdf03b2..6b54392b 100644 --- a/devicehandlers/DeviceHandlerMessage.h +++ b/devicehandlers/DeviceHandlerMessage.h @@ -1,91 +1,91 @@ -#ifndef DEVICEHANDLERMESSAGE_H_ -#define DEVICEHANDLERMESSAGE_H_ - -#include -#include -#include -#include -//SHOULDDO: rework the static constructors to name the type of command they are building, maybe even hide setting the commandID. - -/** - * This is used to uniquely identify commands that are sent to a device - * - * The values are defined in the device-specific implementations - */ -typedef uint32_t DeviceCommandId_t; - -/** - * The DeviceHandlerMessage is used to send Commands to a DeviceHandlerIF - */ -class DeviceHandlerMessage { -private: - DeviceHandlerMessage(); -public: - - /** - * These are the commands that can be sent to a DeviceHandlerBase - */ - static const uint8_t MESSAGE_ID = messagetypes::DEVICE_HANDLER_COMMAND; - static const Command_t CMD_RAW = MAKE_COMMAND_ID( 1 ); //!< Sends a raw command, setParameter is a ::store_id_t containing the raw packet to send -// static const Command_t CMD_DIRECT = MAKE_COMMAND_ID( 2 ); //!< Sends a direct command, setParameter is a ::DeviceCommandId_t, setParameter2 is a ::store_id_t containing the data needed for the command - static const Command_t CMD_SWITCH_ADDRESS = MAKE_COMMAND_ID( 3 ); //!< Requests a IO-Board switch, setParameter() is the IO-Board identifier - static const Command_t CMD_WIRETAPPING = MAKE_COMMAND_ID( 4 ); //!< (De)Activates the monitoring of all raw traffic in DeviceHandlers, setParameter is 0 to deactivate, 1 to activate - - /*static const Command_t REPLY_SWITCHED_IOBOARD = MAKE_COMMAND_ID(1 );//!< Reply to a @c CMD_SWITCH_IOBOARD, indicates switch was successful, getParameter() contains the board switched to (0: nominal, 1: redundant) - static const Command_t REPLY_CANT_SWITCH_IOBOARD = MAKE_COMMAND_ID( 2); //!< Reply to a @c CMD_SWITCH_IOBOARD, indicating the switch could not be performed, getParameter() contains the error message - static const Command_t REPLY_WIRETAPPING = MAKE_COMMAND_ID( 3); //!< Reply to a @c CMD_WIRETAPPING, getParameter() is the current state, 1 enabled, 0 disabled - - static const Command_t REPLY_COMMAND_WAS_SENT = MAKE_COMMAND_ID(4 );//!< Reply to a @c CMD_RAW or @c CMD_DIRECT, indicates the command was successfully sent to the device, getParameter() contains the ::DeviceCommandId_t - static const Command_t REPLY_COMMAND_NOT_SUPPORTED = MAKE_COMMAND_ID(5 );//!< Reply to a @c CMD_DIRECT, the requested ::DeviceCommand_t is not supported, getParameter() contains the requested ::DeviceCommand_t, getParameter2() contains the ::DeviceCommandId_t - static const Command_t REPLY_COMMAND_WAS_NOT_SENT = MAKE_COMMAND_ID(6 );//!< Reply to a @c CMD_RAW or @c CMD_DIRECT, indicates the command was not sent, getParameter contains the RMAP Return code (@see rmap.h), getParameter2() contains the ::DeviceCommandId_t - - static const Command_t REPLY_COMMAND_ALREADY_SENT = MAKE_COMMAND_ID(7 );//!< Reply to a @c CMD_DIRECT, the requested ::DeviceCommand_t has already been sent to the device and not ye been answered - static const Command_t REPLY_WRONG_MODE_FOR_CMD = MAKE_COMMAND_ID(8 );//!< Reply to a @c CMD_RAW or @c CMD_DIRECT, indicates that the requested command can not be sent in the curent mode, getParameter() contains the DeviceHandlerCommand_t - static const Command_t REPLY_NO_DATA = MAKE_COMMAND_ID(9 ); //!< Reply to a CMD_RAW or @c CMD_DIRECT, indicates that the ::store_id_t was invalid, getParameter() contains the ::DeviceCommandId_t, getPrameter2() contains the error code - */ - static const Command_t REPLY_DIRECT_COMMAND_SENT = ActionMessage::STEP_SUCCESS; //!< Signals that a direct command was sent - static const Command_t REPLY_RAW_COMMAND = MAKE_COMMAND_ID(0x11 ); //!< Contains a raw command sent to the Device - static const Command_t REPLY_RAW_REPLY = MAKE_COMMAND_ID( 0x12); //!< Contains a raw reply from the Device, getParameter() is the ObjcetId of the sender, getParameter2() is a ::store_id_t containing the raw packet received - static const Command_t REPLY_DIRECT_COMMAND_DATA = ActionMessage::DATA_REPLY; - - /** - * Default Destructor - */ - virtual ~DeviceHandlerMessage() { - } - - static store_address_t getStoreAddress(const CommandMessage* message); - static uint32_t getDeviceCommandId(const CommandMessage* message); - static object_id_t getDeviceObjectId(const CommandMessage *message); - static object_id_t getIoBoardObjectId(const CommandMessage* message); - static uint8_t getWiretappingMode(const CommandMessage* message); - -// static void setDeviceHandlerDirectCommandMessage(CommandMessage* message, -// DeviceCommandId_t deviceCommand, -// store_address_t commandParametersStoreId); - - static void setDeviceHandlerDirectCommandReply(CommandMessage* message, - object_id_t deviceObjectid, - store_address_t commandParametersStoreId); - - static void setDeviceHandlerRawCommandMessage(CommandMessage* message, - store_address_t rawPacketStoreId); - - static void setDeviceHandlerRawReplyMessage(CommandMessage* message, - object_id_t deviceObjectid, store_address_t rawPacketStoreId, - bool isCommand); - -// static void setDeviceHandlerMessage(CommandMessage* message, -// Command_t command, DeviceCommandId_t deviceCommand, -// store_address_t commandParametersStoreId); -// static void setDeviceHandlerMessage(CommandMessage* message, -// Command_t command, store_address_t rawPacketStoreId); - static void setDeviceHandlerWiretappingMessage(CommandMessage* message, - uint8_t wiretappingMode); - static void setDeviceHandlerSwitchIoBoardMessage(CommandMessage* message, - object_id_t ioBoardIdentifier); - - static void clear(CommandMessage* message); -}; - -#endif /* DEVICEHANDLERMESSAGE_H_ */ +#ifndef DEVICEHANDLERMESSAGE_H_ +#define DEVICEHANDLERMESSAGE_H_ + +#include "../action/ActionMessage.h" +#include "../ipc/CommandMessage.h" +#include "../objectmanager/SystemObjectIF.h" +#include "../storagemanager/StorageManagerIF.h" +//SHOULDDO: rework the static constructors to name the type of command they are building, maybe even hide setting the commandID. + +/** + * This is used to uniquely identify commands that are sent to a device + * + * The values are defined in the device-specific implementations + */ +typedef uint32_t DeviceCommandId_t; + +/** + * The DeviceHandlerMessage is used to send Commands to a DeviceHandlerIF + */ +class DeviceHandlerMessage { +private: + DeviceHandlerMessage(); +public: + + /** + * These are the commands that can be sent to a DeviceHandlerBase + */ + static const uint8_t MESSAGE_ID = messagetypes::DEVICE_HANDLER_COMMAND; + static const Command_t CMD_RAW = MAKE_COMMAND_ID( 1 ); //!< Sends a raw command, setParameter is a ::store_id_t containing the raw packet to send +// static const Command_t CMD_DIRECT = MAKE_COMMAND_ID( 2 ); //!< Sends a direct command, setParameter is a ::DeviceCommandId_t, setParameter2 is a ::store_id_t containing the data needed for the command + static const Command_t CMD_SWITCH_ADDRESS = MAKE_COMMAND_ID( 3 ); //!< Requests a IO-Board switch, setParameter() is the IO-Board identifier + static const Command_t CMD_WIRETAPPING = MAKE_COMMAND_ID( 4 ); //!< (De)Activates the monitoring of all raw traffic in DeviceHandlers, setParameter is 0 to deactivate, 1 to activate + + /*static const Command_t REPLY_SWITCHED_IOBOARD = MAKE_COMMAND_ID(1 );//!< Reply to a @c CMD_SWITCH_IOBOARD, indicates switch was successful, getParameter() contains the board switched to (0: nominal, 1: redundant) + static const Command_t REPLY_CANT_SWITCH_IOBOARD = MAKE_COMMAND_ID( 2); //!< Reply to a @c CMD_SWITCH_IOBOARD, indicating the switch could not be performed, getParameter() contains the error message + static const Command_t REPLY_WIRETAPPING = MAKE_COMMAND_ID( 3); //!< Reply to a @c CMD_WIRETAPPING, getParameter() is the current state, 1 enabled, 0 disabled + + static const Command_t REPLY_COMMAND_WAS_SENT = MAKE_COMMAND_ID(4 );//!< Reply to a @c CMD_RAW or @c CMD_DIRECT, indicates the command was successfully sent to the device, getParameter() contains the ::DeviceCommandId_t + static const Command_t REPLY_COMMAND_NOT_SUPPORTED = MAKE_COMMAND_ID(5 );//!< Reply to a @c CMD_DIRECT, the requested ::DeviceCommand_t is not supported, getParameter() contains the requested ::DeviceCommand_t, getParameter2() contains the ::DeviceCommandId_t + static const Command_t REPLY_COMMAND_WAS_NOT_SENT = MAKE_COMMAND_ID(6 );//!< Reply to a @c CMD_RAW or @c CMD_DIRECT, indicates the command was not sent, getParameter contains the RMAP Return code (@see rmap.h), getParameter2() contains the ::DeviceCommandId_t + + static const Command_t REPLY_COMMAND_ALREADY_SENT = MAKE_COMMAND_ID(7 );//!< Reply to a @c CMD_DIRECT, the requested ::DeviceCommand_t has already been sent to the device and not ye been answered + static const Command_t REPLY_WRONG_MODE_FOR_CMD = MAKE_COMMAND_ID(8 );//!< Reply to a @c CMD_RAW or @c CMD_DIRECT, indicates that the requested command can not be sent in the curent mode, getParameter() contains the DeviceHandlerCommand_t + static const Command_t REPLY_NO_DATA = MAKE_COMMAND_ID(9 ); //!< Reply to a CMD_RAW or @c CMD_DIRECT, indicates that the ::store_id_t was invalid, getParameter() contains the ::DeviceCommandId_t, getPrameter2() contains the error code + */ + static const Command_t REPLY_DIRECT_COMMAND_SENT = ActionMessage::STEP_SUCCESS; //!< Signals that a direct command was sent + static const Command_t REPLY_RAW_COMMAND = MAKE_COMMAND_ID(0x11 ); //!< Contains a raw command sent to the Device + static const Command_t REPLY_RAW_REPLY = MAKE_COMMAND_ID( 0x12); //!< Contains a raw reply from the Device, getParameter() is the ObjcetId of the sender, getParameter2() is a ::store_id_t containing the raw packet received + static const Command_t REPLY_DIRECT_COMMAND_DATA = ActionMessage::DATA_REPLY; + + /** + * Default Destructor + */ + virtual ~DeviceHandlerMessage() { + } + + static store_address_t getStoreAddress(const CommandMessage* message); + static uint32_t getDeviceCommandId(const CommandMessage* message); + static object_id_t getDeviceObjectId(const CommandMessage *message); + static object_id_t getIoBoardObjectId(const CommandMessage* message); + static uint8_t getWiretappingMode(const CommandMessage* message); + +// static void setDeviceHandlerDirectCommandMessage(CommandMessage* message, +// DeviceCommandId_t deviceCommand, +// store_address_t commandParametersStoreId); + + static void setDeviceHandlerDirectCommandReply(CommandMessage* message, + object_id_t deviceObjectid, + store_address_t commandParametersStoreId); + + static void setDeviceHandlerRawCommandMessage(CommandMessage* message, + store_address_t rawPacketStoreId); + + static void setDeviceHandlerRawReplyMessage(CommandMessage* message, + object_id_t deviceObjectid, store_address_t rawPacketStoreId, + bool isCommand); + +// static void setDeviceHandlerMessage(CommandMessage* message, +// Command_t command, DeviceCommandId_t deviceCommand, +// store_address_t commandParametersStoreId); +// static void setDeviceHandlerMessage(CommandMessage* message, +// Command_t command, store_address_t rawPacketStoreId); + static void setDeviceHandlerWiretappingMessage(CommandMessage* message, + uint8_t wiretappingMode); + static void setDeviceHandlerSwitchIoBoardMessage(CommandMessage* message, + object_id_t ioBoardIdentifier); + + static void clear(CommandMessage* message); +}; + +#endif /* DEVICEHANDLERMESSAGE_H_ */ diff --git a/devicehandlers/DeviceTmReportingWrapper.cpp b/devicehandlers/DeviceTmReportingWrapper.cpp index ce5eb109..f19b02e9 100644 --- a/devicehandlers/DeviceTmReportingWrapper.cpp +++ b/devicehandlers/DeviceTmReportingWrapper.cpp @@ -1,46 +1,46 @@ -#include -#include -#include - -DeviceTmReportingWrapper::DeviceTmReportingWrapper(object_id_t objectId, - ActionId_t actionId, SerializeIF* data) : - objectId(objectId), actionId(actionId), data(data) { -} - -DeviceTmReportingWrapper::~DeviceTmReportingWrapper() { - -} - -ReturnValue_t DeviceTmReportingWrapper::serialize(uint8_t** buffer, - size_t* size, size_t maxSize, Endianness streamEndianness) const { - ReturnValue_t result = SerializeAdapter::serialize(&objectId, - buffer, size, maxSize, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - result = SerializeAdapter::serialize(&actionId, buffer, - size, maxSize, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - return data->serialize(buffer, size, maxSize, streamEndianness); -} - -size_t DeviceTmReportingWrapper::getSerializedSize() const { - return sizeof(objectId) + sizeof(ActionId_t) + data->getSerializedSize(); -} - -ReturnValue_t DeviceTmReportingWrapper::deSerialize(const uint8_t** buffer, - size_t* size, Endianness streamEndianness) { - ReturnValue_t result = SerializeAdapter::deSerialize(&objectId, - buffer, size, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - result = SerializeAdapter::deSerialize(&actionId, buffer, - size, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - return data->deSerialize(buffer, size, streamEndianness); -} +#include "../serialize/SerializeAdapter.h" +#include "../devicehandlers/DeviceTmReportingWrapper.h" +#include "../serialize/SerializeAdapter.h" + +DeviceTmReportingWrapper::DeviceTmReportingWrapper(object_id_t objectId, + ActionId_t actionId, SerializeIF* data) : + objectId(objectId), actionId(actionId), data(data) { +} + +DeviceTmReportingWrapper::~DeviceTmReportingWrapper() { + +} + +ReturnValue_t DeviceTmReportingWrapper::serialize(uint8_t** buffer, + size_t* size, size_t maxSize, Endianness streamEndianness) const { + ReturnValue_t result = SerializeAdapter::serialize(&objectId, + buffer, size, maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = SerializeAdapter::serialize(&actionId, buffer, + size, maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return data->serialize(buffer, size, maxSize, streamEndianness); +} + +size_t DeviceTmReportingWrapper::getSerializedSize() const { + return sizeof(objectId) + sizeof(ActionId_t) + data->getSerializedSize(); +} + +ReturnValue_t DeviceTmReportingWrapper::deSerialize(const uint8_t** buffer, + size_t* size, Endianness streamEndianness) { + ReturnValue_t result = SerializeAdapter::deSerialize(&objectId, + buffer, size, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = SerializeAdapter::deSerialize(&actionId, buffer, + size, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return data->deSerialize(buffer, size, streamEndianness); +} diff --git a/devicehandlers/DeviceTmReportingWrapper.h b/devicehandlers/DeviceTmReportingWrapper.h index 4432b7f1..ecf7089a 100644 --- a/devicehandlers/DeviceTmReportingWrapper.h +++ b/devicehandlers/DeviceTmReportingWrapper.h @@ -1,27 +1,27 @@ -#ifndef DEVICETMREPORTINGWRAPPER_H_ -#define DEVICETMREPORTINGWRAPPER_H_ - -#include -#include -#include - -class DeviceTmReportingWrapper: public SerializeIF { -public: - DeviceTmReportingWrapper(object_id_t objectId, ActionId_t actionId, - SerializeIF *data); - virtual ~DeviceTmReportingWrapper(); - - virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) const override; - - virtual size_t getSerializedSize() const override; - - virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - Endianness streamEndianness) override; -private: - object_id_t objectId; - ActionId_t actionId; - SerializeIF *data; -}; - -#endif /* DEVICETMREPORTINGWRAPPER_H_ */ +#ifndef DEVICETMREPORTINGWRAPPER_H_ +#define DEVICETMREPORTINGWRAPPER_H_ + +#include "../action/HasActionsIF.h" +#include "../objectmanager/SystemObjectIF.h" +#include "../serialize/SerializeIF.h" + +class DeviceTmReportingWrapper: public SerializeIF { +public: + DeviceTmReportingWrapper(object_id_t objectId, ActionId_t actionId, + SerializeIF *data); + virtual ~DeviceTmReportingWrapper(); + + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + size_t maxSize, Endianness streamEndianness) const override; + + virtual size_t getSerializedSize() const override; + + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + Endianness streamEndianness) override; +private: + object_id_t objectId; + ActionId_t actionId; + SerializeIF *data; +}; + +#endif /* DEVICETMREPORTINGWRAPPER_H_ */ diff --git a/devicehandlers/HealthDevice.cpp b/devicehandlers/HealthDevice.cpp index 8367a6bc..de7e4d8c 100644 --- a/devicehandlers/HealthDevice.cpp +++ b/devicehandlers/HealthDevice.cpp @@ -1,59 +1,59 @@ -#include -#include - -HealthDevice::HealthDevice(object_id_t setObjectId, - MessageQueueId_t parentQueue) : - SystemObject(setObjectId), lastHealth(HEALTHY), parentQueue( - parentQueue), commandQueue(), healthHelper(this, setObjectId) { - commandQueue = QueueFactory::instance()->createMessageQueue(3, CommandMessage::MINIMUM_COMMAND_MESSAGE_SIZE); -} - -HealthDevice::~HealthDevice() { - QueueFactory::instance()->deleteMessageQueue(commandQueue); -} - -ReturnValue_t HealthDevice::performOperation(uint8_t opCode) { - CommandMessage command; - ReturnValue_t result = commandQueue->receiveMessage(&command); - if (result == HasReturnvaluesIF::RETURN_OK) { - healthHelper.handleHealthCommand(&command); - } - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t HealthDevice::initialize() { - ReturnValue_t result = SystemObject::initialize(); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - if (parentQueue != 0) { - return healthHelper.initialize(parentQueue); - } else { - return healthHelper.initialize(); - } -} - -MessageQueueId_t HealthDevice::getCommandQueue() const { - return commandQueue->getId(); -} - -void HealthDevice::setParentQueue(MessageQueueId_t parentQueue) { - healthHelper.setParentQueue(parentQueue); -} - -bool HealthDevice::hasHealthChanged() { - bool changed; - HealthState currentHealth = healthHelper.getHealth(); - changed = currentHealth != lastHealth; - lastHealth = currentHealth; - return changed; -} - -ReturnValue_t HealthDevice::setHealth(HealthState health) { - healthHelper.setHealth(health); - return HasReturnvaluesIF::RETURN_OK; -} - -HasHealthIF::HealthState HealthDevice::getHealth() { - return healthHelper.getHealth(); -} +#include "../devicehandlers/HealthDevice.h" +#include "../ipc/QueueFactory.h" + +HealthDevice::HealthDevice(object_id_t setObjectId, + MessageQueueId_t parentQueue) : + SystemObject(setObjectId), lastHealth(HEALTHY), parentQueue( + parentQueue), commandQueue(), healthHelper(this, setObjectId) { + commandQueue = QueueFactory::instance()->createMessageQueue(3, CommandMessage::MINIMUM_COMMAND_MESSAGE_SIZE); +} + +HealthDevice::~HealthDevice() { + QueueFactory::instance()->deleteMessageQueue(commandQueue); +} + +ReturnValue_t HealthDevice::performOperation(uint8_t opCode) { + CommandMessage command; + ReturnValue_t result = commandQueue->receiveMessage(&command); + if (result == HasReturnvaluesIF::RETURN_OK) { + healthHelper.handleHealthCommand(&command); + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t HealthDevice::initialize() { + ReturnValue_t result = SystemObject::initialize(); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if (parentQueue != 0) { + return healthHelper.initialize(parentQueue); + } else { + return healthHelper.initialize(); + } +} + +MessageQueueId_t HealthDevice::getCommandQueue() const { + return commandQueue->getId(); +} + +void HealthDevice::setParentQueue(MessageQueueId_t parentQueue) { + healthHelper.setParentQueue(parentQueue); +} + +bool HealthDevice::hasHealthChanged() { + bool changed; + HealthState currentHealth = healthHelper.getHealth(); + changed = currentHealth != lastHealth; + lastHealth = currentHealth; + return changed; +} + +ReturnValue_t HealthDevice::setHealth(HealthState health) { + healthHelper.setHealth(health); + return HasReturnvaluesIF::RETURN_OK; +} + +HasHealthIF::HealthState HealthDevice::getHealth() { + return healthHelper.getHealth(); +} diff --git a/devicehandlers/HealthDevice.h b/devicehandlers/HealthDevice.h index ffb9e5bd..fb38584e 100644 --- a/devicehandlers/HealthDevice.h +++ b/devicehandlers/HealthDevice.h @@ -1,40 +1,40 @@ -#ifndef HEALTHDEVICE_H_ -#define HEALTHDEVICE_H_ - -#include -#include -#include -#include -#include - -class HealthDevice: public SystemObject, - public ExecutableObjectIF, - public HasHealthIF { -public: - HealthDevice(object_id_t setObjectId, MessageQueueId_t parentQueue); - virtual ~HealthDevice(); - - ReturnValue_t performOperation(uint8_t opCode); - - ReturnValue_t initialize(); - - virtual MessageQueueId_t getCommandQueue() const; - - void setParentQueue(MessageQueueId_t parentQueue); - - bool hasHealthChanged(); - - virtual ReturnValue_t setHealth(HealthState health); - - virtual HealthState getHealth(); - -protected: - HealthState lastHealth; - - MessageQueueId_t parentQueue; - MessageQueueIF* commandQueue; -public: - HealthHelper healthHelper; -}; - -#endif /* HEALTHDEVICE_H_ */ +#ifndef HEALTHDEVICE_H_ +#define HEALTHDEVICE_H_ + +#include "../health/HasHealthIF.h" +#include "../health/HealthHelper.h" +#include "../objectmanager/SystemObject.h" +#include "../tasks/ExecutableObjectIF.h" +#include "../ipc/MessageQueueIF.h" + +class HealthDevice: public SystemObject, + public ExecutableObjectIF, + public HasHealthIF { +public: + HealthDevice(object_id_t setObjectId, MessageQueueId_t parentQueue); + virtual ~HealthDevice(); + + ReturnValue_t performOperation(uint8_t opCode); + + ReturnValue_t initialize(); + + virtual MessageQueueId_t getCommandQueue() const; + + void setParentQueue(MessageQueueId_t parentQueue); + + bool hasHealthChanged(); + + virtual ReturnValue_t setHealth(HealthState health); + + virtual HealthState getHealth(); + +protected: + HealthState lastHealth; + + MessageQueueId_t parentQueue; + MessageQueueIF* commandQueue; +public: + HealthHelper healthHelper; +}; + +#endif /* HEALTHDEVICE_H_ */ diff --git a/events/Event.cpp b/events/Event.cpp index 9ea9f552..a94ae6db 100644 --- a/events/Event.cpp +++ b/events/Event.cpp @@ -1,14 +1,14 @@ -#include -namespace EVENT { -EventId_t getEventId(Event event) { - return (event & 0xFFFF); -} - -EventSeverity_t getSeverity(Event event) { - return ((event >> 16) & 0xFF); -} - -Event makeEvent(EventId_t eventId, EventSeverity_t eventSeverity) { - return (eventSeverity << 16) + (eventId & 0xFFFF); -} -} +#include "../events/Event.h" +namespace EVENT { +EventId_t getEventId(Event event) { + return (event & 0xFFFF); +} + +EventSeverity_t getSeverity(Event event) { + return ((event >> 16) & 0xFF); +} + +Event makeEvent(EventId_t eventId, EventSeverity_t eventSeverity) { + return (eventSeverity << 16) + (eventId & 0xFFFF); +} +} diff --git a/events/Event.h b/events/Event.h index 0a1cfcf2..f613e701 100644 --- a/events/Event.h +++ b/events/Event.h @@ -1,45 +1,45 @@ -#ifndef FRAMEWORK_EVENTS_EVENT_H_ -#define FRAMEWORK_EVENTS_EVENT_H_ - -#include -#include -//could be move to more suitable location -#include - -typedef uint16_t EventId_t; -typedef uint8_t EventSeverity_t; - -#define MAKE_EVENT(id, severity) (((severity)<<16)+(SUBSYSTEM_ID*100)+(id)) - -typedef uint32_t Event; - -namespace EVENT { -EventId_t getEventId(Event event); - -EventSeverity_t getSeverity(Event event); - -Event makeEvent(EventId_t eventId, EventSeverity_t eventSeverity); - -} - -namespace SEVERITY { - static const EventSeverity_t INFO = 1; - static const EventSeverity_t LOW = 2; - static const EventSeverity_t MEDIUM = 3; - static const EventSeverity_t HIGH = 4; -} - -//Unfortunately, this does not work nicely because of the inability to define static classes in headers. -//struct Event { -// Event(uint8_t domain, uint8_t counter, EventSeverity_t severity) : -// id(domain*100+counter), severity(severity) { -// } -// EventId_t id; -// EventSeverity_t severity; -// static const EventSeverity_t INFO = 1; -// static const EventSeverity_t LOW = 2; -// static const EventSeverity_t MEDIUM = 3; -// static const EventSeverity_t HIGH = 4; -//}; - -#endif /* FRAMEWORK_EVENTS_EVENT_H_ */ +#ifndef FRAMEWORK_EVENTS_EVENT_H_ +#define FRAMEWORK_EVENTS_EVENT_H_ + +#include +#include "../events/fwSubsystemIdRanges.h" +//could be move to more suitable location +#include + +typedef uint16_t EventId_t; +typedef uint8_t EventSeverity_t; + +#define MAKE_EVENT(id, severity) (((severity)<<16)+(SUBSYSTEM_ID*100)+(id)) + +typedef uint32_t Event; + +namespace EVENT { +EventId_t getEventId(Event event); + +EventSeverity_t getSeverity(Event event); + +Event makeEvent(EventId_t eventId, EventSeverity_t eventSeverity); + +} + +namespace SEVERITY { + static const EventSeverity_t INFO = 1; + static const EventSeverity_t LOW = 2; + static const EventSeverity_t MEDIUM = 3; + static const EventSeverity_t HIGH = 4; +} + +//Unfortunately, this does not work nicely because of the inability to define static classes in headers. +//struct Event { +// Event(uint8_t domain, uint8_t counter, EventSeverity_t severity) : +// id(domain*100+counter), severity(severity) { +// } +// EventId_t id; +// EventSeverity_t severity; +// static const EventSeverity_t INFO = 1; +// static const EventSeverity_t LOW = 2; +// static const EventSeverity_t MEDIUM = 3; +// static const EventSeverity_t HIGH = 4; +//}; + +#endif /* FRAMEWORK_EVENTS_EVENT_H_ */ diff --git a/events/EventManager.cpp b/events/EventManager.cpp index 04be6f68..5848dd74 100644 --- a/events/EventManager.cpp +++ b/events/EventManager.cpp @@ -1,165 +1,165 @@ -#include -#include -#include -#include -#include - - -const uint16_t EventManager::POOL_SIZES[N_POOLS] = { - sizeof(EventMatchTree::Node), sizeof(EventIdRangeMatcher), - sizeof(ReporterRangeMatcher) }; -// If one checks registerListener calls, there are around 40 (to max 50) -// objects registering for certain events. -// Each listener requires 1 or 2 EventIdMatcher and 1 or 2 ReportRangeMatcher. -// So a good guess is 75 to a max of 100 pools required for each, which fits well. -// SHOULDDO: Shouldn't this be in the config folder and passed via ctor? -const uint16_t EventManager::N_ELEMENTS[N_POOLS] = { 240, 120, 120 }; - -EventManager::EventManager(object_id_t setObjectId) : - SystemObject(setObjectId), - factoryBackend(0, POOL_SIZES, N_ELEMENTS, false, true) { - mutex = MutexFactory::instance()->createMutex(); - eventReportQueue = QueueFactory::instance()->createMessageQueue( - MAX_EVENTS_PER_CYCLE, EventMessage::EVENT_MESSAGE_SIZE); -} - -EventManager::~EventManager() { - QueueFactory::instance()->deleteMessageQueue(eventReportQueue); - MutexFactory::instance()->deleteMutex(mutex); -} - -MessageQueueId_t EventManager::getEventReportQueue() { - return eventReportQueue->getId(); -} - -ReturnValue_t EventManager::performOperation(uint8_t opCode) { - ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; - while (result == HasReturnvaluesIF::RETURN_OK) { - EventMessage message; - result = eventReportQueue->receiveMessage(&message); - if (result == HasReturnvaluesIF::RETURN_OK) { -#ifdef DEBUG - printEvent(&message); -#endif - notifyListeners(&message); - } - } - return HasReturnvaluesIF::RETURN_OK; -} - -void EventManager::notifyListeners(EventMessage* message) { - lockMutex(); - for (auto iter = listenerList.begin(); iter != listenerList.end(); ++iter) { - if (iter->second.match(message)) { - MessageQueueSenderIF::sendMessage(iter->first, message, - message->getSender()); - } - } - unlockMutex(); -} - -ReturnValue_t EventManager::registerListener(MessageQueueId_t listener, -bool forwardAllButSelected) { - auto result = listenerList.insert( - std::pair(listener, - EventMatchTree(&factoryBackend, forwardAllButSelected))); - if (!result.second) { - return HasReturnvaluesIF::RETURN_FAILED; - } - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t EventManager::subscribeToEvent(MessageQueueId_t listener, - EventId_t event) { - return subscribeToEventRange(listener, event); -} - -ReturnValue_t EventManager::subscribeToAllEventsFrom(MessageQueueId_t listener, - object_id_t object) { - return subscribeToEventRange(listener, 0, 0, true, object); -} - -ReturnValue_t EventManager::subscribeToEventRange(MessageQueueId_t listener, - EventId_t idFrom, EventId_t idTo, bool idInverted, - object_id_t reporterFrom, object_id_t reporterTo, - bool reporterInverted) { - auto iter = listenerList.find(listener); - if (iter == listenerList.end()) { - return LISTENER_NOT_FOUND; - } - lockMutex(); - ReturnValue_t result = iter->second.addMatch(idFrom, idTo, idInverted, - reporterFrom, reporterTo, reporterInverted); - unlockMutex(); - return result; -} - -ReturnValue_t EventManager::unsubscribeFromEventRange(MessageQueueId_t listener, - EventId_t idFrom, EventId_t idTo, bool idInverted, - object_id_t reporterFrom, object_id_t reporterTo, - bool reporterInverted) { - auto iter = listenerList.find(listener); - if (iter == listenerList.end()) { - return LISTENER_NOT_FOUND; - } - lockMutex(); - ReturnValue_t result = iter->second.removeMatch(idFrom, idTo, idInverted, - reporterFrom, reporterTo, reporterInverted); - unlockMutex(); - return result; -} - -#ifdef DEBUG - -//forward declaration, should be implemented by mission -const char* translateObject(object_id_t object); -const char * translateEvents(Event event); - -void EventManager::printEvent(EventMessage* message) { - const char *string = 0; - switch (message->getSeverity()) { - case SEVERITY::INFO: -// string = translateObject(message->getReporter()); -// sif::info << "EVENT: "; -// if (string != 0) { -// sif::info << string; -// } else { -// sif::info << "0x" << std::hex << message->getReporter() << std::dec; -// } -// sif::info << " reported " << translateEvents(message->getEvent()) << " (" -// << std::dec << message->getEventId() << std::hex << ") P1: 0x" -// << message->getParameter1() << " P2: 0x" -// << message->getParameter2() << std::dec << std::endl; - break; - default: - string = translateObject(message->getReporter()); - sif::debug << "EventManager: "; - if (string != 0) { - sif::debug << string; - } - else { - sif::debug << "0x" << std::hex << message->getReporter() << std::dec; - } - sif::debug << " reported " << translateEvents(message->getEvent()) - << " (" << std::dec << message->getEventId() << ") " - << std::endl; - - sif::debug << std::hex << "P1 Hex: 0x" << message->getParameter1() - << ", P1 Dec: " << std::dec << message->getParameter1() - << std::endl; - sif::debug << std::hex << "P2 Hex: 0x" << message->getParameter2() - << ", P2 Dec: " << std::dec << message->getParameter2() - << std::endl; - break; - } - -} -#endif - -void EventManager::lockMutex() { - mutex->lockMutex(MutexIF::BLOCKING); -} - -void EventManager::unlockMutex() { - mutex->unlockMutex(); -} +#include "../events/EventManager.h" +#include "../events/EventMessage.h" +#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../ipc/QueueFactory.h" +#include "../ipc/MutexFactory.h" + + +const uint16_t EventManager::POOL_SIZES[N_POOLS] = { + sizeof(EventMatchTree::Node), sizeof(EventIdRangeMatcher), + sizeof(ReporterRangeMatcher) }; +// If one checks registerListener calls, there are around 40 (to max 50) +// objects registering for certain events. +// Each listener requires 1 or 2 EventIdMatcher and 1 or 2 ReportRangeMatcher. +// So a good guess is 75 to a max of 100 pools required for each, which fits well. +// SHOULDDO: Shouldn't this be in the config folder and passed via ctor? +const uint16_t EventManager::N_ELEMENTS[N_POOLS] = { 240, 120, 120 }; + +EventManager::EventManager(object_id_t setObjectId) : + SystemObject(setObjectId), + factoryBackend(0, POOL_SIZES, N_ELEMENTS, false, true) { + mutex = MutexFactory::instance()->createMutex(); + eventReportQueue = QueueFactory::instance()->createMessageQueue( + MAX_EVENTS_PER_CYCLE, EventMessage::EVENT_MESSAGE_SIZE); +} + +EventManager::~EventManager() { + QueueFactory::instance()->deleteMessageQueue(eventReportQueue); + MutexFactory::instance()->deleteMutex(mutex); +} + +MessageQueueId_t EventManager::getEventReportQueue() { + return eventReportQueue->getId(); +} + +ReturnValue_t EventManager::performOperation(uint8_t opCode) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + while (result == HasReturnvaluesIF::RETURN_OK) { + EventMessage message; + result = eventReportQueue->receiveMessage(&message); + if (result == HasReturnvaluesIF::RETURN_OK) { +#ifdef DEBUG + printEvent(&message); +#endif + notifyListeners(&message); + } + } + return HasReturnvaluesIF::RETURN_OK; +} + +void EventManager::notifyListeners(EventMessage* message) { + lockMutex(); + for (auto iter = listenerList.begin(); iter != listenerList.end(); ++iter) { + if (iter->second.match(message)) { + MessageQueueSenderIF::sendMessage(iter->first, message, + message->getSender()); + } + } + unlockMutex(); +} + +ReturnValue_t EventManager::registerListener(MessageQueueId_t listener, +bool forwardAllButSelected) { + auto result = listenerList.insert( + std::pair(listener, + EventMatchTree(&factoryBackend, forwardAllButSelected))); + if (!result.second) { + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t EventManager::subscribeToEvent(MessageQueueId_t listener, + EventId_t event) { + return subscribeToEventRange(listener, event); +} + +ReturnValue_t EventManager::subscribeToAllEventsFrom(MessageQueueId_t listener, + object_id_t object) { + return subscribeToEventRange(listener, 0, 0, true, object); +} + +ReturnValue_t EventManager::subscribeToEventRange(MessageQueueId_t listener, + EventId_t idFrom, EventId_t idTo, bool idInverted, + object_id_t reporterFrom, object_id_t reporterTo, + bool reporterInverted) { + auto iter = listenerList.find(listener); + if (iter == listenerList.end()) { + return LISTENER_NOT_FOUND; + } + lockMutex(); + ReturnValue_t result = iter->second.addMatch(idFrom, idTo, idInverted, + reporterFrom, reporterTo, reporterInverted); + unlockMutex(); + return result; +} + +ReturnValue_t EventManager::unsubscribeFromEventRange(MessageQueueId_t listener, + EventId_t idFrom, EventId_t idTo, bool idInverted, + object_id_t reporterFrom, object_id_t reporterTo, + bool reporterInverted) { + auto iter = listenerList.find(listener); + if (iter == listenerList.end()) { + return LISTENER_NOT_FOUND; + } + lockMutex(); + ReturnValue_t result = iter->second.removeMatch(idFrom, idTo, idInverted, + reporterFrom, reporterTo, reporterInverted); + unlockMutex(); + return result; +} + +#ifdef DEBUG + +//forward declaration, should be implemented by mission +const char* translateObject(object_id_t object); +const char * translateEvents(Event event); + +void EventManager::printEvent(EventMessage* message) { + const char *string = 0; + switch (message->getSeverity()) { + case SEVERITY::INFO: +// string = translateObject(message->getReporter()); +// sif::info << "EVENT: "; +// if (string != 0) { +// sif::info << string; +// } else { +// sif::info << "0x" << std::hex << message->getReporter() << std::dec; +// } +// sif::info << " reported " << translateEvents(message->getEvent()) << " (" +// << std::dec << message->getEventId() << std::hex << ") P1: 0x" +// << message->getParameter1() << " P2: 0x" +// << message->getParameter2() << std::dec << std::endl; + break; + default: + string = translateObject(message->getReporter()); + sif::debug << "EventManager: "; + if (string != 0) { + sif::debug << string; + } + else { + sif::debug << "0x" << std::hex << message->getReporter() << std::dec; + } + sif::debug << " reported " << translateEvents(message->getEvent()) + << " (" << std::dec << message->getEventId() << ") " + << std::endl; + + sif::debug << std::hex << "P1 Hex: 0x" << message->getParameter1() + << ", P1 Dec: " << std::dec << message->getParameter1() + << std::endl; + sif::debug << std::hex << "P2 Hex: 0x" << message->getParameter2() + << ", P2 Dec: " << std::dec << message->getParameter2() + << std::endl; + break; + } + +} +#endif + +void EventManager::lockMutex() { + mutex->lockMutex(MutexIF::BLOCKING); +} + +void EventManager::unlockMutex() { + mutex->unlockMutex(); +} diff --git a/events/EventManager.h b/events/EventManager.h index 6fac8352..5323edd8 100644 --- a/events/EventManager.h +++ b/events/EventManager.h @@ -1,61 +1,61 @@ -#ifndef EVENTMANAGER_H_ -#define EVENTMANAGER_H_ - -#include -#include -#include -#include -#include -#include -#include -#include - -class EventManager: public EventManagerIF, - public ExecutableObjectIF, - public SystemObject { -public: - static const uint16_t MAX_EVENTS_PER_CYCLE = 80; - - EventManager(object_id_t setObjectId); - virtual ~EventManager(); - - MessageQueueId_t getEventReportQueue(); - - ReturnValue_t registerListener(MessageQueueId_t listener, bool forwardAllButSelected = false); - ReturnValue_t subscribeToEvent(MessageQueueId_t listener, EventId_t event); - ReturnValue_t subscribeToAllEventsFrom(MessageQueueId_t listener, - object_id_t object); - ReturnValue_t subscribeToEventRange(MessageQueueId_t listener, - EventId_t idFrom = 0, EventId_t idTo = 0, bool idInverted = false, - object_id_t reporterFrom = 0, object_id_t reporterTo = 0, - bool reporterInverted = false); - ReturnValue_t unsubscribeFromEventRange(MessageQueueId_t listener, - EventId_t idFrom = 0, EventId_t idTo = 0, bool idInverted = false, - object_id_t reporterFrom = 0, object_id_t reporterTo = 0, - bool reporterInverted = false); - ReturnValue_t performOperation(uint8_t opCode); -protected: - - MessageQueueIF* eventReportQueue = nullptr; - - std::map listenerList; - - MutexIF* mutex = nullptr; - - static const uint8_t N_POOLS = 3; - LocalPool factoryBackend; - static const uint16_t POOL_SIZES[N_POOLS]; - static const uint16_t N_ELEMENTS[N_POOLS]; - - void notifyListeners(EventMessage *message); - -#ifdef DEBUG - void printEvent(EventMessage *message); -#endif - - void lockMutex(); - - void unlockMutex(); -}; - -#endif /* EVENTMANAGER_H_ */ +#ifndef EVENTMANAGER_H_ +#define EVENTMANAGER_H_ + +#include "../events/eventmatching/EventMatchTree.h" +#include "../events/EventManagerIF.h" +#include "../objectmanager/SystemObject.h" +#include "../storagemanager/LocalPool.h" +#include "../tasks/ExecutableObjectIF.h" +#include "../ipc/MessageQueueIF.h" +#include "../ipc/MutexIF.h" +#include + +class EventManager: public EventManagerIF, + public ExecutableObjectIF, + public SystemObject { +public: + static const uint16_t MAX_EVENTS_PER_CYCLE = 80; + + EventManager(object_id_t setObjectId); + virtual ~EventManager(); + + MessageQueueId_t getEventReportQueue(); + + ReturnValue_t registerListener(MessageQueueId_t listener, bool forwardAllButSelected = false); + ReturnValue_t subscribeToEvent(MessageQueueId_t listener, EventId_t event); + ReturnValue_t subscribeToAllEventsFrom(MessageQueueId_t listener, + object_id_t object); + ReturnValue_t subscribeToEventRange(MessageQueueId_t listener, + EventId_t idFrom = 0, EventId_t idTo = 0, bool idInverted = false, + object_id_t reporterFrom = 0, object_id_t reporterTo = 0, + bool reporterInverted = false); + ReturnValue_t unsubscribeFromEventRange(MessageQueueId_t listener, + EventId_t idFrom = 0, EventId_t idTo = 0, bool idInverted = false, + object_id_t reporterFrom = 0, object_id_t reporterTo = 0, + bool reporterInverted = false); + ReturnValue_t performOperation(uint8_t opCode); +protected: + + MessageQueueIF* eventReportQueue = nullptr; + + std::map listenerList; + + MutexIF* mutex = nullptr; + + static const uint8_t N_POOLS = 3; + LocalPool factoryBackend; + static const uint16_t POOL_SIZES[N_POOLS]; + static const uint16_t N_ELEMENTS[N_POOLS]; + + void notifyListeners(EventMessage *message); + +#ifdef DEBUG + void printEvent(EventMessage *message); +#endif + + void lockMutex(); + + void unlockMutex(); +}; + +#endif /* EVENTMANAGER_H_ */ diff --git a/events/EventManagerIF.h b/events/EventManagerIF.h index bc0de432..bb36f0a3 100644 --- a/events/EventManagerIF.h +++ b/events/EventManagerIF.h @@ -1,52 +1,52 @@ -#ifndef EVENTMANAGERIF_H_ -#define EVENTMANAGERIF_H_ - -#include -#include -#include -#include - -class EventManagerIF { -public: - - static const uint8_t INTERFACE_ID = CLASS_ID::EVENT_MANAGER_IF; - static const ReturnValue_t LISTENER_NOT_FOUND = MAKE_RETURN_CODE(1); - virtual ~EventManagerIF() { - } - - virtual MessageQueueId_t getEventReportQueue() = 0; - - virtual ReturnValue_t registerListener(MessageQueueId_t listener, bool forwardAllButSelected = false) = 0; - virtual ReturnValue_t subscribeToEvent(MessageQueueId_t listener, - EventId_t event) = 0; - virtual ReturnValue_t subscribeToAllEventsFrom(MessageQueueId_t listener, - object_id_t object) = 0; - virtual ReturnValue_t subscribeToEventRange(MessageQueueId_t listener, - EventId_t idFrom = 0, EventId_t idTo = 0, bool idInverted = false, - object_id_t reporterFrom = 0, object_id_t reporterTo = 0, - bool reporterInverted = false) = 0; - virtual ReturnValue_t unsubscribeFromEventRange(MessageQueueId_t listener, - EventId_t idFrom = 0, EventId_t idTo = 0, bool idInverted = false, - object_id_t reporterFrom = 0, object_id_t reporterTo = 0, - bool reporterInverted = false) = 0; - - static void triggerEvent(object_id_t reportingObject, Event event, - uint32_t parameter1 = 0, uint32_t parameter2 = 0, MessageQueueId_t sentFrom = 0) { - EventMessage message(event, reportingObject, parameter1, parameter2); - triggerEvent(&message, sentFrom); - } - static void triggerEvent(EventMessage* message, MessageQueueId_t sentFrom = 0) { - static MessageQueueId_t eventmanagerQueue = 0; - if (eventmanagerQueue == 0) { - EventManagerIF *eventmanager = objectManager->get( - objects::EVENT_MANAGER); - if (eventmanager != NULL) { - eventmanagerQueue = eventmanager->getEventReportQueue(); - } - } - MessageQueueSenderIF::sendMessage(eventmanagerQueue, message, sentFrom); - } - -}; - -#endif /* EVENTMANAGERIF_H_ */ +#ifndef EVENTMANAGERIF_H_ +#define EVENTMANAGERIF_H_ + +#include "../events/eventmatching/eventmatching.h" +#include "../events/EventMessage.h" +#include "../objectmanager/ObjectManagerIF.h" +#include "../ipc/MessageQueueSenderIF.h" + +class EventManagerIF { +public: + + static const uint8_t INTERFACE_ID = CLASS_ID::EVENT_MANAGER_IF; + static const ReturnValue_t LISTENER_NOT_FOUND = MAKE_RETURN_CODE(1); + virtual ~EventManagerIF() { + } + + virtual MessageQueueId_t getEventReportQueue() = 0; + + virtual ReturnValue_t registerListener(MessageQueueId_t listener, bool forwardAllButSelected = false) = 0; + virtual ReturnValue_t subscribeToEvent(MessageQueueId_t listener, + EventId_t event) = 0; + virtual ReturnValue_t subscribeToAllEventsFrom(MessageQueueId_t listener, + object_id_t object) = 0; + virtual ReturnValue_t subscribeToEventRange(MessageQueueId_t listener, + EventId_t idFrom = 0, EventId_t idTo = 0, bool idInverted = false, + object_id_t reporterFrom = 0, object_id_t reporterTo = 0, + bool reporterInverted = false) = 0; + virtual ReturnValue_t unsubscribeFromEventRange(MessageQueueId_t listener, + EventId_t idFrom = 0, EventId_t idTo = 0, bool idInverted = false, + object_id_t reporterFrom = 0, object_id_t reporterTo = 0, + bool reporterInverted = false) = 0; + + static void triggerEvent(object_id_t reportingObject, Event event, + uint32_t parameter1 = 0, uint32_t parameter2 = 0, MessageQueueId_t sentFrom = 0) { + EventMessage message(event, reportingObject, parameter1, parameter2); + triggerEvent(&message, sentFrom); + } + static void triggerEvent(EventMessage* message, MessageQueueId_t sentFrom = 0) { + static MessageQueueId_t eventmanagerQueue = 0; + if (eventmanagerQueue == 0) { + EventManagerIF *eventmanager = objectManager->get( + objects::EVENT_MANAGER); + if (eventmanager != NULL) { + eventmanagerQueue = eventmanager->getEventReportQueue(); + } + } + MessageQueueSenderIF::sendMessage(eventmanagerQueue, message, sentFrom); + } + +}; + +#endif /* EVENTMANAGERIF_H_ */ diff --git a/events/EventMessage.cpp b/events/EventMessage.cpp index f06f68c3..28538f7f 100644 --- a/events/EventMessage.cpp +++ b/events/EventMessage.cpp @@ -1,114 +1,114 @@ -#include -#include - -EventMessage::EventMessage() { - messageSize = EVENT_MESSAGE_SIZE; - clearEventMessage(); -} - -EventMessage::EventMessage(Event event, object_id_t reporter, - uint32_t parameter1, uint32_t parameter2) { - messageSize = EVENT_MESSAGE_SIZE; - setMessageId(EVENT_MESSAGE); - setEvent(event); - setReporter(reporter); - setParameter1(parameter1); - setParameter2(parameter2); -} - -EventMessage::~EventMessage() { -} - -Event EventMessage::getEvent() { - Event event; - memcpy(&event, getData(), sizeof(Event)); - return (event & 0xFFFFFF); -} - -void EventMessage::setEvent(Event event) { - Event tempEvent; - memcpy(&tempEvent, getData(), sizeof(Event)); - tempEvent = (tempEvent & 0xFF000000) + (event & 0xFFFFFF); - memcpy(getData(), &tempEvent, sizeof(Event)); -} - -uint8_t EventMessage::getMessageId() { - Event event; - memcpy(&event, getData(), sizeof(Event)); - return (event & 0xFF000000) >> 24; -} - -void EventMessage::setMessageId(uint8_t id) { - Event event; - memcpy(&event, getData(), sizeof(Event)); - event = (event & 0x00FFFFFF) + (id << 24); - memcpy(getData(), &event, sizeof(Event)); -} - -EventSeverity_t EventMessage::getSeverity() { - Event event; - memcpy(&event, getData(), sizeof(Event)); - return EVENT::getSeverity(event); -} - -void EventMessage::setSeverity(EventSeverity_t severity) { - Event event; - memcpy(&event, getData(), sizeof(Event)); - event = (event & 0xFF00FFFF) + (severity << 16); - memcpy(getData(), &event, sizeof(Event)); -} - -EventId_t EventMessage::getEventId() { - Event event; - memcpy(&event, getData(), sizeof(Event)); - return EVENT::getEventId(event); -} - -void EventMessage::setEventId(EventId_t eventId) { - Event event; - memcpy(&event, getData(), sizeof(Event)); - event = (event & 0xFFFF0000) + eventId; - memcpy(getData(), &event, sizeof(Event)); -} - -object_id_t EventMessage::getReporter() { - object_id_t parameter; - memcpy(¶meter, getData() + sizeof(Event), sizeof(object_id_t)); - return parameter; -} - -void EventMessage::setReporter(object_id_t reporter) { - memcpy(getData() + sizeof(Event), &reporter, sizeof(object_id_t)); -} - -uint32_t EventMessage::getParameter1() { - uint32_t parameter; - memcpy(¶meter, getData() + sizeof(Event) + sizeof(object_id_t), 4); - return parameter; -} - -void EventMessage::setParameter1(uint32_t parameter) { - memcpy(getData() + sizeof(Event) + sizeof(object_id_t), ¶meter, 4); -} - -uint32_t EventMessage::getParameter2() { - uint32_t parameter; - memcpy(¶meter, getData() + sizeof(Event) + sizeof(object_id_t) + 4, 4); - return parameter; -} - -void EventMessage::setParameter2(uint32_t parameter) { - memcpy(getData() + sizeof(Event) + sizeof(object_id_t) + 4, ¶meter, 4); -} - -void EventMessage::clearEventMessage() { - setEvent(INVALID_EVENT); -} - -bool EventMessage::isClearedEventMessage() { - return getEvent() == INVALID_EVENT; -} - -size_t EventMessage::getMinimumMessageSize() { - return EVENT_MESSAGE_SIZE; -} +#include "../events/EventMessage.h" +#include + +EventMessage::EventMessage() { + messageSize = EVENT_MESSAGE_SIZE; + clearEventMessage(); +} + +EventMessage::EventMessage(Event event, object_id_t reporter, + uint32_t parameter1, uint32_t parameter2) { + messageSize = EVENT_MESSAGE_SIZE; + setMessageId(EVENT_MESSAGE); + setEvent(event); + setReporter(reporter); + setParameter1(parameter1); + setParameter2(parameter2); +} + +EventMessage::~EventMessage() { +} + +Event EventMessage::getEvent() { + Event event; + memcpy(&event, getData(), sizeof(Event)); + return (event & 0xFFFFFF); +} + +void EventMessage::setEvent(Event event) { + Event tempEvent; + memcpy(&tempEvent, getData(), sizeof(Event)); + tempEvent = (tempEvent & 0xFF000000) + (event & 0xFFFFFF); + memcpy(getData(), &tempEvent, sizeof(Event)); +} + +uint8_t EventMessage::getMessageId() { + Event event; + memcpy(&event, getData(), sizeof(Event)); + return (event & 0xFF000000) >> 24; +} + +void EventMessage::setMessageId(uint8_t id) { + Event event; + memcpy(&event, getData(), sizeof(Event)); + event = (event & 0x00FFFFFF) + (id << 24); + memcpy(getData(), &event, sizeof(Event)); +} + +EventSeverity_t EventMessage::getSeverity() { + Event event; + memcpy(&event, getData(), sizeof(Event)); + return EVENT::getSeverity(event); +} + +void EventMessage::setSeverity(EventSeverity_t severity) { + Event event; + memcpy(&event, getData(), sizeof(Event)); + event = (event & 0xFF00FFFF) + (severity << 16); + memcpy(getData(), &event, sizeof(Event)); +} + +EventId_t EventMessage::getEventId() { + Event event; + memcpy(&event, getData(), sizeof(Event)); + return EVENT::getEventId(event); +} + +void EventMessage::setEventId(EventId_t eventId) { + Event event; + memcpy(&event, getData(), sizeof(Event)); + event = (event & 0xFFFF0000) + eventId; + memcpy(getData(), &event, sizeof(Event)); +} + +object_id_t EventMessage::getReporter() { + object_id_t parameter; + memcpy(¶meter, getData() + sizeof(Event), sizeof(object_id_t)); + return parameter; +} + +void EventMessage::setReporter(object_id_t reporter) { + memcpy(getData() + sizeof(Event), &reporter, sizeof(object_id_t)); +} + +uint32_t EventMessage::getParameter1() { + uint32_t parameter; + memcpy(¶meter, getData() + sizeof(Event) + sizeof(object_id_t), 4); + return parameter; +} + +void EventMessage::setParameter1(uint32_t parameter) { + memcpy(getData() + sizeof(Event) + sizeof(object_id_t), ¶meter, 4); +} + +uint32_t EventMessage::getParameter2() { + uint32_t parameter; + memcpy(¶meter, getData() + sizeof(Event) + sizeof(object_id_t) + 4, 4); + return parameter; +} + +void EventMessage::setParameter2(uint32_t parameter) { + memcpy(getData() + sizeof(Event) + sizeof(object_id_t) + 4, ¶meter, 4); +} + +void EventMessage::clearEventMessage() { + setEvent(INVALID_EVENT); +} + +bool EventMessage::isClearedEventMessage() { + return getEvent() == INVALID_EVENT; +} + +size_t EventMessage::getMinimumMessageSize() { + return EVENT_MESSAGE_SIZE; +} diff --git a/events/EventMessage.h b/events/EventMessage.h index 9cbe3336..8769333b 100644 --- a/events/EventMessage.h +++ b/events/EventMessage.h @@ -1,52 +1,52 @@ -#ifndef EVENTMESSAGE_H_ -#define EVENTMESSAGE_H_ - -#include -#include -#include - -/** - * Passing on events through IPC. - * Event Id, severity and message type retrieval is a bit difficult. - */ -class EventMessage: public MessageQueueMessage { -public: - static const uint8_t EVENT_MESSAGE = 0; //!< Normal event - static const uint8_t CONFIRMATION_REQUEST = 1; //!< Request to parent if event is caused by child or not. - static const uint8_t YOUR_FAULT = 2; //!< The fault was caused by child, parent believes it's ok. - static const uint8_t MY_FAULT = 3; //!< The fault was caused by the parent, child is ok. - //Add other messageIDs here if necessary. - static const uint8_t EVENT_MESSAGE_SIZE = HEADER_SIZE + sizeof(Event) - + 3 * sizeof(uint32_t); - - EventMessage(); -// EventMessage(EventId_t event, EventSeverity_t severity, -// object_id_t reporter, uint32_t parameter1, uint32_t parameter2 = 0); - EventMessage(Event event, object_id_t reporter, uint32_t parameter1, - uint32_t parameter2 = 0); - virtual ~EventMessage(); - Event getEvent(); - void setEvent(Event event); - uint8_t getMessageId(); - void setMessageId(uint8_t id); - EventSeverity_t getSeverity(); - void setSeverity(EventSeverity_t severity); - EventId_t getEventId(); - void setEventId(EventId_t event); - object_id_t getReporter(); - void setReporter(object_id_t reporter); - uint32_t getParameter1(); - void setParameter1(uint32_t parameter); - uint32_t getParameter2(); - void setParameter2(uint32_t parameter); - - void clearEventMessage(); - bool isClearedEventMessage(); - -protected: - static const Event INVALID_EVENT = 0; - virtual size_t getMinimumMessageSize(); - -}; - -#endif /* EVENTMESSAGE_H_ */ +#ifndef EVENTMESSAGE_H_ +#define EVENTMESSAGE_H_ + +#include "../events/Event.h" +#include "../ipc/MessageQueueMessage.h" +#include "../objectmanager/ObjectManagerIF.h" + +/** + * Passing on events through IPC. + * Event Id, severity and message type retrieval is a bit difficult. + */ +class EventMessage: public MessageQueueMessage { +public: + static const uint8_t EVENT_MESSAGE = 0; //!< Normal event + static const uint8_t CONFIRMATION_REQUEST = 1; //!< Request to parent if event is caused by child or not. + static const uint8_t YOUR_FAULT = 2; //!< The fault was caused by child, parent believes it's ok. + static const uint8_t MY_FAULT = 3; //!< The fault was caused by the parent, child is ok. + //Add other messageIDs here if necessary. + static const uint8_t EVENT_MESSAGE_SIZE = HEADER_SIZE + sizeof(Event) + + 3 * sizeof(uint32_t); + + EventMessage(); +// EventMessage(EventId_t event, EventSeverity_t severity, +// object_id_t reporter, uint32_t parameter1, uint32_t parameter2 = 0); + EventMessage(Event event, object_id_t reporter, uint32_t parameter1, + uint32_t parameter2 = 0); + virtual ~EventMessage(); + Event getEvent(); + void setEvent(Event event); + uint8_t getMessageId(); + void setMessageId(uint8_t id); + EventSeverity_t getSeverity(); + void setSeverity(EventSeverity_t severity); + EventId_t getEventId(); + void setEventId(EventId_t event); + object_id_t getReporter(); + void setReporter(object_id_t reporter); + uint32_t getParameter1(); + void setParameter1(uint32_t parameter); + uint32_t getParameter2(); + void setParameter2(uint32_t parameter); + + void clearEventMessage(); + bool isClearedEventMessage(); + +protected: + static const Event INVALID_EVENT = 0; + virtual size_t getMinimumMessageSize(); + +}; + +#endif /* EVENTMESSAGE_H_ */ diff --git a/events/EventReportingProxyIF.h b/events/EventReportingProxyIF.h index 8aca4e26..1b8064bd 100644 --- a/events/EventReportingProxyIF.h +++ b/events/EventReportingProxyIF.h @@ -1,19 +1,19 @@ -#ifndef FRAMEWORK_EVENTS_EVENTREPORTINGPROXYIF_H_ -#define FRAMEWORK_EVENTS_EVENTREPORTINGPROXYIF_H_ - -#include - - -class EventReportingProxyIF { -public: - virtual ~EventReportingProxyIF() { - } - - virtual void forwardEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0) const = 0; - -}; - - - - -#endif /* FRAMEWORK_EVENTS_EVENTREPORTINGPROXYIF_H_ */ +#ifndef FRAMEWORK_EVENTS_EVENTREPORTINGPROXYIF_H_ +#define FRAMEWORK_EVENTS_EVENTREPORTINGPROXYIF_H_ + +#include "../events/Event.h" + + +class EventReportingProxyIF { +public: + virtual ~EventReportingProxyIF() { + } + + virtual void forwardEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0) const = 0; + +}; + + + + +#endif /* FRAMEWORK_EVENTS_EVENTREPORTINGPROXYIF_H_ */ diff --git a/events/eventmatching/EventIdRangeMatcher.cpp b/events/eventmatching/EventIdRangeMatcher.cpp index ac9156fd..40220e4b 100644 --- a/events/eventmatching/EventIdRangeMatcher.cpp +++ b/events/eventmatching/EventIdRangeMatcher.cpp @@ -1,12 +1,12 @@ -#include - -EventIdRangeMatcher::EventIdRangeMatcher(EventId_t lower, EventId_t upper, - bool inverted) : EventRangeMatcherBase(lower, upper, inverted) { -} - -EventIdRangeMatcher::~EventIdRangeMatcher() { -} - -bool EventIdRangeMatcher::match(EventMessage* message) { - return rangeMatcher.match(message->getEventId()); -} +#include "../../events/eventmatching/EventIdRangeMatcher.h" + +EventIdRangeMatcher::EventIdRangeMatcher(EventId_t lower, EventId_t upper, + bool inverted) : EventRangeMatcherBase(lower, upper, inverted) { +} + +EventIdRangeMatcher::~EventIdRangeMatcher() { +} + +bool EventIdRangeMatcher::match(EventMessage* message) { + return rangeMatcher.match(message->getEventId()); +} diff --git a/events/eventmatching/EventIdRangeMatcher.h b/events/eventmatching/EventIdRangeMatcher.h index 57b77cb1..ffc2ce80 100644 --- a/events/eventmatching/EventIdRangeMatcher.h +++ b/events/eventmatching/EventIdRangeMatcher.h @@ -1,13 +1,13 @@ -#ifndef FRAMEWORK_EVENTS_EVENTMATCHING_EVENTIDRANGEMATCHER_H_ -#define FRAMEWORK_EVENTS_EVENTMATCHING_EVENTIDRANGEMATCHER_H_ - -#include - -class EventIdRangeMatcher: public EventRangeMatcherBase { -public: - EventIdRangeMatcher(EventId_t lower, EventId_t upper, bool inverted); - ~EventIdRangeMatcher(); - bool match(EventMessage* message); -}; - -#endif /* FRAMEWORK_EVENTS_EVENTMATCHING_EVENTIDRANGEMATCHER_H_ */ +#ifndef FRAMEWORK_EVENTS_EVENTMATCHING_EVENTIDRANGEMATCHER_H_ +#define FRAMEWORK_EVENTS_EVENTMATCHING_EVENTIDRANGEMATCHER_H_ + +#include "../../events/eventmatching/EventRangeMatcherBase.h" + +class EventIdRangeMatcher: public EventRangeMatcherBase { +public: + EventIdRangeMatcher(EventId_t lower, EventId_t upper, bool inverted); + ~EventIdRangeMatcher(); + bool match(EventMessage* message); +}; + +#endif /* FRAMEWORK_EVENTS_EVENTMATCHING_EVENTIDRANGEMATCHER_H_ */ diff --git a/events/eventmatching/EventMatchTree.cpp b/events/eventmatching/EventMatchTree.cpp index e1925b8f..fef1b83e 100644 --- a/events/eventmatching/EventMatchTree.cpp +++ b/events/eventmatching/EventMatchTree.cpp @@ -1,149 +1,149 @@ -#include -#include -#include -#include - -EventMatchTree::EventMatchTree(StorageManagerIF* storageBackend, - bool invertedMatch) : - MatchTree(end(), 1), factory(storageBackend), invertedMatch( - invertedMatch) { -} - -EventMatchTree::~EventMatchTree() { -} - -bool EventMatchTree::match(EventMessage* number) { - if (invertedMatch) { - return !MatchTree::match(number); - } else { - return MatchTree::match(number); - } -} - -ReturnValue_t EventMatchTree::addMatch(EventId_t idFrom, EventId_t idTo, - bool idInverted, object_id_t reporterFrom, object_id_t reporterTo, - bool reporterInverted) { - if (idFrom == 0) { - //Assuming all events shall be forwarded. - idTo = 0; - idInverted = true; - } - if (idTo == 0) { - idTo = idFrom; - } - iterator lastTest; - ReturnValue_t result = findOrInsertRangeMatcher(begin(), idFrom, idTo, idInverted, &lastTest); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - if (reporterFrom == 0) { - //No need to add another AND branch - return RETURN_OK; - } - if (reporterTo == 0) { - reporterTo = reporterFrom; - } - return findOrInsertRangeMatcher( - lastTest.left(), reporterFrom, reporterTo, reporterInverted, - &lastTest); -} - -ReturnValue_t EventMatchTree::removeMatch(EventId_t idFrom, EventId_t idTo, - bool idInverted, object_id_t reporterFrom, object_id_t reporterTo, - bool reporterInverted) { - - iterator foundElement; - - if (idFrom == 0) { - //Assuming a "forward all events" request. - idTo = 0; - idInverted = true; - } - if (idTo == 0) { - idTo = idFrom; - } - foundElement = findRangeMatcher(begin(), - idFrom, idTo, idInverted); - if (foundElement == end()) { - return NO_MATCH; //Can't tell if too detailed or just not found. - } - if (reporterFrom == 0) { - if (foundElement.left() == end()) { - return removeElementAndReconnectChildren(foundElement); - } else { - return TOO_GENERAL_REQUEST; - } - } - if (reporterTo == 0) { - reporterTo = reporterFrom; - } - foundElement = findRangeMatcher( - foundElement.left(), reporterFrom, reporterTo, reporterInverted); - if (foundElement == end()) { - return NO_MATCH; - } else { - return removeElementAndReconnectChildren(foundElement); - } -} - -template -inline ReturnValue_t EventMatchTree::findOrInsertRangeMatcher(iterator start, - VALUE_T idFrom, VALUE_T idTo, bool inverted, iterator* lastTest) { - bool attachToBranch = AND; - iterator iter = start; - while (iter != end()) { - INSERTION_T* matcher = static_cast(*iter); - attachToBranch = OR; - *lastTest = iter; - if ((matcher->rangeMatcher.lowerBound == idFrom) - && (matcher->rangeMatcher.upperBound == idTo) - && (matcher->rangeMatcher.inverted == inverted)) { - return RETURN_OK; - } else { - iter = iter.right(); - } - } - //Only reached if nothing was found. - SerializeableMatcherIF* newContent = factory.generate< - INSERTION_T>(idFrom, idTo, inverted); - if (newContent == NULL) { - return FULL; - } - Node* newNode = factory.generate(newContent); - if (newNode == NULL) { - //Need to make sure partially generated content is deleted, otherwise, that's a leak. - factory.destroy(static_cast(newContent)); - return FULL; - } - *lastTest = insert(attachToBranch, *lastTest, newNode); - if (*lastTest == end()) { - //This actaully never fails, so creating a dedicated returncode seems an overshoot. - return RETURN_FAILED; - } - return RETURN_OK; -} - -template -EventMatchTree::iterator EventMatchTree::findRangeMatcher(iterator start, - VALUE_T idFrom, VALUE_T idTo, bool inverted) { - iterator iter = start; - while (iter != end()) { - INSERTION_T* matcher = static_cast(*iter); - if ((matcher->rangeMatcher.lowerBound == idFrom) - && (matcher->rangeMatcher.upperBound == idTo) - && (matcher->rangeMatcher.inverted == inverted)) { - break; - } else { - iter = iter.right(); //next OR element - } - } - return iter; -} - -ReturnValue_t EventMatchTree::cleanUpElement(iterator position) { - factory.destroy(position.element->value); - //If deletion fails, delete element anyway, nothing we can do. - //SHOULDO: Throw event, or write debug output. - return factory.destroy(position.element); -} +#include "../../events/eventmatching/EventIdRangeMatcher.h" +#include "../../events/eventmatching/EventMatchTree.h" +#include "../../events/eventmatching/ReporterRangeMatcher.h" +#include "../../events/eventmatching/SeverityRangeMatcher.h" + +EventMatchTree::EventMatchTree(StorageManagerIF* storageBackend, + bool invertedMatch) : + MatchTree(end(), 1), factory(storageBackend), invertedMatch( + invertedMatch) { +} + +EventMatchTree::~EventMatchTree() { +} + +bool EventMatchTree::match(EventMessage* number) { + if (invertedMatch) { + return !MatchTree::match(number); + } else { + return MatchTree::match(number); + } +} + +ReturnValue_t EventMatchTree::addMatch(EventId_t idFrom, EventId_t idTo, + bool idInverted, object_id_t reporterFrom, object_id_t reporterTo, + bool reporterInverted) { + if (idFrom == 0) { + //Assuming all events shall be forwarded. + idTo = 0; + idInverted = true; + } + if (idTo == 0) { + idTo = idFrom; + } + iterator lastTest; + ReturnValue_t result = findOrInsertRangeMatcher(begin(), idFrom, idTo, idInverted, &lastTest); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if (reporterFrom == 0) { + //No need to add another AND branch + return RETURN_OK; + } + if (reporterTo == 0) { + reporterTo = reporterFrom; + } + return findOrInsertRangeMatcher( + lastTest.left(), reporterFrom, reporterTo, reporterInverted, + &lastTest); +} + +ReturnValue_t EventMatchTree::removeMatch(EventId_t idFrom, EventId_t idTo, + bool idInverted, object_id_t reporterFrom, object_id_t reporterTo, + bool reporterInverted) { + + iterator foundElement; + + if (idFrom == 0) { + //Assuming a "forward all events" request. + idTo = 0; + idInverted = true; + } + if (idTo == 0) { + idTo = idFrom; + } + foundElement = findRangeMatcher(begin(), + idFrom, idTo, idInverted); + if (foundElement == end()) { + return NO_MATCH; //Can't tell if too detailed or just not found. + } + if (reporterFrom == 0) { + if (foundElement.left() == end()) { + return removeElementAndReconnectChildren(foundElement); + } else { + return TOO_GENERAL_REQUEST; + } + } + if (reporterTo == 0) { + reporterTo = reporterFrom; + } + foundElement = findRangeMatcher( + foundElement.left(), reporterFrom, reporterTo, reporterInverted); + if (foundElement == end()) { + return NO_MATCH; + } else { + return removeElementAndReconnectChildren(foundElement); + } +} + +template +inline ReturnValue_t EventMatchTree::findOrInsertRangeMatcher(iterator start, + VALUE_T idFrom, VALUE_T idTo, bool inverted, iterator* lastTest) { + bool attachToBranch = AND; + iterator iter = start; + while (iter != end()) { + INSERTION_T* matcher = static_cast(*iter); + attachToBranch = OR; + *lastTest = iter; + if ((matcher->rangeMatcher.lowerBound == idFrom) + && (matcher->rangeMatcher.upperBound == idTo) + && (matcher->rangeMatcher.inverted == inverted)) { + return RETURN_OK; + } else { + iter = iter.right(); + } + } + //Only reached if nothing was found. + SerializeableMatcherIF* newContent = factory.generate< + INSERTION_T>(idFrom, idTo, inverted); + if (newContent == NULL) { + return FULL; + } + Node* newNode = factory.generate(newContent); + if (newNode == NULL) { + //Need to make sure partially generated content is deleted, otherwise, that's a leak. + factory.destroy(static_cast(newContent)); + return FULL; + } + *lastTest = insert(attachToBranch, *lastTest, newNode); + if (*lastTest == end()) { + //This actaully never fails, so creating a dedicated returncode seems an overshoot. + return RETURN_FAILED; + } + return RETURN_OK; +} + +template +EventMatchTree::iterator EventMatchTree::findRangeMatcher(iterator start, + VALUE_T idFrom, VALUE_T idTo, bool inverted) { + iterator iter = start; + while (iter != end()) { + INSERTION_T* matcher = static_cast(*iter); + if ((matcher->rangeMatcher.lowerBound == idFrom) + && (matcher->rangeMatcher.upperBound == idTo) + && (matcher->rangeMatcher.inverted == inverted)) { + break; + } else { + iter = iter.right(); //next OR element + } + } + return iter; +} + +ReturnValue_t EventMatchTree::cleanUpElement(iterator position) { + factory.destroy(position.element->value); + //If deletion fails, delete element anyway, nothing we can do. + //SHOULDO: Throw event, or write debug output. + return factory.destroy(position.element); +} diff --git a/events/eventmatching/EventMatchTree.h b/events/eventmatching/EventMatchTree.h index bd81e3be..ba02217a 100644 --- a/events/eventmatching/EventMatchTree.h +++ b/events/eventmatching/EventMatchTree.h @@ -1,36 +1,36 @@ -#ifndef FRAMEWORK_EVENTS_EVENTMATCHING_EVENTMATCHTREE_H_ -#define FRAMEWORK_EVENTS_EVENTMATCHING_EVENTMATCHTREE_H_ - -#include -#include -#include -#include -class StorageManagerIF; - -class EventMatchTree: public MatchTree, public HasReturnvaluesIF { -public: - EventMatchTree(StorageManagerIF* storageBackend, bool invertedMatch); - virtual ~EventMatchTree(); - ReturnValue_t addMatch(EventId_t idFrom = 0, EventId_t idTo = 0, bool idInverted = false, - object_id_t reporterFrom = 0, object_id_t reporterTo = 0, - bool reporterInverted = false); - ReturnValue_t removeMatch(EventId_t idFrom = 0, EventId_t idTo = 0, bool idInverted = false, - object_id_t reporterFrom = 0, object_id_t reporterTo = 0, - bool reporterInverted = false); - bool match(EventMessage* number); -protected: - ReturnValue_t cleanUpElement(iterator position); -private: - PlacementFactory factory; - bool invertedMatch; - template - ReturnValue_t findOrInsertRangeMatcher(iterator start, VALUE_T idFrom, - VALUE_T idTo, bool inverted, iterator* lastTest); - - template - iterator findRangeMatcher(iterator start, VALUE_T idFrom, VALUE_T idTo, - bool inverted); - -}; - -#endif /* FRAMEWORK_EVENTS_EVENTMATCHING_EVENTMATCHTREE_H_ */ +#ifndef FRAMEWORK_EVENTS_EVENTMATCHING_EVENTMATCHTREE_H_ +#define FRAMEWORK_EVENTS_EVENTMATCHING_EVENTMATCHTREE_H_ + +#include "../../container/PlacementFactory.h" +#include "../../events/EventMessage.h" +#include "../../globalfunctions/matching/MatchTree.h" +#include "../../returnvalues/HasReturnvaluesIF.h" +class StorageManagerIF; + +class EventMatchTree: public MatchTree, public HasReturnvaluesIF { +public: + EventMatchTree(StorageManagerIF* storageBackend, bool invertedMatch); + virtual ~EventMatchTree(); + ReturnValue_t addMatch(EventId_t idFrom = 0, EventId_t idTo = 0, bool idInverted = false, + object_id_t reporterFrom = 0, object_id_t reporterTo = 0, + bool reporterInverted = false); + ReturnValue_t removeMatch(EventId_t idFrom = 0, EventId_t idTo = 0, bool idInverted = false, + object_id_t reporterFrom = 0, object_id_t reporterTo = 0, + bool reporterInverted = false); + bool match(EventMessage* number); +protected: + ReturnValue_t cleanUpElement(iterator position); +private: + PlacementFactory factory; + bool invertedMatch; + template + ReturnValue_t findOrInsertRangeMatcher(iterator start, VALUE_T idFrom, + VALUE_T idTo, bool inverted, iterator* lastTest); + + template + iterator findRangeMatcher(iterator start, VALUE_T idFrom, VALUE_T idTo, + bool inverted); + +}; + +#endif /* FRAMEWORK_EVENTS_EVENTMATCHING_EVENTMATCHTREE_H_ */ diff --git a/events/eventmatching/EventRangeMatcherBase.h b/events/eventmatching/EventRangeMatcherBase.h index 587669ba..ab42800a 100644 --- a/events/eventmatching/EventRangeMatcherBase.h +++ b/events/eventmatching/EventRangeMatcherBase.h @@ -1,29 +1,29 @@ -#ifndef FRAMEWORK_EVENTS_EVENTMATCHING_EVENTRANGEMATCHERBASE_H_ -#define FRAMEWORK_EVENTS_EVENTMATCHING_EVENTRANGEMATCHERBASE_H_ - -#include -#include -#include - -template -class EventRangeMatcherBase: public SerializeableMatcherIF { - friend class EventMatchTree; -public: - EventRangeMatcherBase(T from, T till, bool inverted) : rangeMatcher(from, till, inverted) { } - virtual ~EventRangeMatcherBase() { } - ReturnValue_t serialize(uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) const { - return rangeMatcher.serialize(buffer, size, maxSize, streamEndianness); - } - size_t getSerializedSize() const { - return rangeMatcher.getSerializedSize(); - } - ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - Endianness streamEndianness) { - return rangeMatcher.deSerialize(buffer, size, streamEndianness); - } -protected: - RangeMatcher rangeMatcher; -}; - -#endif /* FRAMEWORK_EVENTS_EVENTMATCHING_EVENTRANGEMATCHERBASE_H_ */ +#ifndef FRAMEWORK_EVENTS_EVENTMATCHING_EVENTRANGEMATCHERBASE_H_ +#define FRAMEWORK_EVENTS_EVENTMATCHING_EVENTRANGEMATCHERBASE_H_ + +#include "../../events/EventMessage.h" +#include "../../globalfunctions/matching/RangeMatcher.h" +#include "../../globalfunctions/matching/SerializeableMatcherIF.h" + +template +class EventRangeMatcherBase: public SerializeableMatcherIF { + friend class EventMatchTree; +public: + EventRangeMatcherBase(T from, T till, bool inverted) : rangeMatcher(from, till, inverted) { } + virtual ~EventRangeMatcherBase() { } + ReturnValue_t serialize(uint8_t** buffer, size_t* size, + size_t maxSize, Endianness streamEndianness) const { + return rangeMatcher.serialize(buffer, size, maxSize, streamEndianness); + } + size_t getSerializedSize() const { + return rangeMatcher.getSerializedSize(); + } + ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + Endianness streamEndianness) { + return rangeMatcher.deSerialize(buffer, size, streamEndianness); + } +protected: + RangeMatcher rangeMatcher; +}; + +#endif /* FRAMEWORK_EVENTS_EVENTMATCHING_EVENTRANGEMATCHERBASE_H_ */ diff --git a/events/eventmatching/ReporterRangeMatcher.cpp b/events/eventmatching/ReporterRangeMatcher.cpp index 76b8e788..6751b5e0 100644 --- a/events/eventmatching/ReporterRangeMatcher.cpp +++ b/events/eventmatching/ReporterRangeMatcher.cpp @@ -1,13 +1,13 @@ -#include - -ReporterRangeMatcher::ReporterRangeMatcher(object_id_t lower, object_id_t upper, - bool inverted) : EventRangeMatcherBase(lower, upper, inverted) { -} - -ReporterRangeMatcher::~ReporterRangeMatcher() { - -} - -bool ReporterRangeMatcher::match(EventMessage* message) { - return rangeMatcher.match(message->getReporter()); -} +#include "../../events/eventmatching/ReporterRangeMatcher.h" + +ReporterRangeMatcher::ReporterRangeMatcher(object_id_t lower, object_id_t upper, + bool inverted) : EventRangeMatcherBase(lower, upper, inverted) { +} + +ReporterRangeMatcher::~ReporterRangeMatcher() { + +} + +bool ReporterRangeMatcher::match(EventMessage* message) { + return rangeMatcher.match(message->getReporter()); +} diff --git a/events/eventmatching/ReporterRangeMatcher.h b/events/eventmatching/ReporterRangeMatcher.h index 65be2365..ee23d076 100644 --- a/events/eventmatching/ReporterRangeMatcher.h +++ b/events/eventmatching/ReporterRangeMatcher.h @@ -1,13 +1,13 @@ -#ifndef FRAMEWORK_EVENTS_EVENTMATCHING_REPORTERRANGEMATCHER_H_ -#define FRAMEWORK_EVENTS_EVENTMATCHING_REPORTERRANGEMATCHER_H_ - -#include - -class ReporterRangeMatcher: public EventRangeMatcherBase { -public: - ReporterRangeMatcher(object_id_t lower, object_id_t upper, bool inverted); - ~ReporterRangeMatcher(); - bool match(EventMessage* message); -}; - -#endif /* FRAMEWORK_EVENTS_EVENTMATCHING_REPORTERRANGEMATCHER_H_ */ +#ifndef FRAMEWORK_EVENTS_EVENTMATCHING_REPORTERRANGEMATCHER_H_ +#define FRAMEWORK_EVENTS_EVENTMATCHING_REPORTERRANGEMATCHER_H_ + +#include "../../events/eventmatching/EventRangeMatcherBase.h" + +class ReporterRangeMatcher: public EventRangeMatcherBase { +public: + ReporterRangeMatcher(object_id_t lower, object_id_t upper, bool inverted); + ~ReporterRangeMatcher(); + bool match(EventMessage* message); +}; + +#endif /* FRAMEWORK_EVENTS_EVENTMATCHING_REPORTERRANGEMATCHER_H_ */ diff --git a/events/eventmatching/SeverityRangeMatcher.cpp b/events/eventmatching/SeverityRangeMatcher.cpp index 98f8d7e1..41eb9020 100644 --- a/events/eventmatching/SeverityRangeMatcher.cpp +++ b/events/eventmatching/SeverityRangeMatcher.cpp @@ -1,14 +1,14 @@ -#include -#include -#include - -SeverityRangeMatcher::SeverityRangeMatcher(EventSeverity_t from, - EventSeverity_t till, bool inverted) : EventRangeMatcherBase(from, till, inverted) { -} - -SeverityRangeMatcher::~SeverityRangeMatcher() { -} - -bool SeverityRangeMatcher::match(EventMessage* message) { - return rangeMatcher.match(message->getSeverity()); -} +#include "../../events/eventmatching/SeverityRangeMatcher.h" +#include "../../events/EventMessage.h" +#include "../../serialize/SerializeAdapter.h" + +SeverityRangeMatcher::SeverityRangeMatcher(EventSeverity_t from, + EventSeverity_t till, bool inverted) : EventRangeMatcherBase(from, till, inverted) { +} + +SeverityRangeMatcher::~SeverityRangeMatcher() { +} + +bool SeverityRangeMatcher::match(EventMessage* message) { + return rangeMatcher.match(message->getSeverity()); +} diff --git a/events/eventmatching/SeverityRangeMatcher.h b/events/eventmatching/SeverityRangeMatcher.h index ffacff81..b3c3fbc8 100644 --- a/events/eventmatching/SeverityRangeMatcher.h +++ b/events/eventmatching/SeverityRangeMatcher.h @@ -1,13 +1,13 @@ -#ifndef FRAMEWORK_EVENTS_EVENTMATCHING_SEVERITYRANGEMATCHER_H_ -#define FRAMEWORK_EVENTS_EVENTMATCHING_SEVERITYRANGEMATCHER_H_ - -#include - -class SeverityRangeMatcher: public EventRangeMatcherBase { -public: - SeverityRangeMatcher(EventSeverity_t from, EventSeverity_t till, bool inverted); - ~SeverityRangeMatcher(); - bool match(EventMessage* message); -}; - -#endif /* FRAMEWORK_EVENTS_EVENTMATCHING_SEVERITYRANGEMATCHER_H_ */ +#ifndef FRAMEWORK_EVENTS_EVENTMATCHING_SEVERITYRANGEMATCHER_H_ +#define FRAMEWORK_EVENTS_EVENTMATCHING_SEVERITYRANGEMATCHER_H_ + +#include "../../events/eventmatching/EventRangeMatcherBase.h" + +class SeverityRangeMatcher: public EventRangeMatcherBase { +public: + SeverityRangeMatcher(EventSeverity_t from, EventSeverity_t till, bool inverted); + ~SeverityRangeMatcher(); + bool match(EventMessage* message); +}; + +#endif /* FRAMEWORK_EVENTS_EVENTMATCHING_SEVERITYRANGEMATCHER_H_ */ diff --git a/events/eventmatching/eventmatching.h b/events/eventmatching/eventmatching.h index 435c7457..85b852a5 100644 --- a/events/eventmatching/eventmatching.h +++ b/events/eventmatching/eventmatching.h @@ -1,10 +1,10 @@ -#ifndef EVENTMATCHING_H_ -#define EVENTMATCHING_H_ - -#include -#include -#include -#include - - -#endif /* EVENTMATCHING_H_ */ +#ifndef EVENTMATCHING_H_ +#define EVENTMATCHING_H_ + +#include "../../events/eventmatching/EventIdRangeMatcher.h" +#include "../../events/eventmatching/EventMatchTree.h" +#include "../../events/eventmatching/ReporterRangeMatcher.h" +#include "../../events/eventmatching/SeverityRangeMatcher.h" + + +#endif /* EVENTMATCHING_H_ */ diff --git a/fdir/ConfirmsFailuresIF.h b/fdir/ConfirmsFailuresIF.h index 460749ee..1896d24a 100644 --- a/fdir/ConfirmsFailuresIF.h +++ b/fdir/ConfirmsFailuresIF.h @@ -1,20 +1,20 @@ -#ifndef FRAMEWORK_FDIR_CONFIRMSFAILURESIF_H_ -#define FRAMEWORK_FDIR_CONFIRMSFAILURESIF_H_ - -#include -#include - -// TODO: Documentation. -class ConfirmsFailuresIF { -public: - static const uint8_t INTERFACE_ID = CLASS_ID::HANDLES_FAILURES_IF; - static const ReturnValue_t YOUR_FAULT = MAKE_RETURN_CODE(0); - static const ReturnValue_t MY_FAULT = MAKE_RETURN_CODE(1); - static const ReturnValue_t CONFIRM_LATER = MAKE_RETURN_CODE(2); - virtual ~ConfirmsFailuresIF() {} - virtual MessageQueueId_t getEventReceptionQueue() = 0; -}; - - - -#endif /* FRAMEWORK_FDIR_CONFIRMSFAILURESIF_H_ */ +#ifndef FRAMEWORK_FDIR_CONFIRMSFAILURESIF_H_ +#define FRAMEWORK_FDIR_CONFIRMSFAILURESIF_H_ + +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../ipc/MessageQueueSenderIF.h" + +// TODO: Documentation. +class ConfirmsFailuresIF { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::HANDLES_FAILURES_IF; + static const ReturnValue_t YOUR_FAULT = MAKE_RETURN_CODE(0); + static const ReturnValue_t MY_FAULT = MAKE_RETURN_CODE(1); + static const ReturnValue_t CONFIRM_LATER = MAKE_RETURN_CODE(2); + virtual ~ConfirmsFailuresIF() {} + virtual MessageQueueId_t getEventReceptionQueue() = 0; +}; + + + +#endif /* FRAMEWORK_FDIR_CONFIRMSFAILURESIF_H_ */ diff --git a/fdir/EventCorrelation.cpp b/fdir/EventCorrelation.cpp index 32aa3cd3..dea6a569 100644 --- a/fdir/EventCorrelation.cpp +++ b/fdir/EventCorrelation.cpp @@ -1,44 +1,44 @@ -#include - -EventCorrelation::EventCorrelation(uint32_t timeout) : - eventPending(false) { - correlationTimer.setTimeout(timeout); -} - -EventCorrelation::~EventCorrelation() { -} - -EventCorrelation::State EventCorrelation::doesEventCorrelate() { - if (correlationTimer.isBusy()) { - eventPending = false; - return CORRELATED; - } else { - if (eventPending) { - return ALREADY_STARTED; - } else { - eventPending = true; - correlationTimer.resetTimer(); - return CORRELATION_STARTED; - } - } -} - -bool EventCorrelation::isEventPending() { - if (eventPending) { - eventPending = false; - return true; - } else { - correlationTimer.resetTimer(); - return false; - } -} - -bool EventCorrelation::hasPendingEventTimedOut() { - if (correlationTimer.hasTimedOut()) { - bool temp = eventPending; - eventPending = false; - return temp; - } else { - return false; - } -} +#include "../fdir/EventCorrelation.h" + +EventCorrelation::EventCorrelation(uint32_t timeout) : + eventPending(false) { + correlationTimer.setTimeout(timeout); +} + +EventCorrelation::~EventCorrelation() { +} + +EventCorrelation::State EventCorrelation::doesEventCorrelate() { + if (correlationTimer.isBusy()) { + eventPending = false; + return CORRELATED; + } else { + if (eventPending) { + return ALREADY_STARTED; + } else { + eventPending = true; + correlationTimer.resetTimer(); + return CORRELATION_STARTED; + } + } +} + +bool EventCorrelation::isEventPending() { + if (eventPending) { + eventPending = false; + return true; + } else { + correlationTimer.resetTimer(); + return false; + } +} + +bool EventCorrelation::hasPendingEventTimedOut() { + if (correlationTimer.hasTimedOut()) { + bool temp = eventPending; + eventPending = false; + return temp; + } else { + return false; + } +} diff --git a/fdir/EventCorrelation.h b/fdir/EventCorrelation.h index 0cad6265..bbfe92c1 100644 --- a/fdir/EventCorrelation.h +++ b/fdir/EventCorrelation.h @@ -1,23 +1,23 @@ -#ifndef FRAMEWORK_FDIR_EVENTCORRELATION_H_ -#define FRAMEWORK_FDIR_EVENTCORRELATION_H_ - -#include - -class EventCorrelation { -public: - enum State { - CORRELATION_STARTED, - CORRELATED, - ALREADY_STARTED - }; - EventCorrelation(uint32_t timeout); - ~EventCorrelation(); - EventCorrelation::State doesEventCorrelate(); - bool isEventPending(); - bool hasPendingEventTimedOut(); - Countdown correlationTimer; -private: - bool eventPending; -}; - -#endif /* FRAMEWORK_FDIR_EVENTCORRELATION_H_ */ +#ifndef FRAMEWORK_FDIR_EVENTCORRELATION_H_ +#define FRAMEWORK_FDIR_EVENTCORRELATION_H_ + +#include "../timemanager/Countdown.h" + +class EventCorrelation { +public: + enum State { + CORRELATION_STARTED, + CORRELATED, + ALREADY_STARTED + }; + EventCorrelation(uint32_t timeout); + ~EventCorrelation(); + EventCorrelation::State doesEventCorrelate(); + bool isEventPending(); + bool hasPendingEventTimedOut(); + Countdown correlationTimer; +private: + bool eventPending; +}; + +#endif /* FRAMEWORK_FDIR_EVENTCORRELATION_H_ */ diff --git a/fdir/FailureIsolationBase.cpp b/fdir/FailureIsolationBase.cpp index ad4493ff..b9994dc3 100644 --- a/fdir/FailureIsolationBase.cpp +++ b/fdir/FailureIsolationBase.cpp @@ -1,164 +1,164 @@ -#include -#include -#include -#include -#include -#include - -FailureIsolationBase::FailureIsolationBase(object_id_t owner, - object_id_t parent, uint8_t messageDepth, uint8_t parameterDomainBase) : - ownerId(owner), faultTreeParent(parent), - parameterDomainBase(parameterDomainBase) { - eventQueue = QueueFactory::instance()->createMessageQueue(messageDepth, - EventMessage::EVENT_MESSAGE_SIZE); -} - -FailureIsolationBase::~FailureIsolationBase() { - QueueFactory::instance()->deleteMessageQueue(eventQueue); -} - -ReturnValue_t FailureIsolationBase::initialize() { - EventManagerIF* manager = objectManager->get( - objects::EVENT_MANAGER); - if (manager == nullptr) { - sif::error << "FailureIsolationBase::initialize: Event Manager has not" - " been initialized!" << std::endl; - return RETURN_FAILED; - } - ReturnValue_t result = manager->registerListener(eventQueue->getId()); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - if (ownerId != objects::NO_OBJECT) { - result = manager->subscribeToAllEventsFrom(eventQueue->getId(), ownerId); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - owner = objectManager->get(ownerId); - if (owner == nullptr) { - sif::error << "FailureIsolationBase::intialize: Owner object " - "invalid. Make sure it implements HasHealthIF" << std::endl; - return ObjectManagerIF::CHILD_INIT_FAILED; - } - } - if (faultTreeParent != objects::NO_OBJECT) { - ConfirmsFailuresIF* parentIF = objectManager->get( - faultTreeParent); - if (parentIF == nullptr) { - sif::error << "FailureIsolationBase::intialize: Parent object" - << "invalid." << std::endl; - sif::error << "Make sure it implements ConfirmsFailuresIF." - << std::endl; - return ObjectManagerIF::CHILD_INIT_FAILED; - return RETURN_FAILED; - } - eventQueue->setDefaultDestination(parentIF->getEventReceptionQueue()); - } - return RETURN_OK; -} - -void FailureIsolationBase::checkForFailures() { - EventMessage event; - for (ReturnValue_t result = eventQueue->receiveMessage(&event); - result == RETURN_OK; result = eventQueue->receiveMessage(&event)) { - if (event.getSender() == eventQueue->getId()) { - //We already got this event, because we sent it. - continue; - } - switch (event.getMessageId()) { - case EventMessage::EVENT_MESSAGE: - if (isFdirDisabledForSeverity(event.getSeverity())) { - //We do not handle events when disabled. - continue; - } - eventReceived(&event); - break; - case EventMessage::CONFIRMATION_REQUEST: - doConfirmFault(&event); - break; - case EventMessage::YOUR_FAULT: - eventConfirmed(&event); - break; - case EventMessage::MY_FAULT: - wasParentsFault(&event); - break; - default: - break; - } - } - decrementFaultCounters(); -} - -void FailureIsolationBase::setOwnerHealth(HasHealthIF::HealthState health) { - if (owner != NULL) { - owner->setHealth(health); - } - //else: owner has no health. - -} - -MessageQueueId_t FailureIsolationBase::getEventReceptionQueue() { - return eventQueue->getId(); -} - -ReturnValue_t FailureIsolationBase::sendConfirmationRequest(EventMessage* event, - MessageQueueId_t destination) { - event->setMessageId(EventMessage::CONFIRMATION_REQUEST); - if (destination != MessageQueueIF::NO_QUEUE) { - return eventQueue->sendMessage(destination, event); - } else if (faultTreeParent != objects::NO_OBJECT) { - return eventQueue->sendToDefault(event); - } - return RETURN_FAILED; -} - -void FailureIsolationBase::eventConfirmed(EventMessage* event) { -} - -void FailureIsolationBase::wasParentsFault(EventMessage* event) { -} - -void FailureIsolationBase::doConfirmFault(EventMessage* event) { - ReturnValue_t result = confirmFault(event); - if (result == YOUR_FAULT) { - event->setMessageId(EventMessage::YOUR_FAULT); - eventQueue->reply(event); - } else if (result == MY_FAULT) { - event->setMessageId(EventMessage::MY_FAULT); - eventQueue->reply(event); - } else { - - } -} - -ReturnValue_t FailureIsolationBase::confirmFault(EventMessage* event) { - return YOUR_FAULT; -} - -void FailureIsolationBase::triggerEvent(Event event, uint32_t parameter1, - uint32_t parameter2) { - //With this mechanism, all events are disabled for a certain device. - //That's not so good for visibility. - if (isFdirDisabledForSeverity(EVENT::getSeverity(event))) { - return; - } - EventMessage message(event, ownerId, parameter1, parameter2); - EventManagerIF::triggerEvent(&message, eventQueue->getId()); - eventReceived(&message); -} - -bool FailureIsolationBase::isFdirDisabledForSeverity(EventSeverity_t severity) { - if ((owner != NULL) && (severity != SEVERITY::INFO)) { - if (owner->getHealth() == HasHealthIF::EXTERNAL_CONTROL) { - //External control disables handling of fault messages. - return true; - } - } - return false; -} - -void FailureIsolationBase::throwFdirEvent(Event event, uint32_t parameter1, - uint32_t parameter2) { - EventMessage message(event, ownerId, parameter1, parameter2); - EventManagerIF::triggerEvent(&message, eventQueue->getId()); -} +#include "../events/EventManagerIF.h" +#include "../fdir/FailureIsolationBase.h" +#include "../health/HasHealthIF.h" +#include "../health/HealthMessage.h" +#include "../ipc/QueueFactory.h" +#include "../objectmanager/ObjectManagerIF.h" + +FailureIsolationBase::FailureIsolationBase(object_id_t owner, + object_id_t parent, uint8_t messageDepth, uint8_t parameterDomainBase) : + ownerId(owner), faultTreeParent(parent), + parameterDomainBase(parameterDomainBase) { + eventQueue = QueueFactory::instance()->createMessageQueue(messageDepth, + EventMessage::EVENT_MESSAGE_SIZE); +} + +FailureIsolationBase::~FailureIsolationBase() { + QueueFactory::instance()->deleteMessageQueue(eventQueue); +} + +ReturnValue_t FailureIsolationBase::initialize() { + EventManagerIF* manager = objectManager->get( + objects::EVENT_MANAGER); + if (manager == nullptr) { + sif::error << "FailureIsolationBase::initialize: Event Manager has not" + " been initialized!" << std::endl; + return RETURN_FAILED; + } + ReturnValue_t result = manager->registerListener(eventQueue->getId()); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if (ownerId != objects::NO_OBJECT) { + result = manager->subscribeToAllEventsFrom(eventQueue->getId(), ownerId); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + owner = objectManager->get(ownerId); + if (owner == nullptr) { + sif::error << "FailureIsolationBase::intialize: Owner object " + "invalid. Make sure it implements HasHealthIF" << std::endl; + return ObjectManagerIF::CHILD_INIT_FAILED; + } + } + if (faultTreeParent != objects::NO_OBJECT) { + ConfirmsFailuresIF* parentIF = objectManager->get( + faultTreeParent); + if (parentIF == nullptr) { + sif::error << "FailureIsolationBase::intialize: Parent object" + << "invalid." << std::endl; + sif::error << "Make sure it implements ConfirmsFailuresIF." + << std::endl; + return ObjectManagerIF::CHILD_INIT_FAILED; + return RETURN_FAILED; + } + eventQueue->setDefaultDestination(parentIF->getEventReceptionQueue()); + } + return RETURN_OK; +} + +void FailureIsolationBase::checkForFailures() { + EventMessage event; + for (ReturnValue_t result = eventQueue->receiveMessage(&event); + result == RETURN_OK; result = eventQueue->receiveMessage(&event)) { + if (event.getSender() == eventQueue->getId()) { + //We already got this event, because we sent it. + continue; + } + switch (event.getMessageId()) { + case EventMessage::EVENT_MESSAGE: + if (isFdirDisabledForSeverity(event.getSeverity())) { + //We do not handle events when disabled. + continue; + } + eventReceived(&event); + break; + case EventMessage::CONFIRMATION_REQUEST: + doConfirmFault(&event); + break; + case EventMessage::YOUR_FAULT: + eventConfirmed(&event); + break; + case EventMessage::MY_FAULT: + wasParentsFault(&event); + break; + default: + break; + } + } + decrementFaultCounters(); +} + +void FailureIsolationBase::setOwnerHealth(HasHealthIF::HealthState health) { + if (owner != NULL) { + owner->setHealth(health); + } + //else: owner has no health. + +} + +MessageQueueId_t FailureIsolationBase::getEventReceptionQueue() { + return eventQueue->getId(); +} + +ReturnValue_t FailureIsolationBase::sendConfirmationRequest(EventMessage* event, + MessageQueueId_t destination) { + event->setMessageId(EventMessage::CONFIRMATION_REQUEST); + if (destination != MessageQueueIF::NO_QUEUE) { + return eventQueue->sendMessage(destination, event); + } else if (faultTreeParent != objects::NO_OBJECT) { + return eventQueue->sendToDefault(event); + } + return RETURN_FAILED; +} + +void FailureIsolationBase::eventConfirmed(EventMessage* event) { +} + +void FailureIsolationBase::wasParentsFault(EventMessage* event) { +} + +void FailureIsolationBase::doConfirmFault(EventMessage* event) { + ReturnValue_t result = confirmFault(event); + if (result == YOUR_FAULT) { + event->setMessageId(EventMessage::YOUR_FAULT); + eventQueue->reply(event); + } else if (result == MY_FAULT) { + event->setMessageId(EventMessage::MY_FAULT); + eventQueue->reply(event); + } else { + + } +} + +ReturnValue_t FailureIsolationBase::confirmFault(EventMessage* event) { + return YOUR_FAULT; +} + +void FailureIsolationBase::triggerEvent(Event event, uint32_t parameter1, + uint32_t parameter2) { + //With this mechanism, all events are disabled for a certain device. + //That's not so good for visibility. + if (isFdirDisabledForSeverity(EVENT::getSeverity(event))) { + return; + } + EventMessage message(event, ownerId, parameter1, parameter2); + EventManagerIF::triggerEvent(&message, eventQueue->getId()); + eventReceived(&message); +} + +bool FailureIsolationBase::isFdirDisabledForSeverity(EventSeverity_t severity) { + if ((owner != NULL) && (severity != SEVERITY::INFO)) { + if (owner->getHealth() == HasHealthIF::EXTERNAL_CONTROL) { + //External control disables handling of fault messages. + return true; + } + } + return false; +} + +void FailureIsolationBase::throwFdirEvent(Event event, uint32_t parameter1, + uint32_t parameter2) { + EventMessage message(event, ownerId, parameter1, parameter2); + EventManagerIF::triggerEvent(&message, eventQueue->getId()); +} diff --git a/fdir/FailureIsolationBase.h b/fdir/FailureIsolationBase.h index c0fe6041..b2735e6d 100644 --- a/fdir/FailureIsolationBase.h +++ b/fdir/FailureIsolationBase.h @@ -1,56 +1,56 @@ -#ifndef FRAMEWORK_FDIR_FAILUREISOLATIONBASE_H_ -#define FRAMEWORK_FDIR_FAILUREISOLATIONBASE_H_ - -#include -#include -#include -#include -#include -#include -#include - -class FailureIsolationBase: public HasReturnvaluesIF, - public ConfirmsFailuresIF, - public HasParametersIF { -public: - static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::FDIR_1; - static const Event FDIR_CHANGED_STATE = MAKE_EVENT(1, SEVERITY::INFO); //!< FDIR has an internal state, which changed from par2 (oldState) to par1 (newState). - static const Event FDIR_STARTS_RECOVERY = MAKE_EVENT(2, SEVERITY::MEDIUM); //!< FDIR tries to restart device. Par1: event that caused recovery. - static const Event FDIR_TURNS_OFF_DEVICE = MAKE_EVENT(3, SEVERITY::MEDIUM); //!< FDIR turns off device. Par1: event that caused recovery. - - FailureIsolationBase(object_id_t owner, - object_id_t parent = objects::NO_OBJECT, - uint8_t messageDepth = 10, uint8_t parameterDomainBase = 0xF0); - - virtual ~FailureIsolationBase(); - virtual ReturnValue_t initialize(); - - /** - * This is called by the DHB in performOperation() - */ - void checkForFailures(); - MessageQueueId_t getEventReceptionQueue() override; - virtual void triggerEvent(Event event, uint32_t parameter1 = 0, - uint32_t parameter2 = 0); -protected: - MessageQueueIF* eventQueue = nullptr; - object_id_t ownerId; - HasHealthIF* owner = nullptr; - object_id_t faultTreeParent; - uint8_t parameterDomainBase; - void setOwnerHealth(HasHealthIF::HealthState health); - virtual ReturnValue_t eventReceived(EventMessage* event) = 0; - virtual void eventConfirmed(EventMessage* event); - virtual void wasParentsFault(EventMessage* event); - virtual ReturnValue_t confirmFault(EventMessage* event); - virtual void decrementFaultCounters() = 0; - ReturnValue_t sendConfirmationRequest(EventMessage* event, - MessageQueueId_t destination = MessageQueueIF::NO_QUEUE); - void throwFdirEvent(Event event, uint32_t parameter1 = 0, - uint32_t parameter2 = 0); -private: - void doConfirmFault(EventMessage* event);bool isFdirDisabledForSeverity( - EventSeverity_t severity); -}; - -#endif /* FRAMEWORK_FDIR_FAILUREISOLATIONBASE_H_ */ +#ifndef FRAMEWORK_FDIR_FAILUREISOLATIONBASE_H_ +#define FRAMEWORK_FDIR_FAILUREISOLATIONBASE_H_ + +#include "../events/EventMessage.h" +#include "../fdir/ConfirmsFailuresIF.h" +#include "../fdir/FaultCounter.h" +#include "../health/HealthMessage.h" +#include "../parameters/HasParametersIF.h" +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../ipc/MessageQueueIF.h" + +class FailureIsolationBase: public HasReturnvaluesIF, + public ConfirmsFailuresIF, + public HasParametersIF { +public: + static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::FDIR_1; + static const Event FDIR_CHANGED_STATE = MAKE_EVENT(1, SEVERITY::INFO); //!< FDIR has an internal state, which changed from par2 (oldState) to par1 (newState). + static const Event FDIR_STARTS_RECOVERY = MAKE_EVENT(2, SEVERITY::MEDIUM); //!< FDIR tries to restart device. Par1: event that caused recovery. + static const Event FDIR_TURNS_OFF_DEVICE = MAKE_EVENT(3, SEVERITY::MEDIUM); //!< FDIR turns off device. Par1: event that caused recovery. + + FailureIsolationBase(object_id_t owner, + object_id_t parent = objects::NO_OBJECT, + uint8_t messageDepth = 10, uint8_t parameterDomainBase = 0xF0); + + virtual ~FailureIsolationBase(); + virtual ReturnValue_t initialize(); + + /** + * This is called by the DHB in performOperation() + */ + void checkForFailures(); + MessageQueueId_t getEventReceptionQueue() override; + virtual void triggerEvent(Event event, uint32_t parameter1 = 0, + uint32_t parameter2 = 0); +protected: + MessageQueueIF* eventQueue = nullptr; + object_id_t ownerId; + HasHealthIF* owner = nullptr; + object_id_t faultTreeParent; + uint8_t parameterDomainBase; + void setOwnerHealth(HasHealthIF::HealthState health); + virtual ReturnValue_t eventReceived(EventMessage* event) = 0; + virtual void eventConfirmed(EventMessage* event); + virtual void wasParentsFault(EventMessage* event); + virtual ReturnValue_t confirmFault(EventMessage* event); + virtual void decrementFaultCounters() = 0; + ReturnValue_t sendConfirmationRequest(EventMessage* event, + MessageQueueId_t destination = MessageQueueIF::NO_QUEUE); + void throwFdirEvent(Event event, uint32_t parameter1 = 0, + uint32_t parameter2 = 0); +private: + void doConfirmFault(EventMessage* event);bool isFdirDisabledForSeverity( + EventSeverity_t severity); +}; + +#endif /* FRAMEWORK_FDIR_FAILUREISOLATIONBASE_H_ */ diff --git a/fdir/FaultCounter.cpp b/fdir/FaultCounter.cpp index 3dc899c2..674d278a 100644 --- a/fdir/FaultCounter.cpp +++ b/fdir/FaultCounter.cpp @@ -1,86 +1,86 @@ -#include - -FaultCounter::FaultCounter(uint32_t failureThreshold, uint32_t decrementAfterMs, - uint8_t setParameterDomain) : - parameterDomain(setParameterDomain), timer(), faultCount(0), failureThreshold( - failureThreshold) { - timer.setTimeout(decrementAfterMs); -} - -FaultCounter::~FaultCounter() { -} - -void FaultCounter::increment(uint32_t amount) { - if (faultCount == 0) { - timer.resetTimer(); - } - faultCount += amount; -} - -bool FaultCounter::checkForDecrement() { - if (timer.hasTimedOut()) { - timer.resetTimer(); - if (faultCount > 0) { - faultCount--; - return true; - } - } - return false; -} - -bool FaultCounter::incrementAndCheck(uint32_t amount) { - increment(amount); - return aboveThreshold(); -} - -bool FaultCounter::aboveThreshold() { - if (faultCount > failureThreshold) { - faultCount = 0; - return true; - } else { - return false; - } -} - -void FaultCounter::clear() { - faultCount = 0; -} - -void FaultCounter::setFailureThreshold(uint32_t failureThreshold) { - this->failureThreshold = failureThreshold; -} - -void FaultCounter::setFaultDecrementTimeMs(uint32_t timeMs) { - timer.setTimeout(timeMs); -} - -FaultCounter::FaultCounter() : - parameterDomain(0), timer(), faultCount(0), failureThreshold(0) { -} - -ReturnValue_t FaultCounter::getParameter(uint8_t domainId, uint16_t parameterId, - ParameterWrapper* parameterWrapper, const ParameterWrapper* newValues, - uint16_t startAtIndex) { - if (domainId != parameterDomain) { - return INVALID_DOMAIN_ID; - } - - switch (parameterId) { - case 0: - parameterWrapper->set(failureThreshold); - break; - case 1: - parameterWrapper->set(faultCount); - break; - case 2: - parameterWrapper->set(timer.timeout); - break; - default: - return INVALID_MATRIX_ID; - } - return HasReturnvaluesIF::RETURN_OK; -} - -void FaultCounter::setParameterDomain(uint8_t domain) { - parameterDomain = domain; -} +#include "../fdir/FaultCounter.h" + +FaultCounter::FaultCounter(uint32_t failureThreshold, uint32_t decrementAfterMs, + uint8_t setParameterDomain) : + parameterDomain(setParameterDomain), timer(), faultCount(0), failureThreshold( + failureThreshold) { + timer.setTimeout(decrementAfterMs); +} + +FaultCounter::~FaultCounter() { +} + +void FaultCounter::increment(uint32_t amount) { + if (faultCount == 0) { + timer.resetTimer(); + } + faultCount += amount; +} + +bool FaultCounter::checkForDecrement() { + if (timer.hasTimedOut()) { + timer.resetTimer(); + if (faultCount > 0) { + faultCount--; + return true; + } + } + return false; +} + +bool FaultCounter::incrementAndCheck(uint32_t amount) { + increment(amount); + return aboveThreshold(); +} + +bool FaultCounter::aboveThreshold() { + if (faultCount > failureThreshold) { + faultCount = 0; + return true; + } else { + return false; + } +} + +void FaultCounter::clear() { + faultCount = 0; +} + +void FaultCounter::setFailureThreshold(uint32_t failureThreshold) { + this->failureThreshold = failureThreshold; +} + +void FaultCounter::setFaultDecrementTimeMs(uint32_t timeMs) { + timer.setTimeout(timeMs); +} + +FaultCounter::FaultCounter() : + parameterDomain(0), timer(), faultCount(0), failureThreshold(0) { +} + +ReturnValue_t FaultCounter::getParameter(uint8_t domainId, uint16_t parameterId, + ParameterWrapper* parameterWrapper, const ParameterWrapper* newValues, + uint16_t startAtIndex) { + if (domainId != parameterDomain) { + return INVALID_DOMAIN_ID; + } + + switch (parameterId) { + case 0: + parameterWrapper->set(failureThreshold); + break; + case 1: + parameterWrapper->set(faultCount); + break; + case 2: + parameterWrapper->set(timer.timeout); + break; + default: + return INVALID_MATRIX_ID; + } + return HasReturnvaluesIF::RETURN_OK; +} + +void FaultCounter::setParameterDomain(uint8_t domain) { + parameterDomain = domain; +} diff --git a/fdir/FaultCounter.h b/fdir/FaultCounter.h index ac23853c..17e2a3df 100644 --- a/fdir/FaultCounter.h +++ b/fdir/FaultCounter.h @@ -1,38 +1,38 @@ -#ifndef FRAMEWORK_FDIR_FAULTCOUNTER_H_ -#define FRAMEWORK_FDIR_FAULTCOUNTER_H_ - -#include -#include - -class FaultCounter: public HasParametersIF { -public: - FaultCounter(); - FaultCounter(uint32_t failureThreshold, uint32_t decrementAfterMs, - uint8_t setParameterDomain = 0); - virtual ~FaultCounter(); - - bool incrementAndCheck(uint32_t amount = 1); - - void increment(uint32_t amount = 1); - - bool checkForDecrement(); - - bool aboveThreshold(); - - void clear(); - void setFailureThreshold(uint32_t failureThreshold); - void setFaultDecrementTimeMs(uint32_t timeMs); - - virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, - ParameterWrapper *parameterWrapper, - const ParameterWrapper *newValues, uint16_t startAtIndex); - - void setParameterDomain(uint8_t domain); -private: - uint8_t parameterDomain; - Countdown timer; - uint32_t faultCount; - uint32_t failureThreshold; -}; - -#endif /* FRAMEWORK_FDIR_FAULTCOUNTER_H_ */ +#ifndef FRAMEWORK_FDIR_FAULTCOUNTER_H_ +#define FRAMEWORK_FDIR_FAULTCOUNTER_H_ + +#include "../parameters/HasParametersIF.h" +#include "../timemanager/Countdown.h" + +class FaultCounter: public HasParametersIF { +public: + FaultCounter(); + FaultCounter(uint32_t failureThreshold, uint32_t decrementAfterMs, + uint8_t setParameterDomain = 0); + virtual ~FaultCounter(); + + bool incrementAndCheck(uint32_t amount = 1); + + void increment(uint32_t amount = 1); + + bool checkForDecrement(); + + bool aboveThreshold(); + + void clear(); + void setFailureThreshold(uint32_t failureThreshold); + void setFaultDecrementTimeMs(uint32_t timeMs); + + virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, + ParameterWrapper *parameterWrapper, + const ParameterWrapper *newValues, uint16_t startAtIndex); + + void setParameterDomain(uint8_t domain); +private: + uint8_t parameterDomain; + Countdown timer; + uint32_t faultCount; + uint32_t failureThreshold; +}; + +#endif /* FRAMEWORK_FDIR_FAULTCOUNTER_H_ */ diff --git a/globalfunctions/AsciiConverter.cpp b/globalfunctions/AsciiConverter.cpp index 1459a241..f54af6a8 100644 --- a/globalfunctions/AsciiConverter.cpp +++ b/globalfunctions/AsciiConverter.cpp @@ -1,230 +1,230 @@ -#include -#include -#include - -template -ReturnValue_t AsciiConverter::scanAsciiDecimalNumber(const uint8_t** dataPtr, - uint8_t len, T* value) { - if (len > std::numeric_limits().digits10) { - return TOO_LONG_FOR_TARGET_TYPE; - } - - double temp; - - ReturnValue_t result = scanAsciiDecimalNumber_(dataPtr, len, &temp); - - *value = temp; - - return result; -} - -ReturnValue_t AsciiConverter::scanAsciiHexByte(const uint8_t** dataPtr, - uint8_t* value) { - int8_t tmp; - - tmp = convertHexChar(*dataPtr); - (*dataPtr)++; - if (tmp == -1) { - return INVALID_CHARACTERS; - } - if (tmp == -2) { - tmp = 0; - } - - *value = tmp << 4; - - tmp = convertHexChar(*dataPtr); - (*dataPtr)++; - if (tmp == -1) { - return INVALID_CHARACTERS; - } - if (tmp != -2) { - *value += tmp; - } else { - *value = *value >> 4; - } - - return RETURN_OK; -} - -ReturnValue_t AsciiConverter::scanAsciiDecimalNumber_(uint8_t const ** dataPtr, - uint8_t len, double* value) { - - uint8_t const *ptr = *dataPtr; - int8_t sign = 1; - float decimal = 0; - bool abort = false; - - *value = 0; - - //ignore leading space - ptr = clearSpace(ptr, len); - - while ((ptr - *dataPtr < len) && !abort) { - switch (*ptr) { - case '+': - sign = 1; - break; - case '-': - sign = -1; - break; - case '.': - decimal = 1; - break; - case ' ': - case 0x0d: - case 0x0a: - //ignore trailing space - ptr = clearSpace(ptr, len - (ptr - *dataPtr)) - 1; //before aborting the loop, ptr will be incremented - abort = true; - break; - default: - if ((*ptr < 0x30) || (*ptr > 0x39)) { - return INVALID_CHARACTERS; - } - *value = *value * 10 + (*ptr - 0x30); - if (decimal > 0) { - decimal *= 10; - } - break; - } - ptr++; - } - - if (decimal == 0) { - decimal = 1; - } - - *value = *value / (decimal) * sign; - - *dataPtr = ptr; - - return RETURN_OK; -} - -ReturnValue_t AsciiConverter::printFloat(uint8_t* buffer, uint32_t bufferLength, - float value, uint8_t decimalPlaces, uint32_t *printedSize) { - *printedSize = 0; - uint32_t streamposition = 0, integerSize; - bool negative = (value < 0); - int32_t digits = bufferLength - decimalPlaces - 1; - if (digits <= 0) { - return BUFFER_TOO_SMALL; - } - if (negative) { - digits -= 1; - buffer[streamposition++] = '-'; - value = -value; - } - float maximumNumber = pow(10, digits); - if (value >= maximumNumber) { - return BUFFER_TOO_SMALL; - } - //print the numbers before the decimal point; - ReturnValue_t result = printInteger(buffer + streamposition, - bufferLength - streamposition - decimalPlaces - 1, value, - &integerSize); - if (result != RETURN_OK) { - return result; - } - streamposition += integerSize; - //The decimal Point - buffer[streamposition++] = '.'; - - //Print the decimals - uint32_t integerValue = value; - value -= integerValue; - value = value * pow(10, decimalPlaces); - result = printInteger(buffer + streamposition, decimalPlaces, round(value), - &integerSize, true); - *printedSize = integerSize + streamposition; - return result; -} - -ReturnValue_t AsciiConverter::printInteger(uint8_t* buffer, - uint32_t bufferLength, uint32_t value, uint32_t *printedSize, - bool leadingZeros) { - *printedSize = 0; - if (bufferLength == 0) { - return BUFFER_TOO_SMALL; - } - uint32_t maximumNumber = -1; - if (bufferLength < 10) { - maximumNumber = pow(10, bufferLength); - if (value >= maximumNumber) { - return BUFFER_TOO_SMALL; - } - maximumNumber /= 10; - } else { - if (!(value <= maximumNumber)) { - return BUFFER_TOO_SMALL; - } - maximumNumber = 1000000000; - } - if (!leadingZeros && (value == 0)) { - buffer[(*printedSize)++] = '0'; - return RETURN_OK; - } - while (maximumNumber >= 1) { - uint8_t number = value / maximumNumber; - value = value - (number * maximumNumber); - if (!leadingZeros && number == 0) { - maximumNumber /= 10; - } else { - leadingZeros = true; - buffer[(*printedSize)++] = '0' + number; - maximumNumber /= 10; - } - } - return RETURN_OK; -} - -ReturnValue_t AsciiConverter::printSignedInteger(uint8_t* buffer, - uint32_t bufferLength, int32_t value, uint32_t *printedSize) { - bool negative = false; - if ((bufferLength > 0) && (value < 0)) { - *buffer++ = '-'; - bufferLength--; - value = -value; - negative = true; - } - ReturnValue_t result = printInteger(buffer, bufferLength, value, - printedSize); - if (negative) { - (*printedSize)++; - } - return result; -} - -int8_t AsciiConverter::convertHexChar(const uint8_t* character) { - if ((*character > 0x60) && (*character < 0x67)) { - return *character - 0x61 + 10; - } else if ((*character > 0x40) && (*character < 0x47)) { - return *character - 0x41 + 10; - } else if ((*character > 0x2F) && (*character < 0x3A)) { - return *character - 0x30; - } else if (*character == ' ') { - return -2; - } - return -1; -} - -template ReturnValue_t AsciiConverter::scanAsciiDecimalNumber( - const uint8_t** dataPtr, uint8_t len, float* value); -template ReturnValue_t AsciiConverter::scanAsciiDecimalNumber( - const uint8_t** dataPtr, uint8_t len, uint8_t* value); -template ReturnValue_t AsciiConverter::scanAsciiDecimalNumber( - const uint8_t** dataPtr, uint8_t len, uint16_t* value); -template ReturnValue_t AsciiConverter::scanAsciiDecimalNumber( - const uint8_t** dataPtr, uint8_t len, double* value); - -const uint8_t* AsciiConverter::clearSpace(const uint8_t* data, uint8_t len) { - while (len > 0) { - if ((*data != ' ') && (*data != 0x0a) && (*data != 0x0d)) { - return data; - } - data++; - len--; - } - return data; -} +#include "../globalfunctions/AsciiConverter.h" +#include +#include + +template +ReturnValue_t AsciiConverter::scanAsciiDecimalNumber(const uint8_t** dataPtr, + uint8_t len, T* value) { + if (len > std::numeric_limits().digits10) { + return TOO_LONG_FOR_TARGET_TYPE; + } + + double temp; + + ReturnValue_t result = scanAsciiDecimalNumber_(dataPtr, len, &temp); + + *value = temp; + + return result; +} + +ReturnValue_t AsciiConverter::scanAsciiHexByte(const uint8_t** dataPtr, + uint8_t* value) { + int8_t tmp; + + tmp = convertHexChar(*dataPtr); + (*dataPtr)++; + if (tmp == -1) { + return INVALID_CHARACTERS; + } + if (tmp == -2) { + tmp = 0; + } + + *value = tmp << 4; + + tmp = convertHexChar(*dataPtr); + (*dataPtr)++; + if (tmp == -1) { + return INVALID_CHARACTERS; + } + if (tmp != -2) { + *value += tmp; + } else { + *value = *value >> 4; + } + + return RETURN_OK; +} + +ReturnValue_t AsciiConverter::scanAsciiDecimalNumber_(uint8_t const ** dataPtr, + uint8_t len, double* value) { + + uint8_t const *ptr = *dataPtr; + int8_t sign = 1; + float decimal = 0; + bool abort = false; + + *value = 0; + + //ignore leading space + ptr = clearSpace(ptr, len); + + while ((ptr - *dataPtr < len) && !abort) { + switch (*ptr) { + case '+': + sign = 1; + break; + case '-': + sign = -1; + break; + case '.': + decimal = 1; + break; + case ' ': + case 0x0d: + case 0x0a: + //ignore trailing space + ptr = clearSpace(ptr, len - (ptr - *dataPtr)) - 1; //before aborting the loop, ptr will be incremented + abort = true; + break; + default: + if ((*ptr < 0x30) || (*ptr > 0x39)) { + return INVALID_CHARACTERS; + } + *value = *value * 10 + (*ptr - 0x30); + if (decimal > 0) { + decimal *= 10; + } + break; + } + ptr++; + } + + if (decimal == 0) { + decimal = 1; + } + + *value = *value / (decimal) * sign; + + *dataPtr = ptr; + + return RETURN_OK; +} + +ReturnValue_t AsciiConverter::printFloat(uint8_t* buffer, uint32_t bufferLength, + float value, uint8_t decimalPlaces, uint32_t *printedSize) { + *printedSize = 0; + uint32_t streamposition = 0, integerSize; + bool negative = (value < 0); + int32_t digits = bufferLength - decimalPlaces - 1; + if (digits <= 0) { + return BUFFER_TOO_SMALL; + } + if (negative) { + digits -= 1; + buffer[streamposition++] = '-'; + value = -value; + } + float maximumNumber = pow(10, digits); + if (value >= maximumNumber) { + return BUFFER_TOO_SMALL; + } + //print the numbers before the decimal point; + ReturnValue_t result = printInteger(buffer + streamposition, + bufferLength - streamposition - decimalPlaces - 1, value, + &integerSize); + if (result != RETURN_OK) { + return result; + } + streamposition += integerSize; + //The decimal Point + buffer[streamposition++] = '.'; + + //Print the decimals + uint32_t integerValue = value; + value -= integerValue; + value = value * pow(10, decimalPlaces); + result = printInteger(buffer + streamposition, decimalPlaces, round(value), + &integerSize, true); + *printedSize = integerSize + streamposition; + return result; +} + +ReturnValue_t AsciiConverter::printInteger(uint8_t* buffer, + uint32_t bufferLength, uint32_t value, uint32_t *printedSize, + bool leadingZeros) { + *printedSize = 0; + if (bufferLength == 0) { + return BUFFER_TOO_SMALL; + } + uint32_t maximumNumber = -1; + if (bufferLength < 10) { + maximumNumber = pow(10, bufferLength); + if (value >= maximumNumber) { + return BUFFER_TOO_SMALL; + } + maximumNumber /= 10; + } else { + if (!(value <= maximumNumber)) { + return BUFFER_TOO_SMALL; + } + maximumNumber = 1000000000; + } + if (!leadingZeros && (value == 0)) { + buffer[(*printedSize)++] = '0'; + return RETURN_OK; + } + while (maximumNumber >= 1) { + uint8_t number = value / maximumNumber; + value = value - (number * maximumNumber); + if (!leadingZeros && number == 0) { + maximumNumber /= 10; + } else { + leadingZeros = true; + buffer[(*printedSize)++] = '0' + number; + maximumNumber /= 10; + } + } + return RETURN_OK; +} + +ReturnValue_t AsciiConverter::printSignedInteger(uint8_t* buffer, + uint32_t bufferLength, int32_t value, uint32_t *printedSize) { + bool negative = false; + if ((bufferLength > 0) && (value < 0)) { + *buffer++ = '-'; + bufferLength--; + value = -value; + negative = true; + } + ReturnValue_t result = printInteger(buffer, bufferLength, value, + printedSize); + if (negative) { + (*printedSize)++; + } + return result; +} + +int8_t AsciiConverter::convertHexChar(const uint8_t* character) { + if ((*character > 0x60) && (*character < 0x67)) { + return *character - 0x61 + 10; + } else if ((*character > 0x40) && (*character < 0x47)) { + return *character - 0x41 + 10; + } else if ((*character > 0x2F) && (*character < 0x3A)) { + return *character - 0x30; + } else if (*character == ' ') { + return -2; + } + return -1; +} + +template ReturnValue_t AsciiConverter::scanAsciiDecimalNumber( + const uint8_t** dataPtr, uint8_t len, float* value); +template ReturnValue_t AsciiConverter::scanAsciiDecimalNumber( + const uint8_t** dataPtr, uint8_t len, uint8_t* value); +template ReturnValue_t AsciiConverter::scanAsciiDecimalNumber( + const uint8_t** dataPtr, uint8_t len, uint16_t* value); +template ReturnValue_t AsciiConverter::scanAsciiDecimalNumber( + const uint8_t** dataPtr, uint8_t len, double* value); + +const uint8_t* AsciiConverter::clearSpace(const uint8_t* data, uint8_t len) { + while (len > 0) { + if ((*data != ' ') && (*data != 0x0a) && (*data != 0x0d)) { + return data; + } + data++; + len--; + } + return data; +} diff --git a/globalfunctions/AsciiConverter.h b/globalfunctions/AsciiConverter.h index acd406da..27bed4e7 100644 --- a/globalfunctions/AsciiConverter.h +++ b/globalfunctions/AsciiConverter.h @@ -1,39 +1,39 @@ -#ifndef ASCIICONVERTER_H_ -#define ASCIICONVERTER_H_ - -#include - -class AsciiConverter: public HasReturnvaluesIF { -public: - static const uint8_t INTERFACE_ID = CLASS_ID::ASCII_CONVERTER; - static const ReturnValue_t TOO_LONG_FOR_TARGET_TYPE = MAKE_RETURN_CODE(1); - static const ReturnValue_t INVALID_CHARACTERS = MAKE_RETURN_CODE(2); - static const ReturnValue_t BUFFER_TOO_SMALL = MAKE_RETURN_CODE(0x3); - - template - static ReturnValue_t scanAsciiDecimalNumber(const uint8_t **dataPtr, - uint8_t len, T *value); - - static ReturnValue_t scanAsciiHexByte(const uint8_t **dataPtr, - uint8_t *value); - - static ReturnValue_t printFloat(uint8_t *buffer, uint32_t bufferLength, - float value, uint8_t decimalPlaces, uint32_t *printedSize); - - static ReturnValue_t printInteger(uint8_t *buffer, uint32_t bufferLength, - uint32_t value, uint32_t *printedSize, bool leadingZeros = false); - - static ReturnValue_t printSignedInteger(uint8_t *buffer, - uint32_t bufferLength, int32_t value, uint32_t *printedSize); - -private: - AsciiConverter(); - static ReturnValue_t scanAsciiDecimalNumber_(const uint8_t **dataPtr, - uint8_t len, double *value); - - static int8_t convertHexChar(const uint8_t *character); - - static const uint8_t *clearSpace(const uint8_t *data, uint8_t len); -}; - -#endif /* ASCIICONVERTER_H_ */ +#ifndef ASCIICONVERTER_H_ +#define ASCIICONVERTER_H_ + +#include "../returnvalues/HasReturnvaluesIF.h" + +class AsciiConverter: public HasReturnvaluesIF { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::ASCII_CONVERTER; + static const ReturnValue_t TOO_LONG_FOR_TARGET_TYPE = MAKE_RETURN_CODE(1); + static const ReturnValue_t INVALID_CHARACTERS = MAKE_RETURN_CODE(2); + static const ReturnValue_t BUFFER_TOO_SMALL = MAKE_RETURN_CODE(0x3); + + template + static ReturnValue_t scanAsciiDecimalNumber(const uint8_t **dataPtr, + uint8_t len, T *value); + + static ReturnValue_t scanAsciiHexByte(const uint8_t **dataPtr, + uint8_t *value); + + static ReturnValue_t printFloat(uint8_t *buffer, uint32_t bufferLength, + float value, uint8_t decimalPlaces, uint32_t *printedSize); + + static ReturnValue_t printInteger(uint8_t *buffer, uint32_t bufferLength, + uint32_t value, uint32_t *printedSize, bool leadingZeros = false); + + static ReturnValue_t printSignedInteger(uint8_t *buffer, + uint32_t bufferLength, int32_t value, uint32_t *printedSize); + +private: + AsciiConverter(); + static ReturnValue_t scanAsciiDecimalNumber_(const uint8_t **dataPtr, + uint8_t len, double *value); + + static int8_t convertHexChar(const uint8_t *character); + + static const uint8_t *clearSpace(const uint8_t *data, uint8_t len); +}; + +#endif /* ASCIICONVERTER_H_ */ diff --git a/globalfunctions/CRC.cpp b/globalfunctions/CRC.cpp index ecd0b675..6156b558 100644 --- a/globalfunctions/CRC.cpp +++ b/globalfunctions/CRC.cpp @@ -1,139 +1,139 @@ -#include -#include - -const uint16_t CRC::crc16ccitt_table[256] = { - 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, - 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, - 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, - 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, - 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, - 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, - 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, - 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, - 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, - 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, - 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, - 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, - 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, - 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, - 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, - 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, - 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, - 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, - 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, - 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, - 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, - 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, - 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, - 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, - 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, - 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, - 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, - 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, - 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, - 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, - 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, - 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 -}; - - -// CRC implementation -uint16_t CRC::crc16ccitt(uint8_t const input[], uint32_t length, uint16_t startingCrc) -{ - uint8_t *data = (uint8_t *)input; - unsigned int tbl_idx; - - while (length--) { - tbl_idx = ((startingCrc >> 8) ^ *data) & 0xff; - startingCrc = (crc16ccitt_table[tbl_idx] ^ (startingCrc << 8)) & 0xffff; - - data++; - } - return startingCrc & 0xffff; - - //The part below is not used! -// bool temr[16]; -// bool xor_out[16]; -// bool r[16]; -// bool d[8]; -// uint16_t crc_value = 0; -// -// -// for (int i=0; i<16 ;i++) { -// temr[i] = false; -// xor_out[i] = false; -// } -// -// -// for (int i=0; i<16 ;i++) -// r[i] = true; // initialize with 0xFFFF -// -// -// -// for (int j=0; j + +const uint16_t CRC::crc16ccitt_table[256] = { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 +}; + + +// CRC implementation +uint16_t CRC::crc16ccitt(uint8_t const input[], uint32_t length, uint16_t startingCrc) +{ + uint8_t *data = (uint8_t *)input; + unsigned int tbl_idx; + + while (length--) { + tbl_idx = ((startingCrc >> 8) ^ *data) & 0xff; + startingCrc = (crc16ccitt_table[tbl_idx] ^ (startingCrc << 8)) & 0xffff; + + data++; + } + return startingCrc & 0xffff; + + //The part below is not used! +// bool temr[16]; +// bool xor_out[16]; +// bool r[16]; +// bool d[8]; +// uint16_t crc_value = 0; +// +// +// for (int i=0; i<16 ;i++) { +// temr[i] = false; +// xor_out[i] = false; +// } +// +// +// for (int i=0; i<16 ;i++) +// r[i] = true; // initialize with 0xFFFF +// +// +// +// for (int j=0; j - -DleEncoder::DleEncoder() {} - -DleEncoder::~DleEncoder() {} - -ReturnValue_t DleEncoder::encode(const uint8_t* sourceStream, - size_t sourceLen, uint8_t* destStream, size_t maxDestLen, - size_t* encodedLen, bool addStxEtx) { - if (maxDestLen < 2) { - return STREAM_TOO_SHORT; - } - size_t encodedIndex = 0, sourceIndex = 0; - uint8_t nextByte; - if (addStxEtx) { - destStream[0] = STX; - ++encodedIndex; - } - - while (encodedIndex < maxDestLen and sourceIndex < sourceLen) - { - nextByte = sourceStream[sourceIndex]; - // STX, ETX and CR characters in the stream need to be escaped with DLE - if (nextByte == STX or nextByte == ETX or nextByte == CARRIAGE_RETURN) { - if (encodedIndex + 1 >= maxDestLen) { - return STREAM_TOO_SHORT; - } - else { - destStream[encodedIndex] = DLE; - ++encodedIndex; - /* Escaped byte will be actual byte + 0x40. This prevents - * STX, ETX, and carriage return characters from appearing - * in the encoded data stream at all, so when polling an - * encoded stream, the transmission can be stopped at ETX. - * 0x40 was chosen at random with special requirements: - * - Prevent going from one control char to another - * - Prevent overflow for common characters */ - destStream[encodedIndex] = nextByte + 0x40; - } - } - // DLE characters are simply escaped with DLE. - else if (nextByte == DLE) { - if (encodedIndex + 1 >= maxDestLen) { - return STREAM_TOO_SHORT; - } - else { - destStream[encodedIndex] = DLE; - ++encodedIndex; - destStream[encodedIndex] = DLE; - } - } - else { - destStream[encodedIndex] = nextByte; - } - ++encodedIndex; - ++sourceIndex; - } - - if (sourceIndex == sourceLen and encodedIndex < maxDestLen) { - if (addStxEtx) { - destStream[encodedIndex] = ETX; - ++encodedIndex; - } - *encodedLen = encodedIndex; - return RETURN_OK; - } - else { - return STREAM_TOO_SHORT; - } -} - -ReturnValue_t DleEncoder::decode(const uint8_t *sourceStream, - size_t sourceStreamLen, size_t *readLen, uint8_t *destStream, - size_t maxDestStreamlen, size_t *decodedLen) { - size_t encodedIndex = 0, decodedIndex = 0; - uint8_t nextByte; - if (*sourceStream != STX) { - return DECODING_ERROR; - } - ++encodedIndex; - - while ((encodedIndex < sourceStreamLen) && (decodedIndex < maxDestStreamlen) - && (sourceStream[encodedIndex] != ETX) - && (sourceStream[encodedIndex] != STX)) { - if (sourceStream[encodedIndex] == DLE) { - nextByte = sourceStream[encodedIndex + 1]; - // The next byte is a DLE character that was escaped by another - // DLE character, so we can write it to the destination stream. - if (nextByte == DLE) { - destStream[decodedIndex] = nextByte; - } - else { - /* The next byte is a STX, DTX or 0x0D character which - * was escaped by a DLE character. The actual byte was - * also encoded by adding + 0x40 to preven having control chars, - * in the stream at all, so we convert it back. */ - if (nextByte == 0x42 or nextByte == 0x43 or nextByte == 0x4D) { - destStream[decodedIndex] = nextByte - 0x40; - } - else { - return DECODING_ERROR; - } - } - ++encodedIndex; - } - else { - destStream[decodedIndex] = sourceStream[encodedIndex]; - } - - ++encodedIndex; - ++decodedIndex; - } - - if (sourceStream[encodedIndex] != ETX) { - return DECODING_ERROR; - } - else { - *readLen = ++encodedIndex; - *decodedLen = decodedIndex; - return RETURN_OK; - } -} - +#include "../globalfunctions/DleEncoder.h" + +DleEncoder::DleEncoder() {} + +DleEncoder::~DleEncoder() {} + +ReturnValue_t DleEncoder::encode(const uint8_t* sourceStream, + size_t sourceLen, uint8_t* destStream, size_t maxDestLen, + size_t* encodedLen, bool addStxEtx) { + if (maxDestLen < 2) { + return STREAM_TOO_SHORT; + } + size_t encodedIndex = 0, sourceIndex = 0; + uint8_t nextByte; + if (addStxEtx) { + destStream[0] = STX; + ++encodedIndex; + } + + while (encodedIndex < maxDestLen and sourceIndex < sourceLen) + { + nextByte = sourceStream[sourceIndex]; + // STX, ETX and CR characters in the stream need to be escaped with DLE + if (nextByte == STX or nextByte == ETX or nextByte == CARRIAGE_RETURN) { + if (encodedIndex + 1 >= maxDestLen) { + return STREAM_TOO_SHORT; + } + else { + destStream[encodedIndex] = DLE; + ++encodedIndex; + /* Escaped byte will be actual byte + 0x40. This prevents + * STX, ETX, and carriage return characters from appearing + * in the encoded data stream at all, so when polling an + * encoded stream, the transmission can be stopped at ETX. + * 0x40 was chosen at random with special requirements: + * - Prevent going from one control char to another + * - Prevent overflow for common characters */ + destStream[encodedIndex] = nextByte + 0x40; + } + } + // DLE characters are simply escaped with DLE. + else if (nextByte == DLE) { + if (encodedIndex + 1 >= maxDestLen) { + return STREAM_TOO_SHORT; + } + else { + destStream[encodedIndex] = DLE; + ++encodedIndex; + destStream[encodedIndex] = DLE; + } + } + else { + destStream[encodedIndex] = nextByte; + } + ++encodedIndex; + ++sourceIndex; + } + + if (sourceIndex == sourceLen and encodedIndex < maxDestLen) { + if (addStxEtx) { + destStream[encodedIndex] = ETX; + ++encodedIndex; + } + *encodedLen = encodedIndex; + return RETURN_OK; + } + else { + return STREAM_TOO_SHORT; + } +} + +ReturnValue_t DleEncoder::decode(const uint8_t *sourceStream, + size_t sourceStreamLen, size_t *readLen, uint8_t *destStream, + size_t maxDestStreamlen, size_t *decodedLen) { + size_t encodedIndex = 0, decodedIndex = 0; + uint8_t nextByte; + if (*sourceStream != STX) { + return DECODING_ERROR; + } + ++encodedIndex; + + while ((encodedIndex < sourceStreamLen) && (decodedIndex < maxDestStreamlen) + && (sourceStream[encodedIndex] != ETX) + && (sourceStream[encodedIndex] != STX)) { + if (sourceStream[encodedIndex] == DLE) { + nextByte = sourceStream[encodedIndex + 1]; + // The next byte is a DLE character that was escaped by another + // DLE character, so we can write it to the destination stream. + if (nextByte == DLE) { + destStream[decodedIndex] = nextByte; + } + else { + /* The next byte is a STX, DTX or 0x0D character which + * was escaped by a DLE character. The actual byte was + * also encoded by adding + 0x40 to preven having control chars, + * in the stream at all, so we convert it back. */ + if (nextByte == 0x42 or nextByte == 0x43 or nextByte == 0x4D) { + destStream[decodedIndex] = nextByte - 0x40; + } + else { + return DECODING_ERROR; + } + } + ++encodedIndex; + } + else { + destStream[decodedIndex] = sourceStream[encodedIndex]; + } + + ++encodedIndex; + ++decodedIndex; + } + + if (sourceStream[encodedIndex] != ETX) { + return DECODING_ERROR; + } + else { + *readLen = ++encodedIndex; + *decodedLen = decodedIndex; + return RETURN_OK; + } +} + diff --git a/globalfunctions/DleEncoder.h b/globalfunctions/DleEncoder.h index 29851dfe..da3bbaaf 100644 --- a/globalfunctions/DleEncoder.h +++ b/globalfunctions/DleEncoder.h @@ -1,79 +1,79 @@ -#ifndef FRAMEWORK_GLOBALFUNCTIONS_DLEENCODER_H_ -#define FRAMEWORK_GLOBALFUNCTIONS_DLEENCODER_H_ - -#include -#include - -/** - * @brief This DLE Encoder (Data Link Encoder) can be used to encode and - * decode arbitrary data with ASCII control characters - * @details - * List of control codes: - * https://en.wikipedia.org/wiki/C0_and_C1_control_codes - * - * This encoder can be used to achieve a basic transport layer when using - * char based transmission systems. - * The passed source strean is converted into a encoded stream by adding - * a STX marker at the start of the stream and an ETX marker at the end of - * the stream. Any STX, ETX, DLE and CR occurences in the source stream are - * escaped by a DLE character. The encoder also replaces escaped control chars - * by another char, so STX, ETX and CR should not appear anywhere in the actual - * encoded data stream. - * - * When using a strictly char based reception of packets enoded with DLE, - * STX can be used to notify a reader that actual data will start to arrive - * while ETX can be used to notify the reader that the data has ended. - */ -class DleEncoder: public HasReturnvaluesIF { -private: - DleEncoder(); - virtual ~DleEncoder(); - -public: - static constexpr uint8_t INTERFACE_ID = CLASS_ID::DLE_ENCODER; - static constexpr ReturnValue_t STREAM_TOO_SHORT = MAKE_RETURN_CODE(0x01); - static constexpr ReturnValue_t DECODING_ERROR = MAKE_RETURN_CODE(0x02); - - //! Start Of Text character. First character is encoded stream - static constexpr uint8_t STX = 0x02; - //! End Of Text character. Last character in encoded stream - static constexpr uint8_t ETX = 0x03; - //! Data Link Escape character. Used to escape STX, ETX and DLE occurences - //! in the source stream. - static constexpr uint8_t DLE = 0x10; - static constexpr uint8_t CARRIAGE_RETURN = 0x0D; - - /** - * Encodes the give data stream by preceding it with the STX marker - * and ending it with an ETX marker. STX, ETX and DLE characters inside - * the stream are escaped by DLE characters and also replaced by adding - * 0x40 (which is reverted in the decoing process). - * @param sourceStream - * @param sourceLen - * @param destStream - * @param maxDestLen - * @param encodedLen - * @param addStxEtx - * Adding STX and ETX can be omitted, if they are added manually. - * @return - */ - static ReturnValue_t encode(const uint8_t *sourceStream, size_t sourceLen, - uint8_t *destStream, size_t maxDestLen, size_t *encodedLen, - bool addStxEtx = true); - - /** - * Converts an encoded stream back. - * @param sourceStream - * @param sourceStreamLen - * @param readLen - * @param destStream - * @param maxDestStreamlen - * @param decodedLen - * @return - */ - static ReturnValue_t decode(const uint8_t *sourceStream, - size_t sourceStreamLen, size_t *readLen, uint8_t *destStream, - size_t maxDestStreamlen, size_t *decodedLen); -}; - -#endif /* FRAMEWORK_GLOBALFUNCTIONS_DLEENCODER_H_ */ +#ifndef FRAMEWORK_GLOBALFUNCTIONS_DLEENCODER_H_ +#define FRAMEWORK_GLOBALFUNCTIONS_DLEENCODER_H_ + +#include "../returnvalues/HasReturnvaluesIF.h" +#include + +/** + * @brief This DLE Encoder (Data Link Encoder) can be used to encode and + * decode arbitrary data with ASCII control characters + * @details + * List of control codes: + * https://en.wikipedia.org/wiki/C0_and_C1_control_codes + * + * This encoder can be used to achieve a basic transport layer when using + * char based transmission systems. + * The passed source strean is converted into a encoded stream by adding + * a STX marker at the start of the stream and an ETX marker at the end of + * the stream. Any STX, ETX, DLE and CR occurences in the source stream are + * escaped by a DLE character. The encoder also replaces escaped control chars + * by another char, so STX, ETX and CR should not appear anywhere in the actual + * encoded data stream. + * + * When using a strictly char based reception of packets enoded with DLE, + * STX can be used to notify a reader that actual data will start to arrive + * while ETX can be used to notify the reader that the data has ended. + */ +class DleEncoder: public HasReturnvaluesIF { +private: + DleEncoder(); + virtual ~DleEncoder(); + +public: + static constexpr uint8_t INTERFACE_ID = CLASS_ID::DLE_ENCODER; + static constexpr ReturnValue_t STREAM_TOO_SHORT = MAKE_RETURN_CODE(0x01); + static constexpr ReturnValue_t DECODING_ERROR = MAKE_RETURN_CODE(0x02); + + //! Start Of Text character. First character is encoded stream + static constexpr uint8_t STX = 0x02; + //! End Of Text character. Last character in encoded stream + static constexpr uint8_t ETX = 0x03; + //! Data Link Escape character. Used to escape STX, ETX and DLE occurences + //! in the source stream. + static constexpr uint8_t DLE = 0x10; + static constexpr uint8_t CARRIAGE_RETURN = 0x0D; + + /** + * Encodes the give data stream by preceding it with the STX marker + * and ending it with an ETX marker. STX, ETX and DLE characters inside + * the stream are escaped by DLE characters and also replaced by adding + * 0x40 (which is reverted in the decoing process). + * @param sourceStream + * @param sourceLen + * @param destStream + * @param maxDestLen + * @param encodedLen + * @param addStxEtx + * Adding STX and ETX can be omitted, if they are added manually. + * @return + */ + static ReturnValue_t encode(const uint8_t *sourceStream, size_t sourceLen, + uint8_t *destStream, size_t maxDestLen, size_t *encodedLen, + bool addStxEtx = true); + + /** + * Converts an encoded stream back. + * @param sourceStream + * @param sourceStreamLen + * @param readLen + * @param destStream + * @param maxDestStreamlen + * @param decodedLen + * @return + */ + static ReturnValue_t decode(const uint8_t *sourceStream, + size_t sourceStreamLen, size_t *readLen, uint8_t *destStream, + size_t maxDestStreamlen, size_t *decodedLen); +}; + +#endif /* FRAMEWORK_GLOBALFUNCTIONS_DLEENCODER_H_ */ diff --git a/globalfunctions/Type.cpp b/globalfunctions/Type.cpp index 2101074e..9589bed3 100644 --- a/globalfunctions/Type.cpp +++ b/globalfunctions/Type.cpp @@ -1,181 +1,181 @@ -#include -#include - -Type::Type() : - actualType(UNKNOWN_TYPE) { -} - -Type::Type(ActualType_t actualType) : - actualType(actualType) { -} - -Type::Type(const Type& type) : - actualType(type.actualType) { -} - -Type& Type::operator =(Type rhs) { - this->actualType = rhs.actualType; - return *this; -} - -Type& Type::operator =(ActualType_t actualType) { - this->actualType = actualType; - return *this; -} - -Type::operator Type::ActualType_t() const { - return actualType; -} - -bool Type::operator ==(const Type& rhs) { - return this->actualType == rhs.actualType; -} - -bool Type::operator !=(const Type& rhs) { - return !operator==(rhs); -} - -uint8_t Type::getSize() const { - switch (actualType) { - case UINT8_T: - return sizeof(uint8_t); - case INT8_T: - return sizeof(int8_t); - case UINT16_T: - return sizeof(uint16_t); - case INT16_T: - return sizeof(int16_t); - case UINT32_T: - return sizeof(uint32_t); - case INT32_T: - return sizeof(int32_t); - case FLOAT: - return sizeof(float); - case DOUBLE: - return sizeof(double); - default: - return 0; - } -} - -ReturnValue_t Type::serialize(uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) const { - uint8_t ptc; - uint8_t pfc; - ReturnValue_t result = getPtcPfc(&ptc, &pfc); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - result = SerializeAdapter::serialize(&ptc, buffer, size, maxSize, - streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - result = SerializeAdapter::serialize(&pfc, buffer, size, maxSize, - streamEndianness); - - return result; - -} - -size_t Type::getSerializedSize() const { - uint8_t dontcare = 0; - return 2 * SerializeAdapter::getSerializedSize(&dontcare); -} - -ReturnValue_t Type::deSerialize(const uint8_t** buffer, size_t* size, - Endianness streamEndianness) { - uint8_t ptc; - uint8_t pfc; - ReturnValue_t result = SerializeAdapter::deSerialize(&ptc, buffer, - size, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - result = SerializeAdapter::deSerialize(&pfc, buffer, size, - streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - actualType = getActualType(ptc, pfc); - - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t Type::getPtcPfc(uint8_t* ptc, uint8_t* pfc) const { - switch (actualType) { - case UINT8_T: - *ptc = 3; - *pfc = 4; - break; - case INT8_T: - *ptc = 4; - *pfc = 4; - break; - case UINT16_T: - *ptc = 3; - *pfc = 12; - break; - case INT16_T: - *ptc = 4; - *pfc = 12; - break; - case UINT32_T: - *ptc = 3; - *pfc = 14; - break; - case INT32_T: - *ptc = 4; - *pfc = 14; - break; - case FLOAT: - *ptc = 5; - *pfc = 1; - break; - case DOUBLE: - *ptc = 5; - *pfc = 2; - break; - default: - return HasReturnvaluesIF::RETURN_FAILED; - } - return HasReturnvaluesIF::RETURN_OK; -} - -Type::ActualType_t Type::getActualType(uint8_t ptc, uint8_t pfc) { - switch (ptc) { - case 3: - switch (pfc) { - case 4: - return UINT8_T; - case 12: - return UINT16_T; - case 14: - return UINT32_T; - } - break; - case 4: - switch (pfc) { - case 4: - return INT8_T; - case 12: - return INT16_T; - case 14: - return INT32_T; - } - break; - case 5: - switch (pfc) { - case 1: - return FLOAT; - case 2: - return DOUBLE; - } - break; - } - return UNKNOWN_TYPE; -} +#include "../globalfunctions/Type.h" +#include "../serialize/SerializeAdapter.h" + +Type::Type() : + actualType(UNKNOWN_TYPE) { +} + +Type::Type(ActualType_t actualType) : + actualType(actualType) { +} + +Type::Type(const Type& type) : + actualType(type.actualType) { +} + +Type& Type::operator =(Type rhs) { + this->actualType = rhs.actualType; + return *this; +} + +Type& Type::operator =(ActualType_t actualType) { + this->actualType = actualType; + return *this; +} + +Type::operator Type::ActualType_t() const { + return actualType; +} + +bool Type::operator ==(const Type& rhs) { + return this->actualType == rhs.actualType; +} + +bool Type::operator !=(const Type& rhs) { + return !operator==(rhs); +} + +uint8_t Type::getSize() const { + switch (actualType) { + case UINT8_T: + return sizeof(uint8_t); + case INT8_T: + return sizeof(int8_t); + case UINT16_T: + return sizeof(uint16_t); + case INT16_T: + return sizeof(int16_t); + case UINT32_T: + return sizeof(uint32_t); + case INT32_T: + return sizeof(int32_t); + case FLOAT: + return sizeof(float); + case DOUBLE: + return sizeof(double); + default: + return 0; + } +} + +ReturnValue_t Type::serialize(uint8_t** buffer, size_t* size, + size_t maxSize, Endianness streamEndianness) const { + uint8_t ptc; + uint8_t pfc; + ReturnValue_t result = getPtcPfc(&ptc, &pfc); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + result = SerializeAdapter::serialize(&ptc, buffer, size, maxSize, + streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + result = SerializeAdapter::serialize(&pfc, buffer, size, maxSize, + streamEndianness); + + return result; + +} + +size_t Type::getSerializedSize() const { + uint8_t dontcare = 0; + return 2 * SerializeAdapter::getSerializedSize(&dontcare); +} + +ReturnValue_t Type::deSerialize(const uint8_t** buffer, size_t* size, + Endianness streamEndianness) { + uint8_t ptc; + uint8_t pfc; + ReturnValue_t result = SerializeAdapter::deSerialize(&ptc, buffer, + size, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + result = SerializeAdapter::deSerialize(&pfc, buffer, size, + streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + actualType = getActualType(ptc, pfc); + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Type::getPtcPfc(uint8_t* ptc, uint8_t* pfc) const { + switch (actualType) { + case UINT8_T: + *ptc = 3; + *pfc = 4; + break; + case INT8_T: + *ptc = 4; + *pfc = 4; + break; + case UINT16_T: + *ptc = 3; + *pfc = 12; + break; + case INT16_T: + *ptc = 4; + *pfc = 12; + break; + case UINT32_T: + *ptc = 3; + *pfc = 14; + break; + case INT32_T: + *ptc = 4; + *pfc = 14; + break; + case FLOAT: + *ptc = 5; + *pfc = 1; + break; + case DOUBLE: + *ptc = 5; + *pfc = 2; + break; + default: + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; +} + +Type::ActualType_t Type::getActualType(uint8_t ptc, uint8_t pfc) { + switch (ptc) { + case 3: + switch (pfc) { + case 4: + return UINT8_T; + case 12: + return UINT16_T; + case 14: + return UINT32_T; + } + break; + case 4: + switch (pfc) { + case 4: + return INT8_T; + case 12: + return INT16_T; + case 14: + return INT32_T; + } + break; + case 5: + switch (pfc) { + case 1: + return FLOAT; + case 2: + return DOUBLE; + } + break; + } + return UNKNOWN_TYPE; +} diff --git a/globalfunctions/Type.h b/globalfunctions/Type.h index b083a701..c10511f8 100644 --- a/globalfunctions/Type.h +++ b/globalfunctions/Type.h @@ -1,94 +1,94 @@ -#ifndef TYPE_H_ -#define TYPE_H_ - -#include -#include - -/** - * @brief Type definition for CCSDS or ECSS. - */ -class Type: public SerializeIF { -public: - enum ActualType_t { - UINT8_T, - INT8_T, - UINT16_T, - INT16_T, - UINT32_T, - INT32_T, - FLOAT, - DOUBLE, - UNKNOWN_TYPE - }; - - Type(); - - Type(ActualType_t actualType); - - Type(const Type &type); - - Type& operator=(Type rhs); - - Type& operator=(ActualType_t actualType); - - operator ActualType_t() const; - - bool operator==(const Type &rhs); - bool operator!=(const Type &rhs); - - uint8_t getSize() const; - - ReturnValue_t getPtcPfc(uint8_t *ptc, uint8_t *pfc) const; - - static ActualType_t getActualType(uint8_t ptc, uint8_t pfc); - - virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size, - size_t maxSize, Endianness streamEndianness) const override; - - virtual size_t getSerializedSize() const override; - - virtual ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, - Endianness streamEndianness) override; - -private: - ActualType_t actualType; -}; - -template -struct PodTypeConversion { - static const Type::ActualType_t type = Type::UNKNOWN_TYPE; -}; -template<> -struct PodTypeConversion { - static const Type::ActualType_t type = Type::UINT8_T; -}; -template<> -struct PodTypeConversion { - static const Type::ActualType_t type = Type::UINT16_T; -}; -template<> -struct PodTypeConversion { - static const Type::ActualType_t type = Type::UINT32_T; -}; -template<> -struct PodTypeConversion { - static const Type::ActualType_t type = Type::INT8_T; -}; -template<> -struct PodTypeConversion { - static const Type::ActualType_t type = Type::INT16_T; -}; -template<> -struct PodTypeConversion { - static const Type::ActualType_t type = Type::INT32_T; -}; -template<> -struct PodTypeConversion { - static const Type::ActualType_t type = Type::FLOAT; -}; -template<> -struct PodTypeConversion { - static const Type::ActualType_t type = Type::DOUBLE; -}; - -#endif /* TYPE_H_ */ +#ifndef TYPE_H_ +#define TYPE_H_ + +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../serialize/SerializeIF.h" + +/** + * @brief Type definition for CCSDS or ECSS. + */ +class Type: public SerializeIF { +public: + enum ActualType_t { + UINT8_T, + INT8_T, + UINT16_T, + INT16_T, + UINT32_T, + INT32_T, + FLOAT, + DOUBLE, + UNKNOWN_TYPE + }; + + Type(); + + Type(ActualType_t actualType); + + Type(const Type &type); + + Type& operator=(Type rhs); + + Type& operator=(ActualType_t actualType); + + operator ActualType_t() const; + + bool operator==(const Type &rhs); + bool operator!=(const Type &rhs); + + uint8_t getSize() const; + + ReturnValue_t getPtcPfc(uint8_t *ptc, uint8_t *pfc) const; + + static ActualType_t getActualType(uint8_t ptc, uint8_t pfc); + + virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size, + size_t maxSize, Endianness streamEndianness) const override; + + virtual size_t getSerializedSize() const override; + + virtual ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) override; + +private: + ActualType_t actualType; +}; + +template +struct PodTypeConversion { + static const Type::ActualType_t type = Type::UNKNOWN_TYPE; +}; +template<> +struct PodTypeConversion { + static const Type::ActualType_t type = Type::UINT8_T; +}; +template<> +struct PodTypeConversion { + static const Type::ActualType_t type = Type::UINT16_T; +}; +template<> +struct PodTypeConversion { + static const Type::ActualType_t type = Type::UINT32_T; +}; +template<> +struct PodTypeConversion { + static const Type::ActualType_t type = Type::INT8_T; +}; +template<> +struct PodTypeConversion { + static const Type::ActualType_t type = Type::INT16_T; +}; +template<> +struct PodTypeConversion { + static const Type::ActualType_t type = Type::INT32_T; +}; +template<> +struct PodTypeConversion { + static const Type::ActualType_t type = Type::FLOAT; +}; +template<> +struct PodTypeConversion { + static const Type::ActualType_t type = Type::DOUBLE; +}; + +#endif /* TYPE_H_ */ diff --git a/globalfunctions/arrayprinter.cpp b/globalfunctions/arrayprinter.cpp index e8fce56c..3f02c882 100644 --- a/globalfunctions/arrayprinter.cpp +++ b/globalfunctions/arrayprinter.cpp @@ -1,61 +1,61 @@ -#include -#include -#include - -void arrayprinter::print(const uint8_t *data, size_t size, OutputType type, - bool printInfo, size_t maxCharPerLine) { - if(printInfo) { - sif::info << "Printing data with size " << size << ": "; - } - sif::info << "["; - if(type == OutputType::HEX) { - arrayprinter::printHex(data, size, maxCharPerLine); - } - else if (type == OutputType::DEC) { - arrayprinter::printDec(data, size, maxCharPerLine); - } - else if(type == OutputType::BIN) { - arrayprinter::printBin(data, size); - } -} - -void arrayprinter::printHex(const uint8_t *data, size_t size, - size_t maxCharPerLine) { - sif::info << std::hex; - for(size_t i = 0; i < size; i++) { - sif::info << "0x" << static_cast(data[i]); - if(i < size - 1){ - sif::info << " , "; - if(i > 0 and i % maxCharPerLine == 0) { - sif::info << std::endl; - } - } - - } - sif::info << std::dec; - sif::info << "]" << std::endl; -} - -void arrayprinter::printDec(const uint8_t *data, size_t size, - size_t maxCharPerLine) { - sif::info << std::dec; - for(size_t i = 0; i < size; i++) { - sif::info << static_cast(data[i]); - if(i < size - 1){ - sif::info << " , "; - if(i > 0 and i % maxCharPerLine == 0) { - sif::info << std::endl; - } - } - } - sif::info << "]" << std::endl; -} - -void arrayprinter::printBin(const uint8_t *data, size_t size) { - sif::info << "\n" << std::flush; - for(size_t i = 0; i < size; i++) { - sif::info << "Byte " << i + 1 << ": 0b"<< - std::bitset<8>(data[i]) << ",\n" << std::flush; - } - sif::info << "]" << std::endl; -} +#include "../globalfunctions/arrayprinter.h" +#include "../serviceinterface/ServiceInterfaceStream.h" +#include + +void arrayprinter::print(const uint8_t *data, size_t size, OutputType type, + bool printInfo, size_t maxCharPerLine) { + if(printInfo) { + sif::info << "Printing data with size " << size << ": "; + } + sif::info << "["; + if(type == OutputType::HEX) { + arrayprinter::printHex(data, size, maxCharPerLine); + } + else if (type == OutputType::DEC) { + arrayprinter::printDec(data, size, maxCharPerLine); + } + else if(type == OutputType::BIN) { + arrayprinter::printBin(data, size); + } +} + +void arrayprinter::printHex(const uint8_t *data, size_t size, + size_t maxCharPerLine) { + sif::info << std::hex; + for(size_t i = 0; i < size; i++) { + sif::info << "0x" << static_cast(data[i]); + if(i < size - 1){ + sif::info << " , "; + if(i > 0 and i % maxCharPerLine == 0) { + sif::info << std::endl; + } + } + + } + sif::info << std::dec; + sif::info << "]" << std::endl; +} + +void arrayprinter::printDec(const uint8_t *data, size_t size, + size_t maxCharPerLine) { + sif::info << std::dec; + for(size_t i = 0; i < size; i++) { + sif::info << static_cast(data[i]); + if(i < size - 1){ + sif::info << " , "; + if(i > 0 and i % maxCharPerLine == 0) { + sif::info << std::endl; + } + } + } + sif::info << "]" << std::endl; +} + +void arrayprinter::printBin(const uint8_t *data, size_t size) { + sif::info << "\n" << std::flush; + for(size_t i = 0; i < size; i++) { + sif::info << "Byte " << i + 1 << ": 0b"<< + std::bitset<8>(data[i]) << ",\n" << std::flush; + } + sif::info << "]" << std::endl; +} diff --git a/globalfunctions/matching/BinaryMatcher.h b/globalfunctions/matching/BinaryMatcher.h index df7325cf..60e055a1 100644 --- a/globalfunctions/matching/BinaryMatcher.h +++ b/globalfunctions/matching/BinaryMatcher.h @@ -1,41 +1,41 @@ -#ifndef BINARYMATCHER_H_ -#define BINARYMATCHER_H_ - -#include - -template -class BinaryMatcher: public MatcherIF { -public: - bool inverted; - T mask, matchField; - - BinaryMatcher() : - inverted(false), mask(0), matchField(0) { - } - - BinaryMatcher(T mask, T match, bool inverted = false) : - inverted(inverted), mask(mask), matchField(match) { - } - - bool match(T input) { - if (inverted) { - return ~doMatch(input, mask, matchField); - } else { - return doMatch(input, mask, matchField); - } - } - -protected: - - bool doMatch(T input, T mask, T match) { - match = match & mask; - input = input & mask; - if (input == match) { - return true; - } else { - return false; - } - } -}; - -#endif /* BINARYMATCHER_H_ */ +#ifndef BINARYMATCHER_H_ +#define BINARYMATCHER_H_ + +#include "../../globalfunctions/matching/MatcherIF.h" + +template +class BinaryMatcher: public MatcherIF { +public: + bool inverted; + T mask, matchField; + + BinaryMatcher() : + inverted(false), mask(0), matchField(0) { + } + + BinaryMatcher(T mask, T match, bool inverted = false) : + inverted(inverted), mask(mask), matchField(match) { + } + + bool match(T input) { + if (inverted) { + return ~doMatch(input, mask, matchField); + } else { + return doMatch(input, mask, matchField); + } + } + +protected: + + bool doMatch(T input, T mask, T match) { + match = match & mask; + input = input & mask; + if (input == match) { + return true; + } else { + return false; + } + } +}; + +#endif /* BINARYMATCHER_H_ */ diff --git a/globalfunctions/matching/DecimalMatcher.h b/globalfunctions/matching/DecimalMatcher.h index f4722e6b..24f399ef 100644 --- a/globalfunctions/matching/DecimalMatcher.h +++ b/globalfunctions/matching/DecimalMatcher.h @@ -1,50 +1,50 @@ -#ifndef DECIMALMATCHER_H_ -#define DECIMALMATCHER_H_ - -#include - -template -class DecimalMatcher: public MatcherIF { -public: - bool inverted; - T mask, matchField; - - DecimalMatcher() : - inverted(false), mask(0), matchField(0) { - } - - DecimalMatcher(T mask, T match, bool inverted = false) : - inverted(inverted), mask(mask), matchField(match) { - } - - bool match(T input) { - if (inverted) { - return ~doMatch(input, mask, matchField); - } else { - return doMatch(input, mask, matchField); - } - } - -protected: - bool doMatch(T input, T mask, T match) { - T decimal = 1, remainderMask, remainderMatch, remainderInput; - - while (mask != 0) { - remainderMask = mask % (decimal * 10); - remainderMatch = match % (decimal * 10); - remainderInput = input % (decimal * 10); - if (remainderMask != 0) { - if (remainderMatch != remainderInput) { - return false; - } - } - mask -= remainderMask; - match -= remainderMatch; - input -= remainderInput; - decimal *= 10; - } - return true; - } -}; - -#endif /* DECIMALMATCHER_H_ */ +#ifndef DECIMALMATCHER_H_ +#define DECIMALMATCHER_H_ + +#include "../../globalfunctions/matching/MatcherIF.h" + +template +class DecimalMatcher: public MatcherIF { +public: + bool inverted; + T mask, matchField; + + DecimalMatcher() : + inverted(false), mask(0), matchField(0) { + } + + DecimalMatcher(T mask, T match, bool inverted = false) : + inverted(inverted), mask(mask), matchField(match) { + } + + bool match(T input) { + if (inverted) { + return ~doMatch(input, mask, matchField); + } else { + return doMatch(input, mask, matchField); + } + } + +protected: + bool doMatch(T input, T mask, T match) { + T decimal = 1, remainderMask, remainderMatch, remainderInput; + + while (mask != 0) { + remainderMask = mask % (decimal * 10); + remainderMatch = match % (decimal * 10); + remainderInput = input % (decimal * 10); + if (remainderMask != 0) { + if (remainderMatch != remainderInput) { + return false; + } + } + mask -= remainderMask; + match -= remainderMatch; + input -= remainderInput; + decimal *= 10; + } + return true; + } +}; + +#endif /* DECIMALMATCHER_H_ */ diff --git a/globalfunctions/matching/MatchTree.h b/globalfunctions/matching/MatchTree.h index b54f5492..2d380bbb 100644 --- a/globalfunctions/matching/MatchTree.h +++ b/globalfunctions/matching/MatchTree.h @@ -1,216 +1,216 @@ -#ifndef FRAMEWORK_GLOBALFUNCTIONS_MATCHING_MATCHTREE_H_ -#define FRAMEWORK_GLOBALFUNCTIONS_MATCHING_MATCHTREE_H_ - -#include -#include -#include - -template -class MatchTree: public SerializeableMatcherIF, public BinaryTree< - SerializeableMatcherIF> { -public: - - static const uint8_t INTERFACE_ID = CLASS_ID::MATCH_TREE_CLASS; - static const ReturnValue_t TOO_DETAILED_REQUEST = MAKE_RETURN_CODE(1); - static const ReturnValue_t TOO_GENERAL_REQUEST = MAKE_RETURN_CODE(2); - static const ReturnValue_t NO_MATCH = MAKE_RETURN_CODE(3); - static const ReturnValue_t FULL = MAKE_RETURN_CODE(4); - static const ReturnValue_t NEW_NODE_CREATED = MAKE_RETURN_CODE(5); - - typedef typename BinaryTree>::iterator iterator; - typedef BinaryNode> Node; - static const bool AND = true; //LEFT - static const bool OR = false; //RIGHT - MatchTree(BinaryNode>* root, - uint8_t maxDepth = -1) : - BinaryTree>(root), maxDepth(maxDepth) { - } - MatchTree(iterator root, uint8_t maxDepth = -1) : - BinaryTree>(root.element), maxDepth( - maxDepth) { - } - MatchTree() : - BinaryTree>(), maxDepth(-1) { - } - virtual ~MatchTree() { - } - virtual bool match(T number) { - return matchesTree(number); - } - bool matchesTree(T number) { - iterator iter = this->begin(); - if (iter == this->end()) { - return false; - } - return matchSubtree(iter, number); - } - - ReturnValue_t serialize(uint8_t** buffer, size_t* size, - size_t maxSize, SerializeIF::Endianness streamEndianness) const override { - iterator iter = this->begin(); - uint8_t count = this->countRight(iter); - ReturnValue_t result = SerializeAdapter::serialize(&count, - buffer, size, maxSize, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - if (iter == this->end()) { - return HasReturnvaluesIF::RETURN_OK; - } - result = iter->serialize(buffer, size, maxSize, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - if (maxDepth > 0) { - MatchTree temp(iter.left(), maxDepth - 1); - result = temp.serialize(buffer, size, maxSize, streamEndianness); - } - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - iter = iter.right(); - while (iter != this->end()) { - result = iter->serialize(buffer, size, maxSize, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - if (maxDepth > 0) { - MatchTree temp(iter.left(), maxDepth - 1); - result = temp.serialize(buffer, size, maxSize, streamEndianness); - } - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - iter = iter.right(); - } - return result; - } - - size_t getSerializedSize() const override { - //Analogous to serialize! - uint32_t size = 1; //One for count - iterator iter = this->begin(); - if (iter == this->end()) { - return size; - } - //Count object itself - size += iter->getSerializedSize(); - //Handle everything below on AND side - if (maxDepth > 0) { - MatchTree temp(iter.left(), maxDepth - 1); - size += temp.getSerializedSize(); - } - //Handle everything on OR side - iter = iter.right(); - //Iterate over every object on the OR branch - while (iter != this->end()) { - size += iter->getSerializedSize(); - if (maxDepth > 0) { - //If we are allowed to go deeper, handle AND elements. - MatchTree temp(iter.left(), maxDepth - 1); - size += temp.getSerializedSize(); - } - iter = iter.right(); - } - return size; - } - - ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - SerializeIF::Endianness streamEndianness) override { - return HasReturnvaluesIF::RETURN_OK; - } - -protected: - - bool isOnAndBranch(iterator position) { - if ((position == this->end()) || (position.up() == this->end())) { - return false; - } - if (position.up().left() == position) { - return true; - } else { - return false; - } - } - - //SHOULDDO: What to do if insertion/deletion fails. Throw event? - ReturnValue_t removeElementAndAllChildren(iterator position) { - auto children = this->erase(position); - ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; - if (children.first != this->end()) { - result = removeElementAndAllChildren(children.first); - } - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - if (children.second != this->end()) { - result = removeElementAndAllChildren(children.second); - } - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - //Delete element itself. - return cleanUpElement(position); - } - - ReturnValue_t removeElementAndReconnectChildren(iterator position) { - if (position == this->end()) { - return HasReturnvaluesIF::RETURN_OK; - } - //Delete everything from the AND branch. - ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; - if (position.left() != this->end()) { - result = removeElementAndAllChildren(position.left()); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - } - - if (position.right() != this->end()) { - //There's something at the OR branch, reconnect to parent. - if (isOnAndBranch(position)) { - //Either one hierarchy up AND branch... - this->insert(AND, position.up(), position.right().element); - } else { - //or on another OR'ed element (or install new root node). - this->insert(OR, position.up(), position.right().element); - } - } else { - if (isOnAndBranch(position)) { - //Recursively delete parent node as well, because it is not expected to be there anymore. - return removeElementAndReconnectChildren(position.up()); - } else { - //simply delete self. - this->erase(position); - } - - } - //Delete element itself. - return cleanUpElement(position); - } - - virtual ReturnValue_t cleanUpElement(iterator position) { - return HasReturnvaluesIF::RETURN_OK; - } - - bool matchSubtree(iterator iter, T number) { - bool isMatch = iter->match(number); - if (isMatch) { - if (iter.left() == this->end()) { - return true; - } - isMatch = matchSubtree(iter.left(), number); - if (isMatch) { - return true; - } - } - if (iter.right() == this->end()) { - return false; - } - return matchSubtree(iter.right(), number); - } -private: - uint8_t maxDepth; -}; - -#endif /* FRAMEWORK_GLOBALFUNCTIONS_MATCHING_MATCHTREE_H_ */ +#ifndef FRAMEWORK_GLOBALFUNCTIONS_MATCHING_MATCHTREE_H_ +#define FRAMEWORK_GLOBALFUNCTIONS_MATCHING_MATCHTREE_H_ + +#include "../../container/BinaryTree.h" +#include "../../globalfunctions/matching/SerializeableMatcherIF.h" +#include "../../serialize/SerializeAdapter.h" + +template +class MatchTree: public SerializeableMatcherIF, public BinaryTree< + SerializeableMatcherIF> { +public: + + static const uint8_t INTERFACE_ID = CLASS_ID::MATCH_TREE_CLASS; + static const ReturnValue_t TOO_DETAILED_REQUEST = MAKE_RETURN_CODE(1); + static const ReturnValue_t TOO_GENERAL_REQUEST = MAKE_RETURN_CODE(2); + static const ReturnValue_t NO_MATCH = MAKE_RETURN_CODE(3); + static const ReturnValue_t FULL = MAKE_RETURN_CODE(4); + static const ReturnValue_t NEW_NODE_CREATED = MAKE_RETURN_CODE(5); + + typedef typename BinaryTree>::iterator iterator; + typedef BinaryNode> Node; + static const bool AND = true; //LEFT + static const bool OR = false; //RIGHT + MatchTree(BinaryNode>* root, + uint8_t maxDepth = -1) : + BinaryTree>(root), maxDepth(maxDepth) { + } + MatchTree(iterator root, uint8_t maxDepth = -1) : + BinaryTree>(root.element), maxDepth( + maxDepth) { + } + MatchTree() : + BinaryTree>(), maxDepth(-1) { + } + virtual ~MatchTree() { + } + virtual bool match(T number) { + return matchesTree(number); + } + bool matchesTree(T number) { + iterator iter = this->begin(); + if (iter == this->end()) { + return false; + } + return matchSubtree(iter, number); + } + + ReturnValue_t serialize(uint8_t** buffer, size_t* size, + size_t maxSize, SerializeIF::Endianness streamEndianness) const override { + iterator iter = this->begin(); + uint8_t count = this->countRight(iter); + ReturnValue_t result = SerializeAdapter::serialize(&count, + buffer, size, maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if (iter == this->end()) { + return HasReturnvaluesIF::RETURN_OK; + } + result = iter->serialize(buffer, size, maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if (maxDepth > 0) { + MatchTree temp(iter.left(), maxDepth - 1); + result = temp.serialize(buffer, size, maxSize, streamEndianness); + } + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + iter = iter.right(); + while (iter != this->end()) { + result = iter->serialize(buffer, size, maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if (maxDepth > 0) { + MatchTree temp(iter.left(), maxDepth - 1); + result = temp.serialize(buffer, size, maxSize, streamEndianness); + } + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + iter = iter.right(); + } + return result; + } + + size_t getSerializedSize() const override { + //Analogous to serialize! + uint32_t size = 1; //One for count + iterator iter = this->begin(); + if (iter == this->end()) { + return size; + } + //Count object itself + size += iter->getSerializedSize(); + //Handle everything below on AND side + if (maxDepth > 0) { + MatchTree temp(iter.left(), maxDepth - 1); + size += temp.getSerializedSize(); + } + //Handle everything on OR side + iter = iter.right(); + //Iterate over every object on the OR branch + while (iter != this->end()) { + size += iter->getSerializedSize(); + if (maxDepth > 0) { + //If we are allowed to go deeper, handle AND elements. + MatchTree temp(iter.left(), maxDepth - 1); + size += temp.getSerializedSize(); + } + iter = iter.right(); + } + return size; + } + + ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + SerializeIF::Endianness streamEndianness) override { + return HasReturnvaluesIF::RETURN_OK; + } + +protected: + + bool isOnAndBranch(iterator position) { + if ((position == this->end()) || (position.up() == this->end())) { + return false; + } + if (position.up().left() == position) { + return true; + } else { + return false; + } + } + + //SHOULDDO: What to do if insertion/deletion fails. Throw event? + ReturnValue_t removeElementAndAllChildren(iterator position) { + auto children = this->erase(position); + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + if (children.first != this->end()) { + result = removeElementAndAllChildren(children.first); + } + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if (children.second != this->end()) { + result = removeElementAndAllChildren(children.second); + } + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + //Delete element itself. + return cleanUpElement(position); + } + + ReturnValue_t removeElementAndReconnectChildren(iterator position) { + if (position == this->end()) { + return HasReturnvaluesIF::RETURN_OK; + } + //Delete everything from the AND branch. + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + if (position.left() != this->end()) { + result = removeElementAndAllChildren(position.left()); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + + if (position.right() != this->end()) { + //There's something at the OR branch, reconnect to parent. + if (isOnAndBranch(position)) { + //Either one hierarchy up AND branch... + this->insert(AND, position.up(), position.right().element); + } else { + //or on another OR'ed element (or install new root node). + this->insert(OR, position.up(), position.right().element); + } + } else { + if (isOnAndBranch(position)) { + //Recursively delete parent node as well, because it is not expected to be there anymore. + return removeElementAndReconnectChildren(position.up()); + } else { + //simply delete self. + this->erase(position); + } + + } + //Delete element itself. + return cleanUpElement(position); + } + + virtual ReturnValue_t cleanUpElement(iterator position) { + return HasReturnvaluesIF::RETURN_OK; + } + + bool matchSubtree(iterator iter, T number) { + bool isMatch = iter->match(number); + if (isMatch) { + if (iter.left() == this->end()) { + return true; + } + isMatch = matchSubtree(iter.left(), number); + if (isMatch) { + return true; + } + } + if (iter.right() == this->end()) { + return false; + } + return matchSubtree(iter.right(), number); + } +private: + uint8_t maxDepth; +}; + +#endif /* FRAMEWORK_GLOBALFUNCTIONS_MATCHING_MATCHTREE_H_ */ diff --git a/globalfunctions/matching/RangeMatcher.h b/globalfunctions/matching/RangeMatcher.h index 6fee1f52..ac67e8b8 100644 --- a/globalfunctions/matching/RangeMatcher.h +++ b/globalfunctions/matching/RangeMatcher.h @@ -1,70 +1,70 @@ -#ifndef RANGEMATCHER_H_ -#define RANGEMATCHER_H_ - -#include -#include - -template -class RangeMatcher: public SerializeableMatcherIF { -public: - bool inverted; - T lowerBound; - T upperBound; - - RangeMatcher() : - inverted(true), lowerBound(1), upperBound(0) { - } - RangeMatcher(T lowerBound, T upperBound, bool inverted = false) : - inverted(inverted), lowerBound(lowerBound), upperBound(upperBound) { - } - - bool match(T input) { - if (inverted) { - return !doMatch(input); - } else { - return doMatch(input); - } - } - - ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize, - SerializeIF::Endianness streamEndianness) const override { - ReturnValue_t result = SerializeAdapter::serialize(&lowerBound, buffer, - size, maxSize, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - result = SerializeAdapter::serialize(&upperBound, buffer, size, - maxSize, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - return SerializeAdapter::serialize(&inverted, buffer, size, maxSize, - streamEndianness); - } - - size_t getSerializedSize() const override { - return sizeof(lowerBound) + sizeof(upperBound) + sizeof(bool); - } - - ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, - SerializeIF::Endianness streamEndianness) override { - ReturnValue_t result = SerializeAdapter::deSerialize(&lowerBound, - buffer, size, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - result = SerializeAdapter::deSerialize(&upperBound, buffer, size, - streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - return SerializeAdapter::deSerialize(&inverted, buffer, size, - streamEndianness); - } -protected: - bool doMatch(T input) { - return (input >= lowerBound) && (input <= upperBound); - } -}; - -#endif /* RANGEMATCHER_H_ */ +#ifndef RANGEMATCHER_H_ +#define RANGEMATCHER_H_ + +#include "../../globalfunctions/matching/SerializeableMatcherIF.h" +#include "../../serialize/SerializeAdapter.h" + +template +class RangeMatcher: public SerializeableMatcherIF { +public: + bool inverted; + T lowerBound; + T upperBound; + + RangeMatcher() : + inverted(true), lowerBound(1), upperBound(0) { + } + RangeMatcher(T lowerBound, T upperBound, bool inverted = false) : + inverted(inverted), lowerBound(lowerBound), upperBound(upperBound) { + } + + bool match(T input) { + if (inverted) { + return !doMatch(input); + } else { + return doMatch(input); + } + } + + ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize, + SerializeIF::Endianness streamEndianness) const override { + ReturnValue_t result = SerializeAdapter::serialize(&lowerBound, buffer, + size, maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = SerializeAdapter::serialize(&upperBound, buffer, size, + maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return SerializeAdapter::serialize(&inverted, buffer, size, maxSize, + streamEndianness); + } + + size_t getSerializedSize() const override { + return sizeof(lowerBound) + sizeof(upperBound) + sizeof(bool); + } + + ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, + SerializeIF::Endianness streamEndianness) override { + ReturnValue_t result = SerializeAdapter::deSerialize(&lowerBound, + buffer, size, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = SerializeAdapter::deSerialize(&upperBound, buffer, size, + streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return SerializeAdapter::deSerialize(&inverted, buffer, size, + streamEndianness); + } +protected: + bool doMatch(T input) { + return (input >= lowerBound) && (input <= upperBound); + } +}; + +#endif /* RANGEMATCHER_H_ */ diff --git a/globalfunctions/matching/SerializeableMatcherIF.h b/globalfunctions/matching/SerializeableMatcherIF.h index 7b00a1b3..0d2873ef 100644 --- a/globalfunctions/matching/SerializeableMatcherIF.h +++ b/globalfunctions/matching/SerializeableMatcherIF.h @@ -1,13 +1,13 @@ -#ifndef FRAMEWORK_GLOBALFUNCTIONS_MATCHING_SERIALIZEABLEMATCHERIF_H_ -#define FRAMEWORK_GLOBALFUNCTIONS_MATCHING_SERIALIZEABLEMATCHERIF_H_ - -#include -#include - -template -class SerializeableMatcherIF : public MatcherIF, public SerializeIF { -public: - virtual ~SerializeableMatcherIF() {} -}; - -#endif /* FRAMEWORK_GLOBALFUNCTIONS_MATCHING_SERIALIZEABLEMATCHERIF_H_ */ +#ifndef FRAMEWORK_GLOBALFUNCTIONS_MATCHING_SERIALIZEABLEMATCHERIF_H_ +#define FRAMEWORK_GLOBALFUNCTIONS_MATCHING_SERIALIZEABLEMATCHERIF_H_ + +#include "../../globalfunctions/matching/MatcherIF.h" +#include "../../serialize/SerializeIF.h" + +template +class SerializeableMatcherIF : public MatcherIF, public SerializeIF { +public: + virtual ~SerializeableMatcherIF() {} +}; + +#endif /* FRAMEWORK_GLOBALFUNCTIONS_MATCHING_SERIALIZEABLEMATCHERIF_H_ */ diff --git a/globalfunctions/math/QuaternionOperations.cpp b/globalfunctions/math/QuaternionOperations.cpp index f8c75149..448d30f1 100644 --- a/globalfunctions/math/QuaternionOperations.cpp +++ b/globalfunctions/math/QuaternionOperations.cpp @@ -1,156 +1,156 @@ -#include "QuaternionOperations.h" -#include - -#include -#include -#include - -QuaternionOperations::~QuaternionOperations() { -} - -void QuaternionOperations::multiply(const double* q1, const double* q2, - double* q) { - double out[4]; - - out[0] = q1[3] * q2[0] + q1[2] * q2[1] - q1[1] * q2[2] + q1[0] * q2[3]; - out[1] = -q1[2] * q2[0] + q1[3] * q2[1] + q1[0] * q2[2] + q1[1] * q2[3]; - out[2] = q1[1] * q2[0] - q1[0] * q2[1] + q1[3] * q2[2] + q1[2] * q2[3]; - out[3] = -q1[0] * q2[0] - q1[1] * q2[1] - q1[2] * q2[2] + q1[3] * q2[3]; - - memcpy(q, out, 4 * sizeof(*q)); -} - -void QuaternionOperations::toDcm(const double* quaternion, double dcm[][3]) { - dcm[0][0] = 2 - * (quaternion[0] * quaternion[0] + quaternion[3] * quaternion[3]) - - 1; - dcm[0][1] = 2 - * (quaternion[0] * quaternion[1] + quaternion[2] * quaternion[3]); - dcm[0][2] = 2 - * (quaternion[0] * quaternion[2] - quaternion[1] * quaternion[3]); - - dcm[1][0] = 2 - * (quaternion[0] * quaternion[1] - quaternion[2] * quaternion[3]); - dcm[1][1] = 2 - * (quaternion[1] * quaternion[1] + quaternion[3] * quaternion[3]) - - 1; - dcm[1][2] = 2 - * (quaternion[1] * quaternion[2] + quaternion[0] * quaternion[3]); - - dcm[2][0] = 2 - * (quaternion[0] * quaternion[2] + quaternion[1] * quaternion[3]); - dcm[2][1] = 2 - * (quaternion[1] * quaternion[2] - quaternion[0] * quaternion[3]); - dcm[2][2] = 2 - * (quaternion[2] * quaternion[2] + quaternion[3] * quaternion[3]) - - 1; -} - -void QuaternionOperations::inverse(const double* quaternion, - double* inverseQuaternion) { - memcpy(inverseQuaternion, quaternion, 4 * sizeof(*quaternion)); - VectorOperations::mulScalar(inverseQuaternion, -1, - inverseQuaternion, 3); -} - -QuaternionOperations::QuaternionOperations() { - -} - -void QuaternionOperations::normalize(const double* quaternion, - double* unitQuaternion) { - VectorOperations::normalize(quaternion, unitQuaternion, 4); -} - -float QuaternionOperations::norm(const double* quaternion) { - return VectorOperations::norm(quaternion, 4); -} - -void QuaternionOperations::fromDcm(const double dcm[][3], double* quaternion, - uint8_t *index) { - - double a[4]; - - a[0] = 1 + dcm[0][0] - dcm[1][1] - dcm[2][2]; - a[1] = 1 - dcm[0][0] + dcm[1][1] - dcm[2][2]; - a[2] = 1 - dcm[0][0] - dcm[1][1] + dcm[2][2]; - a[3] = 1 + dcm[0][0] + dcm[1][1] + dcm[2][2]; - - uint8_t maxAIndex = 0; - - VectorOperations::maxValue(a, 4, &maxAIndex); - - if (index != 0) { - *index = maxAIndex; - } - - switch (maxAIndex) { - case 0: - quaternion[0] = 0.5 * sqrt(a[0]); - quaternion[1] = (dcm[0][1] + dcm[1][0]) / (2 * sqrt(a[0])); - quaternion[2] = (dcm[0][2] + dcm[2][0]) / (2 * sqrt(a[0])); - quaternion[3] = (dcm[1][2] - dcm[2][1]) / (2 * sqrt(a[0])); - break; - case 1: - quaternion[0] = (dcm[0][1] + dcm[1][0]) / (2 * sqrt(a[1])); - quaternion[1] = 0.5 * sqrt(a[1]); - quaternion[2] = (dcm[1][2] + dcm[2][1]) / (2 * sqrt(a[1])); - quaternion[3] = (dcm[2][0] - dcm[0][2]) / (2 * sqrt(a[1])); - break; - case 2: - quaternion[0] = (dcm[0][2] + dcm[2][0]) / (2 * sqrt(a[2])); - quaternion[1] = (dcm[1][2] + dcm[2][1]) / (2 * sqrt(a[2])); - quaternion[2] = 0.5 * sqrt(a[2]); - quaternion[3] = (dcm[0][1] - dcm[1][0]) / (2 * sqrt(a[2])); - break; - case 3: - quaternion[0] = (dcm[1][2] - dcm[2][1]) / (2 * sqrt(a[3])); - quaternion[1] = (dcm[2][0] - dcm[0][2]) / (2 * sqrt(a[3])); - quaternion[2] = (dcm[0][1] - dcm[1][0]) / (2 * sqrt(a[3])); - quaternion[3] = 0.5 * sqrt(a[3]); - break; - } - -} - -void QuaternionOperations::toDcm(const double* quaternion, float dcm[][3]) { - dcm[0][0] = 2 - * (quaternion[0] * quaternion[0] + quaternion[3] * quaternion[3]) - - 1; - dcm[0][1] = 2 - * (quaternion[0] * quaternion[1] + quaternion[2] * quaternion[3]); - dcm[0][2] = 2 - * (quaternion[0] * quaternion[2] - quaternion[1] * quaternion[3]); - - dcm[1][0] = 2 - * (quaternion[0] * quaternion[1] - quaternion[2] * quaternion[3]); - dcm[1][1] = 2 - * (quaternion[1] * quaternion[1] + quaternion[3] * quaternion[3]) - - 1; - dcm[1][2] = 2 - * (quaternion[1] * quaternion[2] + quaternion[0] * quaternion[3]); - - dcm[2][0] = 2 - * (quaternion[0] * quaternion[2] + quaternion[1] * quaternion[3]); - dcm[2][1] = 2 - * (quaternion[1] * quaternion[2] - quaternion[0] * quaternion[3]); - dcm[2][2] = 2 - * (quaternion[2] * quaternion[2] + quaternion[3] * quaternion[3]) - - 1; -} - -void QuaternionOperations::normalize(double* quaternion) { - normalize(quaternion, quaternion); -} - -double QuaternionOperations::getAngle(const double* quaternion, bool abs) { - if (quaternion[3] >= 0) { - return 2 * acos(quaternion[3]); - } else { - if (abs) { - return 2 * acos(-quaternion[3]); - } else { - return -2 * acos(-quaternion[3]); - } - } -} +#include "QuaternionOperations.h" +#include "../../globalfunctions/math/VectorOperations.h" + +#include +#include +#include + +QuaternionOperations::~QuaternionOperations() { +} + +void QuaternionOperations::multiply(const double* q1, const double* q2, + double* q) { + double out[4]; + + out[0] = q1[3] * q2[0] + q1[2] * q2[1] - q1[1] * q2[2] + q1[0] * q2[3]; + out[1] = -q1[2] * q2[0] + q1[3] * q2[1] + q1[0] * q2[2] + q1[1] * q2[3]; + out[2] = q1[1] * q2[0] - q1[0] * q2[1] + q1[3] * q2[2] + q1[2] * q2[3]; + out[3] = -q1[0] * q2[0] - q1[1] * q2[1] - q1[2] * q2[2] + q1[3] * q2[3]; + + memcpy(q, out, 4 * sizeof(*q)); +} + +void QuaternionOperations::toDcm(const double* quaternion, double dcm[][3]) { + dcm[0][0] = 2 + * (quaternion[0] * quaternion[0] + quaternion[3] * quaternion[3]) + - 1; + dcm[0][1] = 2 + * (quaternion[0] * quaternion[1] + quaternion[2] * quaternion[3]); + dcm[0][2] = 2 + * (quaternion[0] * quaternion[2] - quaternion[1] * quaternion[3]); + + dcm[1][0] = 2 + * (quaternion[0] * quaternion[1] - quaternion[2] * quaternion[3]); + dcm[1][1] = 2 + * (quaternion[1] * quaternion[1] + quaternion[3] * quaternion[3]) + - 1; + dcm[1][2] = 2 + * (quaternion[1] * quaternion[2] + quaternion[0] * quaternion[3]); + + dcm[2][0] = 2 + * (quaternion[0] * quaternion[2] + quaternion[1] * quaternion[3]); + dcm[2][1] = 2 + * (quaternion[1] * quaternion[2] - quaternion[0] * quaternion[3]); + dcm[2][2] = 2 + * (quaternion[2] * quaternion[2] + quaternion[3] * quaternion[3]) + - 1; +} + +void QuaternionOperations::inverse(const double* quaternion, + double* inverseQuaternion) { + memcpy(inverseQuaternion, quaternion, 4 * sizeof(*quaternion)); + VectorOperations::mulScalar(inverseQuaternion, -1, + inverseQuaternion, 3); +} + +QuaternionOperations::QuaternionOperations() { + +} + +void QuaternionOperations::normalize(const double* quaternion, + double* unitQuaternion) { + VectorOperations::normalize(quaternion, unitQuaternion, 4); +} + +float QuaternionOperations::norm(const double* quaternion) { + return VectorOperations::norm(quaternion, 4); +} + +void QuaternionOperations::fromDcm(const double dcm[][3], double* quaternion, + uint8_t *index) { + + double a[4]; + + a[0] = 1 + dcm[0][0] - dcm[1][1] - dcm[2][2]; + a[1] = 1 - dcm[0][0] + dcm[1][1] - dcm[2][2]; + a[2] = 1 - dcm[0][0] - dcm[1][1] + dcm[2][2]; + a[3] = 1 + dcm[0][0] + dcm[1][1] + dcm[2][2]; + + uint8_t maxAIndex = 0; + + VectorOperations::maxValue(a, 4, &maxAIndex); + + if (index != 0) { + *index = maxAIndex; + } + + switch (maxAIndex) { + case 0: + quaternion[0] = 0.5 * sqrt(a[0]); + quaternion[1] = (dcm[0][1] + dcm[1][0]) / (2 * sqrt(a[0])); + quaternion[2] = (dcm[0][2] + dcm[2][0]) / (2 * sqrt(a[0])); + quaternion[3] = (dcm[1][2] - dcm[2][1]) / (2 * sqrt(a[0])); + break; + case 1: + quaternion[0] = (dcm[0][1] + dcm[1][0]) / (2 * sqrt(a[1])); + quaternion[1] = 0.5 * sqrt(a[1]); + quaternion[2] = (dcm[1][2] + dcm[2][1]) / (2 * sqrt(a[1])); + quaternion[3] = (dcm[2][0] - dcm[0][2]) / (2 * sqrt(a[1])); + break; + case 2: + quaternion[0] = (dcm[0][2] + dcm[2][0]) / (2 * sqrt(a[2])); + quaternion[1] = (dcm[1][2] + dcm[2][1]) / (2 * sqrt(a[2])); + quaternion[2] = 0.5 * sqrt(a[2]); + quaternion[3] = (dcm[0][1] - dcm[1][0]) / (2 * sqrt(a[2])); + break; + case 3: + quaternion[0] = (dcm[1][2] - dcm[2][1]) / (2 * sqrt(a[3])); + quaternion[1] = (dcm[2][0] - dcm[0][2]) / (2 * sqrt(a[3])); + quaternion[2] = (dcm[0][1] - dcm[1][0]) / (2 * sqrt(a[3])); + quaternion[3] = 0.5 * sqrt(a[3]); + break; + } + +} + +void QuaternionOperations::toDcm(const double* quaternion, float dcm[][3]) { + dcm[0][0] = 2 + * (quaternion[0] * quaternion[0] + quaternion[3] * quaternion[3]) + - 1; + dcm[0][1] = 2 + * (quaternion[0] * quaternion[1] + quaternion[2] * quaternion[3]); + dcm[0][2] = 2 + * (quaternion[0] * quaternion[2] - quaternion[1] * quaternion[3]); + + dcm[1][0] = 2 + * (quaternion[0] * quaternion[1] - quaternion[2] * quaternion[3]); + dcm[1][1] = 2 + * (quaternion[1] * quaternion[1] + quaternion[3] * quaternion[3]) + - 1; + dcm[1][2] = 2 + * (quaternion[1] * quaternion[2] + quaternion[0] * quaternion[3]); + + dcm[2][0] = 2 + * (quaternion[0] * quaternion[2] + quaternion[1] * quaternion[3]); + dcm[2][1] = 2 + * (quaternion[1] * quaternion[2] - quaternion[0] * quaternion[3]); + dcm[2][2] = 2 + * (quaternion[2] * quaternion[2] + quaternion[3] * quaternion[3]) + - 1; +} + +void QuaternionOperations::normalize(double* quaternion) { + normalize(quaternion, quaternion); +} + +double QuaternionOperations::getAngle(const double* quaternion, bool abs) { + if (quaternion[3] >= 0) { + return 2 * acos(quaternion[3]); + } else { + if (abs) { + return 2 * acos(-quaternion[3]); + } else { + return -2 * acos(-quaternion[3]); + } + } +} diff --git a/globalfunctions/timevalOperations.cpp b/globalfunctions/timevalOperations.cpp index 1da45d7b..aa921511 100644 --- a/globalfunctions/timevalOperations.cpp +++ b/globalfunctions/timevalOperations.cpp @@ -1,99 +1,99 @@ -#include - -timeval& operator+=(timeval& lhs, const timeval& rhs) { - int64_t sum = lhs.tv_sec * 1000000. + lhs.tv_usec; - sum += rhs.tv_sec * 1000000. + rhs.tv_usec; - lhs.tv_sec = sum / 1000000; - lhs.tv_usec = sum - lhs.tv_sec * 1000000; - return lhs; -} - -timeval operator+(timeval lhs, const timeval& rhs) { - lhs += rhs; - return lhs; -} - -timeval& operator-=(timeval& lhs, const timeval& rhs) { - int64_t sum = lhs.tv_sec * 1000000. + lhs.tv_usec; - sum -= rhs.tv_sec * 1000000. + rhs.tv_usec; - lhs.tv_sec = sum / 1000000; - lhs.tv_usec = sum - lhs.tv_sec * 1000000; - return lhs; -} - -timeval operator-(timeval lhs, const timeval& rhs) { - lhs -= rhs; - return lhs; -} - -double operator/(const timeval& lhs, const timeval& rhs) { - double lhs64 = lhs.tv_sec * 1000000. + lhs.tv_usec; - double rhs64 = rhs.tv_sec * 1000000. + rhs.tv_usec; - return lhs64 / rhs64; -} - -timeval& operator/=(timeval& lhs, double scalar) { - int64_t product = lhs.tv_sec * 1000000. + lhs.tv_usec; - product /= scalar; - lhs.tv_sec = product / 1000000; - lhs.tv_usec = product - lhs.tv_sec * 1000000; - return lhs; -} - -timeval operator/(timeval lhs, double scalar) { - lhs /= scalar; - return lhs; -} - -timeval& operator*=(timeval& lhs, double scalar) { - int64_t product = lhs.tv_sec * 1000000. + lhs.tv_usec; - product *= scalar; - lhs.tv_sec = product / 1000000; - lhs.tv_usec = product - lhs.tv_sec * 1000000; - return lhs; -} - -timeval operator*(timeval lhs, double scalar) { - lhs *= scalar; - return lhs; -} - -timeval operator*(double scalar, timeval rhs) { - rhs *= scalar; - return rhs; -} - -bool operator==(const timeval& lhs, const timeval& rhs) { - int64_t lhs64 = lhs.tv_sec * 1000000. + lhs.tv_usec; - int64_t rhs64 = rhs.tv_sec * 1000000. + rhs.tv_usec; - return lhs64 == rhs64; -} -bool operator!=(const timeval& lhs, const timeval& rhs) { - return !operator==(lhs, rhs); -} -bool operator<(const timeval& lhs, const timeval& rhs) { - int64_t lhs64 = lhs.tv_sec * 1000000. + lhs.tv_usec; - int64_t rhs64 = rhs.tv_sec * 1000000. + rhs.tv_usec; - return lhs64 < rhs64; -} -bool operator>(const timeval& lhs, const timeval& rhs) { - return operator<(rhs, lhs); -} -bool operator<=(const timeval& lhs, const timeval& rhs) { - return !operator>(lhs, rhs); -} -bool operator>=(const timeval& lhs, const timeval& rhs) { - return !operator<(lhs, rhs); -} - -double timevalOperations::toDouble(const timeval timeval) { - double result = timeval.tv_sec * 1000000. + timeval.tv_usec; - return result / 1000000.; -} - -timeval timevalOperations::toTimeval(const double seconds) { - timeval tval; - tval.tv_sec = seconds; - tval.tv_usec = seconds *(double) 1e6 - (tval.tv_sec *1e6); - return tval; -} +#include "../globalfunctions/timevalOperations.h" + +timeval& operator+=(timeval& lhs, const timeval& rhs) { + int64_t sum = lhs.tv_sec * 1000000. + lhs.tv_usec; + sum += rhs.tv_sec * 1000000. + rhs.tv_usec; + lhs.tv_sec = sum / 1000000; + lhs.tv_usec = sum - lhs.tv_sec * 1000000; + return lhs; +} + +timeval operator+(timeval lhs, const timeval& rhs) { + lhs += rhs; + return lhs; +} + +timeval& operator-=(timeval& lhs, const timeval& rhs) { + int64_t sum = lhs.tv_sec * 1000000. + lhs.tv_usec; + sum -= rhs.tv_sec * 1000000. + rhs.tv_usec; + lhs.tv_sec = sum / 1000000; + lhs.tv_usec = sum - lhs.tv_sec * 1000000; + return lhs; +} + +timeval operator-(timeval lhs, const timeval& rhs) { + lhs -= rhs; + return lhs; +} + +double operator/(const timeval& lhs, const timeval& rhs) { + double lhs64 = lhs.tv_sec * 1000000. + lhs.tv_usec; + double rhs64 = rhs.tv_sec * 1000000. + rhs.tv_usec; + return lhs64 / rhs64; +} + +timeval& operator/=(timeval& lhs, double scalar) { + int64_t product = lhs.tv_sec * 1000000. + lhs.tv_usec; + product /= scalar; + lhs.tv_sec = product / 1000000; + lhs.tv_usec = product - lhs.tv_sec * 1000000; + return lhs; +} + +timeval operator/(timeval lhs, double scalar) { + lhs /= scalar; + return lhs; +} + +timeval& operator*=(timeval& lhs, double scalar) { + int64_t product = lhs.tv_sec * 1000000. + lhs.tv_usec; + product *= scalar; + lhs.tv_sec = product / 1000000; + lhs.tv_usec = product - lhs.tv_sec * 1000000; + return lhs; +} + +timeval operator*(timeval lhs, double scalar) { + lhs *= scalar; + return lhs; +} + +timeval operator*(double scalar, timeval rhs) { + rhs *= scalar; + return rhs; +} + +bool operator==(const timeval& lhs, const timeval& rhs) { + int64_t lhs64 = lhs.tv_sec * 1000000. + lhs.tv_usec; + int64_t rhs64 = rhs.tv_sec * 1000000. + rhs.tv_usec; + return lhs64 == rhs64; +} +bool operator!=(const timeval& lhs, const timeval& rhs) { + return !operator==(lhs, rhs); +} +bool operator<(const timeval& lhs, const timeval& rhs) { + int64_t lhs64 = lhs.tv_sec * 1000000. + lhs.tv_usec; + int64_t rhs64 = rhs.tv_sec * 1000000. + rhs.tv_usec; + return lhs64 < rhs64; +} +bool operator>(const timeval& lhs, const timeval& rhs) { + return operator<(rhs, lhs); +} +bool operator<=(const timeval& lhs, const timeval& rhs) { + return !operator>(lhs, rhs); +} +bool operator>=(const timeval& lhs, const timeval& rhs) { + return !operator<(lhs, rhs); +} + +double timevalOperations::toDouble(const timeval timeval) { + double result = timeval.tv_sec * 1000000. + timeval.tv_usec; + return result / 1000000.; +} + +timeval timevalOperations::toTimeval(const double seconds) { + timeval tval; + tval.tv_sec = seconds; + tval.tv_usec = seconds *(double) 1e6 - (tval.tv_sec *1e6); + return tval; +} diff --git a/health/HasHealthIF.h b/health/HasHealthIF.h index dd27fe39..9ef8c1e9 100644 --- a/health/HasHealthIF.h +++ b/health/HasHealthIF.h @@ -1,50 +1,50 @@ -#ifndef HASHEALTHIF_H_ -#define HASHEALTHIF_H_ - -#include -#include -#include - -class HasHealthIF { -public: - - typedef enum { - HEALTHY = 1, FAULTY = 0, EXTERNAL_CONTROL = 2, NEEDS_RECOVERY = 3, PERMANENT_FAULTY = 4 - } HealthState; - - static const uint8_t INTERFACE_ID = CLASS_ID::HAS_HEALTH_IF; - static const ReturnValue_t OBJECT_NOT_HEALTHY = MAKE_RETURN_CODE(1); - static const ReturnValue_t INVALID_HEALTH_STATE = MAKE_RETURN_CODE(2); - - static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SYSTEM_MANAGER_1; - static const Event HEALTH_INFO = MAKE_EVENT(6, SEVERITY::INFO); - static const Event CHILD_CHANGED_HEALTH = MAKE_EVENT(7, SEVERITY::INFO); - static const Event CHILD_PROBLEMS = MAKE_EVENT(8, SEVERITY::LOW); - static const Event OVERWRITING_HEALTH = MAKE_EVENT(9, SEVERITY::LOW); //!< Assembly overwrites health information of children to keep satellite alive. - static const Event TRYING_RECOVERY = MAKE_EVENT(10, SEVERITY::MEDIUM); //!< Someone starts a recovery of a component (typically power-cycle). No parameters. - static const Event RECOVERY_STEP = MAKE_EVENT(11, SEVERITY::MEDIUM); //!< Recovery is ongoing. Comes twice during recovery. P1: 0 for the first, 1 for the second event. P2: 0 - static const Event RECOVERY_DONE = MAKE_EVENT(12, SEVERITY::MEDIUM); //!< Recovery was completed. Not necessarily successful. No parameters. - - virtual ~HasHealthIF() { - } - - virtual MessageQueueId_t getCommandQueue() const = 0; - - /** - * set the Health State - * - * The parent will be informed, if the Health changes - * - * @param health - */ - virtual ReturnValue_t setHealth(HealthState health) = 0; - - /** - * get Health State - * - * @return Health State of the object - */ - virtual HasHealthIF::HealthState getHealth() = 0; -}; - -#endif /* HASHEALTHIF_H_ */ +#ifndef HASHEALTHIF_H_ +#define HASHEALTHIF_H_ + +#include "../events/Event.h" +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../ipc/MessageQueueSenderIF.h" + +class HasHealthIF { +public: + + typedef enum { + HEALTHY = 1, FAULTY = 0, EXTERNAL_CONTROL = 2, NEEDS_RECOVERY = 3, PERMANENT_FAULTY = 4 + } HealthState; + + static const uint8_t INTERFACE_ID = CLASS_ID::HAS_HEALTH_IF; + static const ReturnValue_t OBJECT_NOT_HEALTHY = MAKE_RETURN_CODE(1); + static const ReturnValue_t INVALID_HEALTH_STATE = MAKE_RETURN_CODE(2); + + static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SYSTEM_MANAGER_1; + static const Event HEALTH_INFO = MAKE_EVENT(6, SEVERITY::INFO); + static const Event CHILD_CHANGED_HEALTH = MAKE_EVENT(7, SEVERITY::INFO); + static const Event CHILD_PROBLEMS = MAKE_EVENT(8, SEVERITY::LOW); + static const Event OVERWRITING_HEALTH = MAKE_EVENT(9, SEVERITY::LOW); //!< Assembly overwrites health information of children to keep satellite alive. + static const Event TRYING_RECOVERY = MAKE_EVENT(10, SEVERITY::MEDIUM); //!< Someone starts a recovery of a component (typically power-cycle). No parameters. + static const Event RECOVERY_STEP = MAKE_EVENT(11, SEVERITY::MEDIUM); //!< Recovery is ongoing. Comes twice during recovery. P1: 0 for the first, 1 for the second event. P2: 0 + static const Event RECOVERY_DONE = MAKE_EVENT(12, SEVERITY::MEDIUM); //!< Recovery was completed. Not necessarily successful. No parameters. + + virtual ~HasHealthIF() { + } + + virtual MessageQueueId_t getCommandQueue() const = 0; + + /** + * set the Health State + * + * The parent will be informed, if the Health changes + * + * @param health + */ + virtual ReturnValue_t setHealth(HealthState health) = 0; + + /** + * get Health State + * + * @return Health State of the object + */ + virtual HasHealthIF::HealthState getHealth() = 0; +}; + +#endif /* HASHEALTHIF_H_ */ diff --git a/health/HealthHelper.cpp b/health/HealthHelper.cpp index ba8504c2..800d6e36 100644 --- a/health/HealthHelper.cpp +++ b/health/HealthHelper.cpp @@ -1,105 +1,105 @@ -#include -#include - -HealthHelper::HealthHelper(HasHealthIF* owner, object_id_t objectId) : - objectId(objectId), owner(owner) { -} - -HealthHelper::~HealthHelper() { -} - -ReturnValue_t HealthHelper::handleHealthCommand(CommandMessage* message) { - switch (message->getCommand()) { - case HealthMessage::HEALTH_SET: - handleSetHealthCommand(message); - return HasReturnvaluesIF::RETURN_OK; - case HealthMessage::HEALTH_ANNOUNCE: { - eventSender->forwardEvent(HasHealthIF::HEALTH_INFO, getHealth(), - getHealth()); - } - return HasReturnvaluesIF::RETURN_OK; - default: - return HasReturnvaluesIF::RETURN_FAILED; - } -} - -HasHealthIF::HealthState HealthHelper::getHealth() { - return healthTable->getHealth(objectId); -} - -ReturnValue_t HealthHelper::initialize(MessageQueueId_t parentQueue) { - setParentQueue(parentQueue); - return initialize(); -} - -void HealthHelper::setParentQueue(MessageQueueId_t parentQueue) { - this->parentQueue = parentQueue; -} - -ReturnValue_t HealthHelper::initialize() { - healthTable = objectManager->get(objects::HEALTH_TABLE); - eventSender = objectManager->get(objectId); - - if (healthTable == nullptr) { - sif::error << "HealthHelper::initialize: Health table object needs" - "to be created in factory." << std::endl; - return ObjectManagerIF::CHILD_INIT_FAILED; - } - - if(eventSender == nullptr) { - sif::error << "HealthHelper::initialize: Owner has to implement " - "ReportingProxyIF." << std::endl; - return ObjectManagerIF::CHILD_INIT_FAILED; - } - - ReturnValue_t result = healthTable->registerObject(objectId, - HasHealthIF::HEALTHY); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - return HasReturnvaluesIF::RETURN_OK; -} - -void HealthHelper::setHealth(HasHealthIF::HealthState health) { - HasHealthIF::HealthState oldHealth = getHealth(); - eventSender->forwardEvent(HasHealthIF::HEALTH_INFO, health, oldHealth); - if (health != oldHealth) { - healthTable->setHealth(objectId, health); - informParent(health, oldHealth); - } -} - -void HealthHelper::informParent(HasHealthIF::HealthState health, - HasHealthIF::HealthState oldHealth) { - if (parentQueue == MessageQueueMessageIF::NO_QUEUE) { - return; - } - CommandMessage information; - HealthMessage::setHealthMessage(&information, HealthMessage::HEALTH_INFO, - health, oldHealth); - if (MessageQueueSenderIF::sendMessage(parentQueue, &information, - owner->getCommandQueue()) != HasReturnvaluesIF::RETURN_OK) { - sif::debug << "HealthHelper::informParent: sending health reply failed." - << std::endl; - } -} - -void HealthHelper::handleSetHealthCommand(CommandMessage* command) { - ReturnValue_t result = owner->setHealth(HealthMessage::getHealth(command)); - if (command->getSender() == MessageQueueMessageIF::NO_QUEUE) { - return; - } - CommandMessage reply; - if (result == HasReturnvaluesIF::RETURN_OK) { - HealthMessage::setHealthMessage(&reply, - HealthMessage::REPLY_HEALTH_SET); - } else { - reply.setReplyRejected(result, command->getCommand()); - } - if (MessageQueueSenderIF::sendMessage(command->getSender(), &reply, - owner->getCommandQueue()) != HasReturnvaluesIF::RETURN_OK) { - sif::debug << "HealthHelper::handleHealthCommand: sending health " - "reply failed." << std::endl; - - } -} +#include "../health/HealthHelper.h" +#include "../serviceinterface/ServiceInterfaceStream.h" + +HealthHelper::HealthHelper(HasHealthIF* owner, object_id_t objectId) : + objectId(objectId), owner(owner) { +} + +HealthHelper::~HealthHelper() { +} + +ReturnValue_t HealthHelper::handleHealthCommand(CommandMessage* message) { + switch (message->getCommand()) { + case HealthMessage::HEALTH_SET: + handleSetHealthCommand(message); + return HasReturnvaluesIF::RETURN_OK; + case HealthMessage::HEALTH_ANNOUNCE: { + eventSender->forwardEvent(HasHealthIF::HEALTH_INFO, getHealth(), + getHealth()); + } + return HasReturnvaluesIF::RETURN_OK; + default: + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +HasHealthIF::HealthState HealthHelper::getHealth() { + return healthTable->getHealth(objectId); +} + +ReturnValue_t HealthHelper::initialize(MessageQueueId_t parentQueue) { + setParentQueue(parentQueue); + return initialize(); +} + +void HealthHelper::setParentQueue(MessageQueueId_t parentQueue) { + this->parentQueue = parentQueue; +} + +ReturnValue_t HealthHelper::initialize() { + healthTable = objectManager->get(objects::HEALTH_TABLE); + eventSender = objectManager->get(objectId); + + if (healthTable == nullptr) { + sif::error << "HealthHelper::initialize: Health table object needs" + "to be created in factory." << std::endl; + return ObjectManagerIF::CHILD_INIT_FAILED; + } + + if(eventSender == nullptr) { + sif::error << "HealthHelper::initialize: Owner has to implement " + "ReportingProxyIF." << std::endl; + return ObjectManagerIF::CHILD_INIT_FAILED; + } + + ReturnValue_t result = healthTable->registerObject(objectId, + HasHealthIF::HEALTHY); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return HasReturnvaluesIF::RETURN_OK; +} + +void HealthHelper::setHealth(HasHealthIF::HealthState health) { + HasHealthIF::HealthState oldHealth = getHealth(); + eventSender->forwardEvent(HasHealthIF::HEALTH_INFO, health, oldHealth); + if (health != oldHealth) { + healthTable->setHealth(objectId, health); + informParent(health, oldHealth); + } +} + +void HealthHelper::informParent(HasHealthIF::HealthState health, + HasHealthIF::HealthState oldHealth) { + if (parentQueue == MessageQueueMessageIF::NO_QUEUE) { + return; + } + CommandMessage information; + HealthMessage::setHealthMessage(&information, HealthMessage::HEALTH_INFO, + health, oldHealth); + if (MessageQueueSenderIF::sendMessage(parentQueue, &information, + owner->getCommandQueue()) != HasReturnvaluesIF::RETURN_OK) { + sif::debug << "HealthHelper::informParent: sending health reply failed." + << std::endl; + } +} + +void HealthHelper::handleSetHealthCommand(CommandMessage* command) { + ReturnValue_t result = owner->setHealth(HealthMessage::getHealth(command)); + if (command->getSender() == MessageQueueMessageIF::NO_QUEUE) { + return; + } + CommandMessage reply; + if (result == HasReturnvaluesIF::RETURN_OK) { + HealthMessage::setHealthMessage(&reply, + HealthMessage::REPLY_HEALTH_SET); + } else { + reply.setReplyRejected(result, command->getCommand()); + } + if (MessageQueueSenderIF::sendMessage(command->getSender(), &reply, + owner->getCommandQueue()) != HasReturnvaluesIF::RETURN_OK) { + sif::debug << "HealthHelper::handleHealthCommand: sending health " + "reply failed." << std::endl; + + } +} diff --git a/health/HealthHelper.h b/health/HealthHelper.h index e112ad2c..99bb501f 100644 --- a/health/HealthHelper.h +++ b/health/HealthHelper.h @@ -1,121 +1,121 @@ -#ifndef FRAMEWORK_HEALTH_HEALTHHELPER_H_ -#define FRAMEWORK_HEALTH_HEALTHHELPER_H_ - -#include -#include -#include -#include -#include -#include -#include -#include - -/** - * Helper class for Objects that implement HasHealthIF - * - * It takes care of registering with the Health Table as well as handling health commands - * (including replying to the sender) and updating the Health Table. - * - * If a parent is set in the ctor, the parent will be informed with a @c HEALTH_INFO message - * about changes in the health state. Note that a @c HEALTH_INFO is only generated if the Health - * changes, not for all @c HEALTH_SET commands received. - * - * It does NOT handle @c HEALTH_INFO messages - */ -class HealthHelper { -public: - - /** - * ctor - * - * @param owner - * @param objectId the object Id to use when communication with the HealthTable - */ - HealthHelper(HasHealthIF* owner, object_id_t objectId); - - virtual ~HealthHelper(); - - /** - * Pointer to the Health Table - * - * only valid after initialize() has been called - */ - HealthTableIF *healthTable = nullptr; - - /** - * Proxy to forward events. - */ - EventReportingProxyIF* eventSender = nullptr; - - /** - * Try to handle the message. - * - * This function handles @c HEALTH_SET and @c HEALTH_READ commands. - * it updates the Health Table and generates a reply to the sender. - * - * @param message - * @return - * -@c RETURN_OK if the message was handled - * -@c RETURN_FAILED if the message could not be handled (ie it was not a @c HEALTH_SET or @c HEALTH_READ message) - */ - ReturnValue_t handleHealthCommand(CommandMessage *message); - - /** - * set the Health State - * - * The parent will be informed, if the Health changes - * - * @param health - */ - void setHealth(HasHealthIF::HealthState health); - - /** - * get Health State - * - * @return Health State of the object - */ - HasHealthIF::HealthState getHealth(); - - /** - * @param parentQueue the Queue id of the parent object. Set to 0 if no parent present - */ - void setParentQueue(MessageQueueId_t parentQueue); - - /** - * - * @param parentQueue the Queue id of the parent object. Set to 0 if no parent present - * @return - * -@c RETURN_OK if the Health Table was found and the object could be registered - * -@c RETURN_FAILED else - */ - ReturnValue_t initialize(MessageQueueId_t parentQueue ); - - ReturnValue_t initialize(); - -private: - /** - * the object id to use when communicating with the Health Table - */ - object_id_t objectId; - - /** - * The Queue of the parent - */ - MessageQueueId_t parentQueue = MessageQueueIF::NO_QUEUE; - - /** - * The one using the healthHelper. - */ - HasHealthIF* owner; - - /** - * if the #parentQueue is not NULL, a @c HEALTH_INFO message will be sent to this queue - * @param health the health is passed as parameter so that the number of calls to the health table can be minimized - * @param oldHealth information of the previous health state. - */ - void informParent(HasHealthIF::HealthState health, HasHealthIF::HealthState oldHealth); - - void handleSetHealthCommand(CommandMessage *message); -}; - -#endif /* HEALTHHELPER_H_ */ +#ifndef FRAMEWORK_HEALTH_HEALTHHELPER_H_ +#define FRAMEWORK_HEALTH_HEALTHHELPER_H_ + +#include "../events/EventManagerIF.h" +#include "../events/EventReportingProxyIF.h" +#include "../health/HasHealthIF.h" +#include "../health/HealthMessage.h" +#include "../health/HealthTableIF.h" +#include "../ipc/MessageQueueIF.h" +#include "../objectmanager/ObjectManagerIF.h" +#include "../returnvalues/HasReturnvaluesIF.h" + +/** + * Helper class for Objects that implement HasHealthIF + * + * It takes care of registering with the Health Table as well as handling health commands + * (including replying to the sender) and updating the Health Table. + * + * If a parent is set in the ctor, the parent will be informed with a @c HEALTH_INFO message + * about changes in the health state. Note that a @c HEALTH_INFO is only generated if the Health + * changes, not for all @c HEALTH_SET commands received. + * + * It does NOT handle @c HEALTH_INFO messages + */ +class HealthHelper { +public: + + /** + * ctor + * + * @param owner + * @param objectId the object Id to use when communication with the HealthTable + */ + HealthHelper(HasHealthIF* owner, object_id_t objectId); + + virtual ~HealthHelper(); + + /** + * Pointer to the Health Table + * + * only valid after initialize() has been called + */ + HealthTableIF *healthTable = nullptr; + + /** + * Proxy to forward events. + */ + EventReportingProxyIF* eventSender = nullptr; + + /** + * Try to handle the message. + * + * This function handles @c HEALTH_SET and @c HEALTH_READ commands. + * it updates the Health Table and generates a reply to the sender. + * + * @param message + * @return + * -@c RETURN_OK if the message was handled + * -@c RETURN_FAILED if the message could not be handled (ie it was not a @c HEALTH_SET or @c HEALTH_READ message) + */ + ReturnValue_t handleHealthCommand(CommandMessage *message); + + /** + * set the Health State + * + * The parent will be informed, if the Health changes + * + * @param health + */ + void setHealth(HasHealthIF::HealthState health); + + /** + * get Health State + * + * @return Health State of the object + */ + HasHealthIF::HealthState getHealth(); + + /** + * @param parentQueue the Queue id of the parent object. Set to 0 if no parent present + */ + void setParentQueue(MessageQueueId_t parentQueue); + + /** + * + * @param parentQueue the Queue id of the parent object. Set to 0 if no parent present + * @return + * -@c RETURN_OK if the Health Table was found and the object could be registered + * -@c RETURN_FAILED else + */ + ReturnValue_t initialize(MessageQueueId_t parentQueue ); + + ReturnValue_t initialize(); + +private: + /** + * the object id to use when communicating with the Health Table + */ + object_id_t objectId; + + /** + * The Queue of the parent + */ + MessageQueueId_t parentQueue = MessageQueueIF::NO_QUEUE; + + /** + * The one using the healthHelper. + */ + HasHealthIF* owner; + + /** + * if the #parentQueue is not NULL, a @c HEALTH_INFO message will be sent to this queue + * @param health the health is passed as parameter so that the number of calls to the health table can be minimized + * @param oldHealth information of the previous health state. + */ + void informParent(HasHealthIF::HealthState health, HasHealthIF::HealthState oldHealth); + + void handleSetHealthCommand(CommandMessage *message); +}; + +#endif /* HEALTHHELPER_H_ */ diff --git a/health/HealthMessage.cpp b/health/HealthMessage.cpp index 768dea46..c5f5b733 100644 --- a/health/HealthMessage.cpp +++ b/health/HealthMessage.cpp @@ -1,28 +1,28 @@ -#include - -void HealthMessage::setHealthMessage(CommandMessage* message, Command_t command, - HasHealthIF::HealthState health, HasHealthIF::HealthState oldHealth) { - message->setCommand(command); - message->setParameter(health); - message->setParameter2(oldHealth); -} - -void HealthMessage::setHealthMessage(CommandMessage* message, Command_t command) { - message->setCommand(command); -} - -HasHealthIF::HealthState HealthMessage::getHealth(const CommandMessage* message) { - return (HasHealthIF::HealthState) message->getParameter(); -} - -void HealthMessage::clear(CommandMessage* message) { - message->setCommand(CommandMessage::CMD_NONE); -} - -HealthMessage::HealthMessage() { -} - -HasHealthIF::HealthState HealthMessage::getOldHealth( - const CommandMessage* message) { - return (HasHealthIF::HealthState) message->getParameter2(); -} +#include "../health/HealthMessage.h" + +void HealthMessage::setHealthMessage(CommandMessage* message, Command_t command, + HasHealthIF::HealthState health, HasHealthIF::HealthState oldHealth) { + message->setCommand(command); + message->setParameter(health); + message->setParameter2(oldHealth); +} + +void HealthMessage::setHealthMessage(CommandMessage* message, Command_t command) { + message->setCommand(command); +} + +HasHealthIF::HealthState HealthMessage::getHealth(const CommandMessage* message) { + return (HasHealthIF::HealthState) message->getParameter(); +} + +void HealthMessage::clear(CommandMessage* message) { + message->setCommand(CommandMessage::CMD_NONE); +} + +HealthMessage::HealthMessage() { +} + +HasHealthIF::HealthState HealthMessage::getOldHealth( + const CommandMessage* message) { + return (HasHealthIF::HealthState) message->getParameter2(); +} diff --git a/health/HealthMessage.h b/health/HealthMessage.h index 13e79b88..d16c65db 100644 --- a/health/HealthMessage.h +++ b/health/HealthMessage.h @@ -1,30 +1,30 @@ -#ifndef HEALTHMESSAGE_H_ -#define HEALTHMESSAGE_H_ - -#include -#include - -class HealthMessage { -public: - static const uint8_t MESSAGE_ID = messagetypes::HEALTH_COMMAND; - static const Command_t HEALTH_SET = MAKE_COMMAND_ID(1);//REPLY_COMMAND_OK/REPLY_REJECTED - static const Command_t HEALTH_ANNOUNCE = MAKE_COMMAND_ID(3); //NO REPLY! - static const Command_t HEALTH_INFO = MAKE_COMMAND_ID(5); - static const Command_t REPLY_HEALTH_SET = MAKE_COMMAND_ID(6); - - static void setHealthMessage(CommandMessage *message, Command_t command, - HasHealthIF::HealthState health, HasHealthIF::HealthState oldHealth = HasHealthIF::FAULTY); - - static void setHealthMessage(CommandMessage *message, Command_t command); - - static HasHealthIF::HealthState getHealth(const CommandMessage *message); - - static HasHealthIF::HealthState getOldHealth(const CommandMessage *message); - - static void clear(CommandMessage *message); - -private: - HealthMessage(); -}; - -#endif /* HEALTHMESSAGE_H_ */ +#ifndef HEALTHMESSAGE_H_ +#define HEALTHMESSAGE_H_ + +#include "../health/HasHealthIF.h" +#include "../ipc/CommandMessage.h" + +class HealthMessage { +public: + static const uint8_t MESSAGE_ID = messagetypes::HEALTH_COMMAND; + static const Command_t HEALTH_SET = MAKE_COMMAND_ID(1);//REPLY_COMMAND_OK/REPLY_REJECTED + static const Command_t HEALTH_ANNOUNCE = MAKE_COMMAND_ID(3); //NO REPLY! + static const Command_t HEALTH_INFO = MAKE_COMMAND_ID(5); + static const Command_t REPLY_HEALTH_SET = MAKE_COMMAND_ID(6); + + static void setHealthMessage(CommandMessage *message, Command_t command, + HasHealthIF::HealthState health, HasHealthIF::HealthState oldHealth = HasHealthIF::FAULTY); + + static void setHealthMessage(CommandMessage *message, Command_t command); + + static HasHealthIF::HealthState getHealth(const CommandMessage *message); + + static HasHealthIF::HealthState getOldHealth(const CommandMessage *message); + + static void clear(CommandMessage *message); + +private: + HealthMessage(); +}; + +#endif /* HEALTHMESSAGE_H_ */ diff --git a/health/HealthTable.cpp b/health/HealthTable.cpp index e11dcd97..88db89b1 100644 --- a/health/HealthTable.cpp +++ b/health/HealthTable.cpp @@ -1,100 +1,100 @@ -#include -#include -#include - -HealthTable::HealthTable(object_id_t objectid) : - SystemObject(objectid) { - mutex = MutexFactory::instance()->createMutex();; - - mapIterator = healthMap.begin(); -} - -HealthTable::~HealthTable() { - MutexFactory::instance()->deleteMutex(mutex); -} - -ReturnValue_t HealthTable::registerObject(object_id_t object, - HasHealthIF::HealthState initilialState) { - if (healthMap.count(object) != 0) { - return HasReturnvaluesIF::RETURN_FAILED; - } - healthMap.insert( - std::pair(object, - initilialState)); - return HasReturnvaluesIF::RETURN_OK; -} - -void HealthTable::setHealth(object_id_t object, - HasHealthIF::HealthState newState) { - mutex->lockMutex(MutexIF::BLOCKING); - HealthMap::iterator iter = healthMap.find(object); - if (iter != healthMap.end()) { - iter->second = newState; - } - mutex->unlockMutex(); -} - -HasHealthIF::HealthState HealthTable::getHealth(object_id_t object) { - HasHealthIF::HealthState state = HasHealthIF::HEALTHY; - mutex->lockMutex(MutexIF::BLOCKING); - HealthMap::iterator iter = healthMap.find(object); - if (iter != healthMap.end()) { - state = iter->second; - } - mutex->unlockMutex(); - return state; -} - -uint32_t HealthTable::getPrintSize() { - mutex->lockMutex(MutexIF::BLOCKING); - uint32_t size = healthMap.size() * 5 + 2; - mutex->unlockMutex(); - return size; -} - -bool HealthTable::hasHealth(object_id_t object) { - bool exits = false; - mutex->lockMutex(MutexIF::BLOCKING); - HealthMap::iterator iter = healthMap.find(object); - if (iter != healthMap.end()) { - exits = true; - } - mutex->unlockMutex(); - return exits; -} - -void HealthTable::printAll(uint8_t* pointer, size_t maxSize) { - mutex->lockMutex(MutexIF::BLOCKING); - size_t size = 0; - uint16_t count = healthMap.size(); - ReturnValue_t result = SerializeAdapter::serialize(&count, - &pointer, &size, maxSize, SerializeIF::Endianness::BIG); - HealthMap::iterator iter; - for (iter = healthMap.begin(); - iter != healthMap.end() && result == HasReturnvaluesIF::RETURN_OK; - ++iter) { - result = SerializeAdapter::serialize(&iter->first, - &pointer, &size, maxSize, SerializeIF::Endianness::BIG); - uint8_t health = iter->second; - result = SerializeAdapter::serialize(&health, &pointer, &size, - maxSize, SerializeIF::Endianness::BIG); - } - mutex->unlockMutex(); -} - -ReturnValue_t HealthTable::iterate( - std::pair *value, bool reset) { - ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; - mutex->lockMutex(MutexIF::BLOCKING); - if (reset) { - mapIterator = healthMap.begin(); - } - if (mapIterator == healthMap.end()) { - result = HasReturnvaluesIF::RETURN_FAILED; - } - *value = *mapIterator; - mapIterator++; - mutex->unlockMutex(); - - return result; -} +#include "../health/HealthTable.h" +#include "../serialize/SerializeAdapter.h" +#include "../ipc/MutexFactory.h" + +HealthTable::HealthTable(object_id_t objectid) : + SystemObject(objectid) { + mutex = MutexFactory::instance()->createMutex();; + + mapIterator = healthMap.begin(); +} + +HealthTable::~HealthTable() { + MutexFactory::instance()->deleteMutex(mutex); +} + +ReturnValue_t HealthTable::registerObject(object_id_t object, + HasHealthIF::HealthState initilialState) { + if (healthMap.count(object) != 0) { + return HasReturnvaluesIF::RETURN_FAILED; + } + healthMap.insert( + std::pair(object, + initilialState)); + return HasReturnvaluesIF::RETURN_OK; +} + +void HealthTable::setHealth(object_id_t object, + HasHealthIF::HealthState newState) { + mutex->lockMutex(MutexIF::BLOCKING); + HealthMap::iterator iter = healthMap.find(object); + if (iter != healthMap.end()) { + iter->second = newState; + } + mutex->unlockMutex(); +} + +HasHealthIF::HealthState HealthTable::getHealth(object_id_t object) { + HasHealthIF::HealthState state = HasHealthIF::HEALTHY; + mutex->lockMutex(MutexIF::BLOCKING); + HealthMap::iterator iter = healthMap.find(object); + if (iter != healthMap.end()) { + state = iter->second; + } + mutex->unlockMutex(); + return state; +} + +uint32_t HealthTable::getPrintSize() { + mutex->lockMutex(MutexIF::BLOCKING); + uint32_t size = healthMap.size() * 5 + 2; + mutex->unlockMutex(); + return size; +} + +bool HealthTable::hasHealth(object_id_t object) { + bool exits = false; + mutex->lockMutex(MutexIF::BLOCKING); + HealthMap::iterator iter = healthMap.find(object); + if (iter != healthMap.end()) { + exits = true; + } + mutex->unlockMutex(); + return exits; +} + +void HealthTable::printAll(uint8_t* pointer, size_t maxSize) { + mutex->lockMutex(MutexIF::BLOCKING); + size_t size = 0; + uint16_t count = healthMap.size(); + ReturnValue_t result = SerializeAdapter::serialize(&count, + &pointer, &size, maxSize, SerializeIF::Endianness::BIG); + HealthMap::iterator iter; + for (iter = healthMap.begin(); + iter != healthMap.end() && result == HasReturnvaluesIF::RETURN_OK; + ++iter) { + result = SerializeAdapter::serialize(&iter->first, + &pointer, &size, maxSize, SerializeIF::Endianness::BIG); + uint8_t health = iter->second; + result = SerializeAdapter::serialize(&health, &pointer, &size, + maxSize, SerializeIF::Endianness::BIG); + } + mutex->unlockMutex(); +} + +ReturnValue_t HealthTable::iterate( + std::pair *value, bool reset) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + mutex->lockMutex(MutexIF::BLOCKING); + if (reset) { + mapIterator = healthMap.begin(); + } + if (mapIterator == healthMap.end()) { + result = HasReturnvaluesIF::RETURN_FAILED; + } + *value = *mapIterator; + mapIterator++; + mutex->unlockMutex(); + + return result; +} diff --git a/health/HealthTable.h b/health/HealthTable.h index 6f1ac829..5ed45041 100644 --- a/health/HealthTable.h +++ b/health/HealthTable.h @@ -1,35 +1,35 @@ -#ifndef FRAMEWORK_HEALTH_HEALTHTABLE_H_ -#define FRAMEWORK_HEALTH_HEALTHTABLE_H_ - -#include -#include -#include -#include - -typedef std::map HealthMap; - -class HealthTable: public HealthTableIF, public SystemObject { -public: - HealthTable(object_id_t objectid); - virtual ~HealthTable(); - - virtual ReturnValue_t registerObject(object_id_t object, - HasHealthIF::HealthState initilialState = HasHealthIF::HEALTHY); - - virtual bool hasHealth(object_id_t object); - virtual void setHealth(object_id_t object, HasHealthIF::HealthState newState); - virtual HasHealthIF::HealthState getHealth(object_id_t); - - virtual uint32_t getPrintSize(); - virtual void printAll(uint8_t *pointer, size_t maxSize); - -protected: - MutexIF* mutex; - HealthMap healthMap; - - HealthMap::iterator mapIterator; - - virtual ReturnValue_t iterate(std::pair *value, bool reset = false); -}; - -#endif /* HEALTHTABLE_H_ */ +#ifndef FRAMEWORK_HEALTH_HEALTHTABLE_H_ +#define FRAMEWORK_HEALTH_HEALTHTABLE_H_ + +#include "../health/HealthTableIF.h" +#include "../objectmanager/SystemObject.h" +#include "../ipc/MutexIF.h" +#include + +typedef std::map HealthMap; + +class HealthTable: public HealthTableIF, public SystemObject { +public: + HealthTable(object_id_t objectid); + virtual ~HealthTable(); + + virtual ReturnValue_t registerObject(object_id_t object, + HasHealthIF::HealthState initilialState = HasHealthIF::HEALTHY); + + virtual bool hasHealth(object_id_t object); + virtual void setHealth(object_id_t object, HasHealthIF::HealthState newState); + virtual HasHealthIF::HealthState getHealth(object_id_t); + + virtual uint32_t getPrintSize(); + virtual void printAll(uint8_t *pointer, size_t maxSize); + +protected: + MutexIF* mutex; + HealthMap healthMap; + + HealthMap::iterator mapIterator; + + virtual ReturnValue_t iterate(std::pair *value, bool reset = false); +}; + +#endif /* HEALTHTABLE_H_ */ diff --git a/health/HealthTableIF.h b/health/HealthTableIF.h index e4606286..bc4a8cfb 100644 --- a/health/HealthTableIF.h +++ b/health/HealthTableIF.h @@ -1,28 +1,28 @@ -#ifndef FRAMEWORK_HEALTH_HEALTHTABLEIF_H_ -#define FRAMEWORK_HEALTH_HEALTHTABLEIF_H_ - -#include -#include -#include -#include - - -class HealthTableIF: public ManagesHealthIF { - // TODO: This is in the mission folder and not in the framework folder. - // delete it? - friend class HealthCommandingService; -public: - virtual ~HealthTableIF() { - } - - virtual ReturnValue_t registerObject(object_id_t object, - HasHealthIF::HealthState initilialState = HasHealthIF::HEALTHY) = 0; - - virtual uint32_t getPrintSize() = 0; - virtual void printAll(uint8_t *pointer, size_t maxSize) = 0; - -protected: - virtual ReturnValue_t iterate(std::pair *value, bool reset = false) = 0; -}; - -#endif /* FRAMEWORK_HEALTH_HEALTHTABLEIF_H_ */ +#ifndef FRAMEWORK_HEALTH_HEALTHTABLEIF_H_ +#define FRAMEWORK_HEALTH_HEALTHTABLEIF_H_ + +#include "../health/ManagesHealthIF.h" +#include "../objectmanager/ObjectManagerIF.h" +#include "../returnvalues/HasReturnvaluesIF.h" +#include + + +class HealthTableIF: public ManagesHealthIF { + // TODO: This is in the mission folder and not in the framework folder. + // delete it? + friend class HealthCommandingService; +public: + virtual ~HealthTableIF() { + } + + virtual ReturnValue_t registerObject(object_id_t object, + HasHealthIF::HealthState initilialState = HasHealthIF::HEALTHY) = 0; + + virtual uint32_t getPrintSize() = 0; + virtual void printAll(uint8_t *pointer, size_t maxSize) = 0; + +protected: + virtual ReturnValue_t iterate(std::pair *value, bool reset = false) = 0; +}; + +#endif /* FRAMEWORK_HEALTH_HEALTHTABLEIF_H_ */ diff --git a/health/ManagesHealthIF.h b/health/ManagesHealthIF.h index ff0c5386..57996dda 100644 --- a/health/ManagesHealthIF.h +++ b/health/ManagesHealthIF.h @@ -1,52 +1,52 @@ -#ifndef FRAMEWORK_HEALTH_MANAGESHEALTHIF_H_ -#define FRAMEWORK_HEALTH_MANAGESHEALTHIF_H_ - -#include -#include -class ManagesHealthIF { -public: - virtual ~ManagesHealthIF() { - } - virtual bool hasHealth(object_id_t object) = 0; - virtual void setHealth(object_id_t object, - HasHealthIF::HealthState newState) = 0; - virtual HasHealthIF::HealthState getHealth(object_id_t) = 0; - - virtual bool isHealthy(object_id_t object) { - return (getHealth(object) == HasHealthIF::HEALTHY); - } - - virtual bool isHealthy(HasHealthIF::HealthState health) { - return (health == HasHealthIF::HEALTHY); - } - - virtual bool isFaulty(object_id_t object) { - HasHealthIF::HealthState health = getHealth(object); - return isFaulty(health); - } - - virtual bool isPermanentFaulty(object_id_t object) { - HasHealthIF::HealthState health = getHealth(object); - return isPermanentFaulty(health); - } - - virtual bool isPermanentFaulty(HasHealthIF::HealthState health) { - return (health == HasHealthIF::PERMANENT_FAULTY); - } - - static bool isFaulty(HasHealthIF::HealthState health) { - return ((health == HasHealthIF::FAULTY) - || (health == HasHealthIF::PERMANENT_FAULTY) - || (health == HasHealthIF::NEEDS_RECOVERY)); - } - - virtual bool isCommandable(object_id_t object) { - return (getHealth(object) != HasHealthIF::EXTERNAL_CONTROL); - } - - virtual bool isCommandable(HasHealthIF::HealthState health) { - return (health != HasHealthIF::EXTERNAL_CONTROL); - } -}; - -#endif /* FRAMEWORK_HEALTH_MANAGESHEALTHIF_H_ */ +#ifndef FRAMEWORK_HEALTH_MANAGESHEALTHIF_H_ +#define FRAMEWORK_HEALTH_MANAGESHEALTHIF_H_ + +#include "../health/HasHealthIF.h" +#include "../objectmanager/ObjectManagerIF.h" +class ManagesHealthIF { +public: + virtual ~ManagesHealthIF() { + } + virtual bool hasHealth(object_id_t object) = 0; + virtual void setHealth(object_id_t object, + HasHealthIF::HealthState newState) = 0; + virtual HasHealthIF::HealthState getHealth(object_id_t) = 0; + + virtual bool isHealthy(object_id_t object) { + return (getHealth(object) == HasHealthIF::HEALTHY); + } + + virtual bool isHealthy(HasHealthIF::HealthState health) { + return (health == HasHealthIF::HEALTHY); + } + + virtual bool isFaulty(object_id_t object) { + HasHealthIF::HealthState health = getHealth(object); + return isFaulty(health); + } + + virtual bool isPermanentFaulty(object_id_t object) { + HasHealthIF::HealthState health = getHealth(object); + return isPermanentFaulty(health); + } + + virtual bool isPermanentFaulty(HasHealthIF::HealthState health) { + return (health == HasHealthIF::PERMANENT_FAULTY); + } + + static bool isFaulty(HasHealthIF::HealthState health) { + return ((health == HasHealthIF::FAULTY) + || (health == HasHealthIF::PERMANENT_FAULTY) + || (health == HasHealthIF::NEEDS_RECOVERY)); + } + + virtual bool isCommandable(object_id_t object) { + return (getHealth(object) != HasHealthIF::EXTERNAL_CONTROL); + } + + virtual bool isCommandable(HasHealthIF::HealthState health) { + return (health != HasHealthIF::EXTERNAL_CONTROL); + } +}; + +#endif /* FRAMEWORK_HEALTH_MANAGESHEALTHIF_H_ */ diff --git a/housekeeping/AcceptsHkPacketsIF.h b/housekeeping/AcceptsHkPacketsIF.h index f44e1d95..879aaf8e 100644 --- a/housekeeping/AcceptsHkPacketsIF.h +++ b/housekeeping/AcceptsHkPacketsIF.h @@ -1,11 +1,11 @@ -#ifndef FRAMEWORK_HOUSEKEEPING_ACCEPTSHKPACKETSIF_H_ -#define FRAMEWORK_HOUSEKEEPING_ACCEPTSHKPACKETSIF_H_ -#include - -class AcceptsHkPacketsIF { -public: - virtual~ AcceptsHkPacketsIF() {}; - virtual MessageQueueId_t getHkQueue() const = 0; -}; - -#endif /* FRAMEWORK_HOUSEKEEPING_ACCEPTSHKPACKETSIF_H_ */ +#ifndef FRAMEWORK_HOUSEKEEPING_ACCEPTSHKPACKETSIF_H_ +#define FRAMEWORK_HOUSEKEEPING_ACCEPTSHKPACKETSIF_H_ +#include "../ipc/MessageQueueMessageIF.h" + +class AcceptsHkPacketsIF { +public: + virtual~ AcceptsHkPacketsIF() {}; + virtual MessageQueueId_t getHkQueue() const = 0; +}; + +#endif /* FRAMEWORK_HOUSEKEEPING_ACCEPTSHKPACKETSIF_H_ */ diff --git a/housekeeping/HousekeepingMessage.cpp b/housekeeping/HousekeepingMessage.cpp index 2335f03d..6777c471 100644 --- a/housekeeping/HousekeepingMessage.cpp +++ b/housekeeping/HousekeepingMessage.cpp @@ -1,48 +1,48 @@ -#include -#include - -HousekeepingMessage::~HousekeepingMessage() {} - -void HousekeepingMessage::setHkReportMessage(CommandMessage* message, sid_t sid, - store_address_t storeId) { - message->setCommand(HK_REPORT); - message->setMessageSize(HK_MESSAGE_SIZE); - setSid(message, sid); - setParameter(message, storeId.raw); -} - -void HousekeepingMessage::setHkDiagnosticsMessage(CommandMessage* message, - sid_t sid, store_address_t storeId) { - message->setCommand(DIAGNOSTICS_REPORT); - message->setMessageSize(HK_MESSAGE_SIZE); - setSid(message, sid); - setParameter(message, storeId.raw); -} - -sid_t HousekeepingMessage::getHkReportMessage(const CommandMessage *message, - store_address_t *storeIdToSet) { - if(storeIdToSet != nullptr) { - *storeIdToSet = getParameter(message); - } - return getSid(message); -} - -sid_t HousekeepingMessage::getSid(const CommandMessage* message) { - sid_t sid; - std::memcpy(&sid.raw, message->getData(), sizeof(sid.raw)); - return sid; -} - -void HousekeepingMessage::setSid(CommandMessage *message, sid_t sid) { - std::memcpy(message->getData(), &sid.raw, sizeof(sid.raw)); -} - - -void HousekeepingMessage::setParameter(CommandMessage *message, - uint32_t parameter) { - message->setParameter3(parameter); -} - -uint32_t HousekeepingMessage::getParameter(const CommandMessage *message) { - return message->getParameter3(); -} +#include "../housekeeping/HousekeepingMessage.h" +#include + +HousekeepingMessage::~HousekeepingMessage() {} + +void HousekeepingMessage::setHkReportMessage(CommandMessage* message, sid_t sid, + store_address_t storeId) { + message->setCommand(HK_REPORT); + message->setMessageSize(HK_MESSAGE_SIZE); + setSid(message, sid); + setParameter(message, storeId.raw); +} + +void HousekeepingMessage::setHkDiagnosticsMessage(CommandMessage* message, + sid_t sid, store_address_t storeId) { + message->setCommand(DIAGNOSTICS_REPORT); + message->setMessageSize(HK_MESSAGE_SIZE); + setSid(message, sid); + setParameter(message, storeId.raw); +} + +sid_t HousekeepingMessage::getHkReportMessage(const CommandMessage *message, + store_address_t *storeIdToSet) { + if(storeIdToSet != nullptr) { + *storeIdToSet = getParameter(message); + } + return getSid(message); +} + +sid_t HousekeepingMessage::getSid(const CommandMessage* message) { + sid_t sid; + std::memcpy(&sid.raw, message->getData(), sizeof(sid.raw)); + return sid; +} + +void HousekeepingMessage::setSid(CommandMessage *message, sid_t sid) { + std::memcpy(message->getData(), &sid.raw, sizeof(sid.raw)); +} + + +void HousekeepingMessage::setParameter(CommandMessage *message, + uint32_t parameter) { + message->setParameter3(parameter); +} + +uint32_t HousekeepingMessage::getParameter(const CommandMessage *message) { + return message->getParameter3(); +} diff --git a/housekeeping/HousekeepingMessage.h b/housekeeping/HousekeepingMessage.h index e2a69805..0f50c2a4 100644 --- a/housekeeping/HousekeepingMessage.h +++ b/housekeeping/HousekeepingMessage.h @@ -1,116 +1,116 @@ -#ifndef FRAMEWORK_HK_HOUSEKEEPINGMESSAGE_H_ -#define FRAMEWORK_HK_HOUSEKEEPINGMESSAGE_H_ - -#include -#include -#include -#include -#include - -union sid_t { - static constexpr uint64_t INVALID_ADDRESS = - std::numeric_limits::max(); - sid_t(): raw(INVALID_ADDRESS) {} - - struct { - object_id_t objectId ; - /** - * A generic 32 bit ID to identify unique HK packets for a single - * object. For example, the DeviceCommandId_t is used for - * DeviceHandlers - */ - uint32_t ownerSetId; - }; - /** - * Alternative access to the raw value. This is also the size of the type. - */ - uint64_t raw; -}; - - -/** - * @brief Special command message type for housekeeping messages - * @details - * This message is slightly larger than regular command messages to accomodate - * the uint64_t structure ID (SID). - */ -class HousekeepingMessage { -public: - - static constexpr size_t HK_MESSAGE_SIZE = CommandMessageIF::HEADER_SIZE + - sizeof(sid_t) + sizeof(uint32_t); - - /** - * The HK message is initialized with a pointer to a message which holds - * the message data, see CommandMessageIF and getInternalMessage(). - * @param message - */ - HousekeepingMessage() = delete; - virtual ~HousekeepingMessage(); - - static constexpr uint8_t MESSAGE_ID = messagetypes::HOUSEKEEPING; - - static constexpr Command_t ADD_HK_REPORT_STRUCT = - MAKE_COMMAND_ID(1); - static constexpr Command_t ADD_DIAGNOSTICS_REPORT_STRUCT = - MAKE_COMMAND_ID(2); - - static constexpr Command_t DELETE_HK_REPORT_STRUCT = MAKE_COMMAND_ID(3); - static constexpr Command_t DELETE_DIAGNOSTICS_REPORT_STRUCT = - MAKE_COMMAND_ID(4); - - static constexpr Command_t ENABLE_PERIODIC_HK_GENERATION = - MAKE_COMMAND_ID(5); - static constexpr Command_t DISABLE_PERIODIC_HK_REPORT_GENERATION = - MAKE_COMMAND_ID(6); - - static constexpr Command_t ENABLE_PERIODIC_DIAGNOSTICS_GENERATION = - MAKE_COMMAND_ID(7); - static constexpr Command_t DISABLE_PERIODIC_DIAGNOSTICS_GENERATION = - MAKE_COMMAND_ID(8); - - static constexpr Command_t REPORT_HK_REPORT_STRUCTURES = MAKE_COMMAND_ID(9); - static constexpr Command_t REPORT_DIAGNOSTICS_REPORT_STRUCTURES = - MAKE_COMMAND_ID(11); - - static constexpr Command_t HK_DEFINITIONS_REPORT = MAKE_COMMAND_ID(10); - static constexpr Command_t DIAGNOSTICS_DEFINITION_REPORT = MAKE_COMMAND_ID(12); - - static constexpr Command_t HK_REPORT = MAKE_COMMAND_ID(25); - static constexpr Command_t DIAGNOSTICS_REPORT = MAKE_COMMAND_ID(26); - - static constexpr Command_t GENERATE_ONE_PARAMETER_REPORT = - MAKE_COMMAND_ID(27); - static constexpr Command_t GENERATE_ONE_DIAGNOSTICS_REPORT = - MAKE_COMMAND_ID(28); - - static constexpr Command_t APPEND_PARAMETERS_TO_PARAMETER_REPORT_STRUCTURE = - MAKE_COMMAND_ID(29); - static constexpr Command_t APPEND_PARAMETERS_TO_DIAGNOSTICS_REPORT_STRUCTURE = - MAKE_COMMAND_ID(30); - - static constexpr Command_t MODIFY_PARAMETER_REPORT_COLLECTION_INTERVAL = - MAKE_COMMAND_ID(31); - static constexpr Command_t MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL = - MAKE_COMMAND_ID(32); - - static sid_t getSid(const CommandMessage* message); - - static void setHkReportMessage(CommandMessage* message, sid_t sid, - store_address_t storeId); - static void setHkDiagnosticsMessage(CommandMessage* message, sid_t sid, - store_address_t storeId); - - //! Get the respective SID and store ID. Command ID can be used beforehand - //! to distinguish between diagnostics and regular HK packets - static sid_t getHkReportMessage(const CommandMessage* message, - store_address_t * storeIdToSet); - -private: - static void setSid(CommandMessage* message, sid_t sid); - static void setParameter(CommandMessage* message, uint32_t parameter); - static uint32_t getParameter(const CommandMessage* message); -}; - - -#endif /* FRAMEWORK_HK_HOUSEKEEPINGMESSAGE_H_ */ +#ifndef FRAMEWORK_HK_HOUSEKEEPINGMESSAGE_H_ +#define FRAMEWORK_HK_HOUSEKEEPINGMESSAGE_H_ + +#include "../ipc/CommandMessage.h" +#include "../ipc/FwMessageTypes.h" +#include "../objectmanager/SystemObjectIF.h" +#include "../storagemanager/StorageManagerIF.h" +#include + +union sid_t { + static constexpr uint64_t INVALID_ADDRESS = + std::numeric_limits::max(); + sid_t(): raw(INVALID_ADDRESS) {} + + struct { + object_id_t objectId ; + /** + * A generic 32 bit ID to identify unique HK packets for a single + * object. For example, the DeviceCommandId_t is used for + * DeviceHandlers + */ + uint32_t ownerSetId; + }; + /** + * Alternative access to the raw value. This is also the size of the type. + */ + uint64_t raw; +}; + + +/** + * @brief Special command message type for housekeeping messages + * @details + * This message is slightly larger than regular command messages to accomodate + * the uint64_t structure ID (SID). + */ +class HousekeepingMessage { +public: + + static constexpr size_t HK_MESSAGE_SIZE = CommandMessageIF::HEADER_SIZE + + sizeof(sid_t) + sizeof(uint32_t); + + /** + * The HK message is initialized with a pointer to a message which holds + * the message data, see CommandMessageIF and getInternalMessage(). + * @param message + */ + HousekeepingMessage() = delete; + virtual ~HousekeepingMessage(); + + static constexpr uint8_t MESSAGE_ID = messagetypes::HOUSEKEEPING; + + static constexpr Command_t ADD_HK_REPORT_STRUCT = + MAKE_COMMAND_ID(1); + static constexpr Command_t ADD_DIAGNOSTICS_REPORT_STRUCT = + MAKE_COMMAND_ID(2); + + static constexpr Command_t DELETE_HK_REPORT_STRUCT = MAKE_COMMAND_ID(3); + static constexpr Command_t DELETE_DIAGNOSTICS_REPORT_STRUCT = + MAKE_COMMAND_ID(4); + + static constexpr Command_t ENABLE_PERIODIC_HK_GENERATION = + MAKE_COMMAND_ID(5); + static constexpr Command_t DISABLE_PERIODIC_HK_REPORT_GENERATION = + MAKE_COMMAND_ID(6); + + static constexpr Command_t ENABLE_PERIODIC_DIAGNOSTICS_GENERATION = + MAKE_COMMAND_ID(7); + static constexpr Command_t DISABLE_PERIODIC_DIAGNOSTICS_GENERATION = + MAKE_COMMAND_ID(8); + + static constexpr Command_t REPORT_HK_REPORT_STRUCTURES = MAKE_COMMAND_ID(9); + static constexpr Command_t REPORT_DIAGNOSTICS_REPORT_STRUCTURES = + MAKE_COMMAND_ID(11); + + static constexpr Command_t HK_DEFINITIONS_REPORT = MAKE_COMMAND_ID(10); + static constexpr Command_t DIAGNOSTICS_DEFINITION_REPORT = MAKE_COMMAND_ID(12); + + static constexpr Command_t HK_REPORT = MAKE_COMMAND_ID(25); + static constexpr Command_t DIAGNOSTICS_REPORT = MAKE_COMMAND_ID(26); + + static constexpr Command_t GENERATE_ONE_PARAMETER_REPORT = + MAKE_COMMAND_ID(27); + static constexpr Command_t GENERATE_ONE_DIAGNOSTICS_REPORT = + MAKE_COMMAND_ID(28); + + static constexpr Command_t APPEND_PARAMETERS_TO_PARAMETER_REPORT_STRUCTURE = + MAKE_COMMAND_ID(29); + static constexpr Command_t APPEND_PARAMETERS_TO_DIAGNOSTICS_REPORT_STRUCTURE = + MAKE_COMMAND_ID(30); + + static constexpr Command_t MODIFY_PARAMETER_REPORT_COLLECTION_INTERVAL = + MAKE_COMMAND_ID(31); + static constexpr Command_t MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL = + MAKE_COMMAND_ID(32); + + static sid_t getSid(const CommandMessage* message); + + static void setHkReportMessage(CommandMessage* message, sid_t sid, + store_address_t storeId); + static void setHkDiagnosticsMessage(CommandMessage* message, sid_t sid, + store_address_t storeId); + + //! Get the respective SID and store ID. Command ID can be used beforehand + //! to distinguish between diagnostics and regular HK packets + static sid_t getHkReportMessage(const CommandMessage* message, + store_address_t * storeIdToSet); + +private: + static void setSid(CommandMessage* message, sid_t sid); + static void setParameter(CommandMessage* message, uint32_t parameter); + static uint32_t getParameter(const CommandMessage* message); +}; + + +#endif /* FRAMEWORK_HK_HOUSEKEEPINGMESSAGE_H_ */ diff --git a/internalError/InternalErrorReporter.cpp b/internalError/InternalErrorReporter.cpp index 8944553d..ed064da6 100644 --- a/internalError/InternalErrorReporter.cpp +++ b/internalError/InternalErrorReporter.cpp @@ -1,125 +1,125 @@ -#include -#include "InternalErrorReporter.h" - -#include -#include - -#include - -InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, - uint32_t queuePoolId, uint32_t tmPoolId, uint32_t storePoolId) : - SystemObject(setObjectId), mutex(NULL), queuePoolId(queuePoolId), - tmPoolId(tmPoolId),storePoolId(storePoolId), queueHits(0), tmHits(0), - storeHits(0) { - mutex = MutexFactory::instance()->createMutex(); -} - -InternalErrorReporter::~InternalErrorReporter() { - MutexFactory::instance()->deleteMutex(mutex); -} - -ReturnValue_t InternalErrorReporter::performOperation(uint8_t opCode) { - - GlobDataSet mySet; - gp_uint32_t queueHitsInPool(queuePoolId, &mySet, - PoolVariableIF::VAR_READ_WRITE); - gp_uint32_t tmHitsInPool(tmPoolId, &mySet, - PoolVariableIF::VAR_READ_WRITE); - - gp_uint32_t storeHitsInPool(storePoolId, &mySet, - PoolVariableIF::VAR_READ_WRITE); - mySet.read(); - - uint32_t newQueueHits = getAndResetQueueHits(); - uint32_t newTmHits = getAndResetTmHits(); - uint32_t newStoreHits = getAndResetStoreHits(); - - queueHitsInPool.value += newQueueHits; - tmHitsInPool.value += newTmHits; - storeHitsInPool.value += newStoreHits; - - mySet.commit(PoolVariableIF::VALID); - - return HasReturnvaluesIF::RETURN_OK; -} - -void InternalErrorReporter::queueMessageNotSent() { - incrementQueueHits(); -} - -void InternalErrorReporter::lostTm() { - incrementTmHits(); -} - -uint32_t InternalErrorReporter::getAndResetQueueHits() { - uint32_t value; - mutex->lockMutex(MutexIF::BLOCKING); - value = queueHits; - queueHits = 0; - mutex->unlockMutex(); - return value; -} - -uint32_t InternalErrorReporter::getQueueHits() { - uint32_t value; - mutex->lockMutex(MutexIF::BLOCKING); - value = queueHits; - mutex->unlockMutex(); - return value; -} - -void InternalErrorReporter::incrementQueueHits() { - mutex->lockMutex(MutexIF::BLOCKING); - queueHits++; - mutex->unlockMutex(); -} - -uint32_t InternalErrorReporter::getAndResetTmHits() { - uint32_t value; - mutex->lockMutex(MutexIF::BLOCKING); - value = tmHits; - tmHits = 0; - mutex->unlockMutex(); - return value; -} - -uint32_t InternalErrorReporter::getTmHits() { - uint32_t value; - mutex->lockMutex(MutexIF::BLOCKING); - value = tmHits; - mutex->unlockMutex(); - return value; -} - -void InternalErrorReporter::incrementTmHits() { - mutex->lockMutex(MutexIF::BLOCKING); - tmHits++; - mutex->unlockMutex(); -} - -void InternalErrorReporter::storeFull() { - incrementStoreHits(); -} - -uint32_t InternalErrorReporter::getAndResetStoreHits() { - uint32_t value; - mutex->lockMutex(MutexIF::BLOCKING); - value = storeHits; - storeHits = 0; - mutex->unlockMutex(); - return value; -} - -uint32_t InternalErrorReporter::getStoreHits() { - uint32_t value; - mutex->lockMutex(MutexIF::BLOCKING); - value = storeHits; - mutex->unlockMutex(); - return value; -} - -void InternalErrorReporter::incrementStoreHits() { - mutex->lockMutex(MutexIF::BLOCKING); - storeHits++; - mutex->unlockMutex(); -} +#include "../datapoolglob/GlobalDataSet.h" +#include "InternalErrorReporter.h" + +#include "../datapoolglob/GlobalPoolVariable.h" +#include "../ipc/MutexFactory.h" + +#include "../serviceinterface/ServiceInterfaceStream.h" + +InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, + uint32_t queuePoolId, uint32_t tmPoolId, uint32_t storePoolId) : + SystemObject(setObjectId), mutex(NULL), queuePoolId(queuePoolId), + tmPoolId(tmPoolId),storePoolId(storePoolId), queueHits(0), tmHits(0), + storeHits(0) { + mutex = MutexFactory::instance()->createMutex(); +} + +InternalErrorReporter::~InternalErrorReporter() { + MutexFactory::instance()->deleteMutex(mutex); +} + +ReturnValue_t InternalErrorReporter::performOperation(uint8_t opCode) { + + GlobDataSet mySet; + gp_uint32_t queueHitsInPool(queuePoolId, &mySet, + PoolVariableIF::VAR_READ_WRITE); + gp_uint32_t tmHitsInPool(tmPoolId, &mySet, + PoolVariableIF::VAR_READ_WRITE); + + gp_uint32_t storeHitsInPool(storePoolId, &mySet, + PoolVariableIF::VAR_READ_WRITE); + mySet.read(); + + uint32_t newQueueHits = getAndResetQueueHits(); + uint32_t newTmHits = getAndResetTmHits(); + uint32_t newStoreHits = getAndResetStoreHits(); + + queueHitsInPool.value += newQueueHits; + tmHitsInPool.value += newTmHits; + storeHitsInPool.value += newStoreHits; + + mySet.commit(PoolVariableIF::VALID); + + return HasReturnvaluesIF::RETURN_OK; +} + +void InternalErrorReporter::queueMessageNotSent() { + incrementQueueHits(); +} + +void InternalErrorReporter::lostTm() { + incrementTmHits(); +} + +uint32_t InternalErrorReporter::getAndResetQueueHits() { + uint32_t value; + mutex->lockMutex(MutexIF::BLOCKING); + value = queueHits; + queueHits = 0; + mutex->unlockMutex(); + return value; +} + +uint32_t InternalErrorReporter::getQueueHits() { + uint32_t value; + mutex->lockMutex(MutexIF::BLOCKING); + value = queueHits; + mutex->unlockMutex(); + return value; +} + +void InternalErrorReporter::incrementQueueHits() { + mutex->lockMutex(MutexIF::BLOCKING); + queueHits++; + mutex->unlockMutex(); +} + +uint32_t InternalErrorReporter::getAndResetTmHits() { + uint32_t value; + mutex->lockMutex(MutexIF::BLOCKING); + value = tmHits; + tmHits = 0; + mutex->unlockMutex(); + return value; +} + +uint32_t InternalErrorReporter::getTmHits() { + uint32_t value; + mutex->lockMutex(MutexIF::BLOCKING); + value = tmHits; + mutex->unlockMutex(); + return value; +} + +void InternalErrorReporter::incrementTmHits() { + mutex->lockMutex(MutexIF::BLOCKING); + tmHits++; + mutex->unlockMutex(); +} + +void InternalErrorReporter::storeFull() { + incrementStoreHits(); +} + +uint32_t InternalErrorReporter::getAndResetStoreHits() { + uint32_t value; + mutex->lockMutex(MutexIF::BLOCKING); + value = storeHits; + storeHits = 0; + mutex->unlockMutex(); + return value; +} + +uint32_t InternalErrorReporter::getStoreHits() { + uint32_t value; + mutex->lockMutex(MutexIF::BLOCKING); + value = storeHits; + mutex->unlockMutex(); + return value; +} + +void InternalErrorReporter::incrementStoreHits() { + mutex->lockMutex(MutexIF::BLOCKING); + storeHits++; + mutex->unlockMutex(); +} diff --git a/internalError/InternalErrorReporter.h b/internalError/InternalErrorReporter.h index 7c1df6a7..1fe7426d 100644 --- a/internalError/InternalErrorReporter.h +++ b/internalError/InternalErrorReporter.h @@ -1,50 +1,50 @@ -#ifndef INTERNALERRORREPORTER_H_ -#define INTERNALERRORREPORTER_H_ - -#include "InternalErrorReporterIF.h" - -#include -#include -#include - -class InternalErrorReporter: public SystemObject, - public ExecutableObjectIF, - public InternalErrorReporterIF { -public: - InternalErrorReporter(object_id_t setObjectId, uint32_t queuePoolId, - uint32_t tmPoolId, uint32_t storePoolId); - virtual ~InternalErrorReporter(); - - virtual ReturnValue_t performOperation(uint8_t opCode); - - virtual void queueMessageNotSent(); - - virtual void lostTm(); - - virtual void storeFull(); -protected: - MutexIF* mutex; - - uint32_t queuePoolId; - uint32_t tmPoolId; - uint32_t storePoolId; - - uint32_t queueHits; - uint32_t tmHits; - uint32_t storeHits; - - uint32_t getAndResetQueueHits(); - uint32_t getQueueHits(); - void incrementQueueHits(); - - uint32_t getAndResetTmHits(); - uint32_t getTmHits(); - void incrementTmHits(); - - uint32_t getAndResetStoreHits(); - uint32_t getStoreHits(); - void incrementStoreHits(); - -}; - -#endif /* INTERNALERRORREPORTER_H_ */ +#ifndef INTERNALERRORREPORTER_H_ +#define INTERNALERRORREPORTER_H_ + +#include "InternalErrorReporterIF.h" + +#include "../tasks/ExecutableObjectIF.h" +#include "../objectmanager/SystemObject.h" +#include "../ipc/MutexIF.h" + +class InternalErrorReporter: public SystemObject, + public ExecutableObjectIF, + public InternalErrorReporterIF { +public: + InternalErrorReporter(object_id_t setObjectId, uint32_t queuePoolId, + uint32_t tmPoolId, uint32_t storePoolId); + virtual ~InternalErrorReporter(); + + virtual ReturnValue_t performOperation(uint8_t opCode); + + virtual void queueMessageNotSent(); + + virtual void lostTm(); + + virtual void storeFull(); +protected: + MutexIF* mutex; + + uint32_t queuePoolId; + uint32_t tmPoolId; + uint32_t storePoolId; + + uint32_t queueHits; + uint32_t tmHits; + uint32_t storeHits; + + uint32_t getAndResetQueueHits(); + uint32_t getQueueHits(); + void incrementQueueHits(); + + uint32_t getAndResetTmHits(); + uint32_t getTmHits(); + void incrementTmHits(); + + uint32_t getAndResetStoreHits(); + uint32_t getStoreHits(); + void incrementStoreHits(); + +}; + +#endif /* INTERNALERRORREPORTER_H_ */ diff --git a/ipc/CommandMessage.cpp b/ipc/CommandMessage.cpp index cc1185c7..6934e6ce 100644 --- a/ipc/CommandMessage.cpp +++ b/ipc/CommandMessage.cpp @@ -1,111 +1,111 @@ -#include -#include -#include - -CommandMessage::CommandMessage() { - MessageQueueMessage::setMessageSize(DEFAULT_COMMAND_MESSAGE_SIZE); - setCommand(CMD_NONE); -} - -CommandMessage::CommandMessage(Command_t command, uint32_t parameter1, - uint32_t parameter2) { - MessageQueueMessage::setMessageSize(DEFAULT_COMMAND_MESSAGE_SIZE); - setCommand(command); - setParameter(parameter1); - setParameter2(parameter2); -} - -Command_t CommandMessage::getCommand() const { - Command_t command; - std::memcpy(&command, MessageQueueMessage::getData(), sizeof(Command_t)); - return command; -} - -void CommandMessage::setCommand(Command_t command) { - std::memcpy(MessageQueueMessage::getData(), &command, sizeof(Command_t)); -} - -uint8_t CommandMessage::getMessageType() const { - // first byte of command ID. - return getCommand() >> 8 & 0xff; -} - -uint32_t CommandMessage::getParameter() const { - uint32_t parameter1; - std::memcpy(¶meter1, this->getData(), sizeof(parameter1)); - return parameter1; -} - -void CommandMessage::setParameter(uint32_t parameter1) { - std::memcpy(this->getData(), ¶meter1, sizeof(parameter1)); -} - -uint32_t CommandMessage::getParameter2() const { - uint32_t parameter2; - std::memcpy(¶meter2, this->getData() + sizeof(uint32_t), - sizeof(parameter2)); - return parameter2; -} - -void CommandMessage::setParameter2(uint32_t parameter2) { - std::memcpy(this->getData() + sizeof(uint32_t), ¶meter2, - sizeof(parameter2)); -} - -uint32_t CommandMessage::getParameter3() const { - uint32_t parameter3; - std::memcpy(¶meter3, this->getData() + 2 * sizeof(uint32_t), - sizeof(parameter3)); - return parameter3; -} - -void CommandMessage::setParameter3(uint32_t parameter3) { - std::memcpy(this->getData() + 2 * sizeof(uint32_t), ¶meter3, - sizeof(parameter3)); -} - -size_t CommandMessage::getMinimumMessageSize() const { - return MINIMUM_COMMAND_MESSAGE_SIZE; -} - -void CommandMessage::clearCommandMessage() { - clear(); -} - -void CommandMessage::clear() { - CommandMessageCleaner::clearCommandMessage(this); -} - -bool CommandMessage::isClearedCommandMessage() { - return getCommand() == CMD_NONE; -} - -void CommandMessage::setToUnknownCommand() { - Command_t initialCommand = getCommand(); - this->clear(); - setReplyRejected(UNKNOWN_COMMAND, initialCommand); -} - -void CommandMessage::setReplyRejected(ReturnValue_t reason, - Command_t initialCommand) { - setCommand(REPLY_REJECTED); - setParameter(reason); - setParameter2(initialCommand); -} - -ReturnValue_t CommandMessage::getReplyRejectedReason( - Command_t *initialCommand) const { - ReturnValue_t reason = getParameter(); - if(initialCommand != nullptr) { - *initialCommand = getParameter2(); - } - return reason; -} - -uint8_t* CommandMessage::getData() { - return MessageQueueMessage::getData() + sizeof(Command_t); -} - -const uint8_t* CommandMessage::getData() const { - return MessageQueueMessage::getData() + sizeof(Command_t); -} +#include "../ipc/CommandMessage.h" +#include "../ipc/CommandMessageCleaner.h" +#include + +CommandMessage::CommandMessage() { + MessageQueueMessage::setMessageSize(DEFAULT_COMMAND_MESSAGE_SIZE); + setCommand(CMD_NONE); +} + +CommandMessage::CommandMessage(Command_t command, uint32_t parameter1, + uint32_t parameter2) { + MessageQueueMessage::setMessageSize(DEFAULT_COMMAND_MESSAGE_SIZE); + setCommand(command); + setParameter(parameter1); + setParameter2(parameter2); +} + +Command_t CommandMessage::getCommand() const { + Command_t command; + std::memcpy(&command, MessageQueueMessage::getData(), sizeof(Command_t)); + return command; +} + +void CommandMessage::setCommand(Command_t command) { + std::memcpy(MessageQueueMessage::getData(), &command, sizeof(Command_t)); +} + +uint8_t CommandMessage::getMessageType() const { + // first byte of command ID. + return getCommand() >> 8 & 0xff; +} + +uint32_t CommandMessage::getParameter() const { + uint32_t parameter1; + std::memcpy(¶meter1, this->getData(), sizeof(parameter1)); + return parameter1; +} + +void CommandMessage::setParameter(uint32_t parameter1) { + std::memcpy(this->getData(), ¶meter1, sizeof(parameter1)); +} + +uint32_t CommandMessage::getParameter2() const { + uint32_t parameter2; + std::memcpy(¶meter2, this->getData() + sizeof(uint32_t), + sizeof(parameter2)); + return parameter2; +} + +void CommandMessage::setParameter2(uint32_t parameter2) { + std::memcpy(this->getData() + sizeof(uint32_t), ¶meter2, + sizeof(parameter2)); +} + +uint32_t CommandMessage::getParameter3() const { + uint32_t parameter3; + std::memcpy(¶meter3, this->getData() + 2 * sizeof(uint32_t), + sizeof(parameter3)); + return parameter3; +} + +void CommandMessage::setParameter3(uint32_t parameter3) { + std::memcpy(this->getData() + 2 * sizeof(uint32_t), ¶meter3, + sizeof(parameter3)); +} + +size_t CommandMessage::getMinimumMessageSize() const { + return MINIMUM_COMMAND_MESSAGE_SIZE; +} + +void CommandMessage::clearCommandMessage() { + clear(); +} + +void CommandMessage::clear() { + CommandMessageCleaner::clearCommandMessage(this); +} + +bool CommandMessage::isClearedCommandMessage() { + return getCommand() == CMD_NONE; +} + +void CommandMessage::setToUnknownCommand() { + Command_t initialCommand = getCommand(); + this->clear(); + setReplyRejected(UNKNOWN_COMMAND, initialCommand); +} + +void CommandMessage::setReplyRejected(ReturnValue_t reason, + Command_t initialCommand) { + setCommand(REPLY_REJECTED); + setParameter(reason); + setParameter2(initialCommand); +} + +ReturnValue_t CommandMessage::getReplyRejectedReason( + Command_t *initialCommand) const { + ReturnValue_t reason = getParameter(); + if(initialCommand != nullptr) { + *initialCommand = getParameter2(); + } + return reason; +} + +uint8_t* CommandMessage::getData() { + return MessageQueueMessage::getData() + sizeof(Command_t); +} + +const uint8_t* CommandMessage::getData() const { + return MessageQueueMessage::getData() + sizeof(Command_t); +} diff --git a/ipc/CommandMessage.h b/ipc/CommandMessage.h index d843e4c5..73b73dc9 100644 --- a/ipc/CommandMessage.h +++ b/ipc/CommandMessage.h @@ -1,129 +1,129 @@ -#ifndef FRAMEWORK_IPC_COMMANDMESSAGE_H_ -#define FRAMEWORK_IPC_COMMANDMESSAGE_H_ - -#include -#include -#include - -/** - * @brief Default command message used to pass command messages between tasks. - * Primary message type for IPC. Contains sender, 2-byte command ID - * field, and 2 4-byte parameters. - * @details - * It operates on an external memory which is contained inside a - * class implementing MessageQueueMessageIF by taking its address. - * This allows for a more flexible designs of message implementations. - * The pointer can be passed to different message implementations without - * the need of unnecessary copying. - * - * The command message is based of the generic MessageQueueMessage which - * currently has an internal message size of 28 bytes. - * @author Bastian Baetz - */ -class CommandMessage: public MessageQueueMessage, public CommandMessageIF { -public: - /** - * Default size can accomodate 2 4-byte parameters. - */ - static constexpr size_t DEFAULT_COMMAND_MESSAGE_SIZE = - CommandMessageIF::MINIMUM_COMMAND_MESSAGE_SIZE + sizeof(uint32_t); - - /** - * @brief Default Constructor, does not initialize anything. - * @details - * This constructor should be used when receiving a Message, as the - * content is filled by the MessageQueue. - */ - CommandMessage(); - /** - * This constructor creates a new message with all message content - * initialized - * - * @param command The DeviceHandlerCommand_t that will be sent - * @param parameter1 The first parameter - * @param parameter2 The second parameter - */ - CommandMessage(Command_t command, uint32_t parameter1, uint32_t parameter2); - - /** - * @brief Default Destructor - */ - virtual ~CommandMessage() {} - - /** - * Read the DeviceHandlerCommand_t that is stored in the message, - * usually used after receiving. - * - * @return the Command stored in the Message - */ - virtual Command_t getCommand() const override; - /** - * Set the command type of the message. Default implementation also - * sets the message type, which will be the first byte of the command ID. - * @param the Command to be sent - */ - virtual void setCommand(Command_t command); - - virtual uint8_t* getData() override; - virtual const uint8_t* getData() const override; - - /** - * Get the first parameter of the message - * @return the first Parameter of the message - */ - uint32_t getParameter() const; - /** - * Set the first parameter of the message - * @param the first parameter of the message - */ - void setParameter(uint32_t parameter1); - uint32_t getParameter2() const; - void setParameter2(uint32_t parameter2); - uint32_t getParameter3() const; - void setParameter3(uint32_t parameter3); - - /** - * check if a message was cleared - * - * @return if the command is CMD_NONE - */ - bool isClearedCommandMessage(); - - /** - * Sets the command to REPLY_REJECTED with parameter UNKNOWN_COMMAND. - * Is needed quite often, so we better code it once only. - */ - void setToUnknownCommand() override; - - /** - * A command message can be rejected and needs to offer a function - * to set a rejected reply - * @param reason - * @param initialCommand - */ - void setReplyRejected(ReturnValue_t reason, - Command_t initialCommand) override; - /** - * Corrensonding getter function. - * @param initialCommand - * @return - */ - ReturnValue_t getReplyRejectedReason( - Command_t* initialCommand = nullptr) const override; - - - virtual void clear() override; - void clearCommandMessage(); - - /** - * Extract message ID, which is the first byte of the command ID for the - * default implementation. - * @return - */ - virtual uint8_t getMessageType() const override; - - /** MessageQueueMessageIF functions used for minimum size check. */ - size_t getMinimumMessageSize() const override; -}; - -#endif /* COMMANDMESSAGE_H_ */ +#ifndef FRAMEWORK_IPC_COMMANDMESSAGE_H_ +#define FRAMEWORK_IPC_COMMANDMESSAGE_H_ + +#include "../ipc/CommandMessageIF.h" +#include "../ipc/MessageQueueMessage.h" +#include "../ipc/FwMessageTypes.h" + +/** + * @brief Default command message used to pass command messages between tasks. + * Primary message type for IPC. Contains sender, 2-byte command ID + * field, and 2 4-byte parameters. + * @details + * It operates on an external memory which is contained inside a + * class implementing MessageQueueMessageIF by taking its address. + * This allows for a more flexible designs of message implementations. + * The pointer can be passed to different message implementations without + * the need of unnecessary copying. + * + * The command message is based of the generic MessageQueueMessage which + * currently has an internal message size of 28 bytes. + * @author Bastian Baetz + */ +class CommandMessage: public MessageQueueMessage, public CommandMessageIF { +public: + /** + * Default size can accomodate 2 4-byte parameters. + */ + static constexpr size_t DEFAULT_COMMAND_MESSAGE_SIZE = + CommandMessageIF::MINIMUM_COMMAND_MESSAGE_SIZE + sizeof(uint32_t); + + /** + * @brief Default Constructor, does not initialize anything. + * @details + * This constructor should be used when receiving a Message, as the + * content is filled by the MessageQueue. + */ + CommandMessage(); + /** + * This constructor creates a new message with all message content + * initialized + * + * @param command The DeviceHandlerCommand_t that will be sent + * @param parameter1 The first parameter + * @param parameter2 The second parameter + */ + CommandMessage(Command_t command, uint32_t parameter1, uint32_t parameter2); + + /** + * @brief Default Destructor + */ + virtual ~CommandMessage() {} + + /** + * Read the DeviceHandlerCommand_t that is stored in the message, + * usually used after receiving. + * + * @return the Command stored in the Message + */ + virtual Command_t getCommand() const override; + /** + * Set the command type of the message. Default implementation also + * sets the message type, which will be the first byte of the command ID. + * @param the Command to be sent + */ + virtual void setCommand(Command_t command); + + virtual uint8_t* getData() override; + virtual const uint8_t* getData() const override; + + /** + * Get the first parameter of the message + * @return the first Parameter of the message + */ + uint32_t getParameter() const; + /** + * Set the first parameter of the message + * @param the first parameter of the message + */ + void setParameter(uint32_t parameter1); + uint32_t getParameter2() const; + void setParameter2(uint32_t parameter2); + uint32_t getParameter3() const; + void setParameter3(uint32_t parameter3); + + /** + * check if a message was cleared + * + * @return if the command is CMD_NONE + */ + bool isClearedCommandMessage(); + + /** + * Sets the command to REPLY_REJECTED with parameter UNKNOWN_COMMAND. + * Is needed quite often, so we better code it once only. + */ + void setToUnknownCommand() override; + + /** + * A command message can be rejected and needs to offer a function + * to set a rejected reply + * @param reason + * @param initialCommand + */ + void setReplyRejected(ReturnValue_t reason, + Command_t initialCommand) override; + /** + * Corrensonding getter function. + * @param initialCommand + * @return + */ + ReturnValue_t getReplyRejectedReason( + Command_t* initialCommand = nullptr) const override; + + + virtual void clear() override; + void clearCommandMessage(); + + /** + * Extract message ID, which is the first byte of the command ID for the + * default implementation. + * @return + */ + virtual uint8_t getMessageType() const override; + + /** MessageQueueMessageIF functions used for minimum size check. */ + size_t getMinimumMessageSize() const override; +}; + +#endif /* COMMANDMESSAGE_H_ */ diff --git a/ipc/CommandMessageCleaner.cpp b/ipc/CommandMessageCleaner.cpp index 23e6e168..a4dec78d 100644 --- a/ipc/CommandMessageCleaner.cpp +++ b/ipc/CommandMessageCleaner.cpp @@ -1,45 +1,45 @@ -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -void CommandMessageCleaner::clearCommandMessage(CommandMessage* message) { - switch(message->getMessageType()){ - case messagetypes::MODE_COMMAND: - ModeMessage::clear(message); - break; - case messagetypes::HEALTH_COMMAND: - HealthMessage::clear(message); - break; - case messagetypes::MODE_SEQUENCE: - ModeSequenceMessage::clear(message); - break; - case messagetypes::ACTION: - ActionMessage::clear(message); - break; - case messagetypes::DEVICE_HANDLER_COMMAND: - DeviceHandlerMessage::clear(message); - break; - case messagetypes::MEMORY: - MemoryMessage::clear(message); - break; - case messagetypes::MONITORING: - MonitoringMessage::clear(message); - break; - case messagetypes::TM_STORE: - TmStoreMessage::clear(message); - break; - case messagetypes::PARAMETER: - ParameterMessage::clear(message); - break; - default: - messagetypes::clearMissionMessage(message); - break; - } -} +#include "../ipc/CommandMessageCleaner.h" + +#include "../devicehandlers/DeviceHandlerMessage.h" +#include "../health/HealthMessage.h" +#include "../memory/MemoryMessage.h" +#include "../modes/ModeMessage.h" +#include "../monitoring/MonitoringMessage.h" +#include "../subsystem/modes/ModeSequenceMessage.h" +#include "../tmstorage/TmStoreMessage.h" +#include "../parameters/ParameterMessage.h" + +void CommandMessageCleaner::clearCommandMessage(CommandMessage* message) { + switch(message->getMessageType()){ + case messagetypes::MODE_COMMAND: + ModeMessage::clear(message); + break; + case messagetypes::HEALTH_COMMAND: + HealthMessage::clear(message); + break; + case messagetypes::MODE_SEQUENCE: + ModeSequenceMessage::clear(message); + break; + case messagetypes::ACTION: + ActionMessage::clear(message); + break; + case messagetypes::DEVICE_HANDLER_COMMAND: + DeviceHandlerMessage::clear(message); + break; + case messagetypes::MEMORY: + MemoryMessage::clear(message); + break; + case messagetypes::MONITORING: + MonitoringMessage::clear(message); + break; + case messagetypes::TM_STORE: + TmStoreMessage::clear(message); + break; + case messagetypes::PARAMETER: + ParameterMessage::clear(message); + break; + default: + messagetypes::clearMissionMessage(message); + break; + } +} diff --git a/ipc/CommandMessageCleaner.h b/ipc/CommandMessageCleaner.h index 48aaa478..f17bf282 100644 --- a/ipc/CommandMessageCleaner.h +++ b/ipc/CommandMessageCleaner.h @@ -1,16 +1,16 @@ -#ifndef FRAMEWORK_IPC_COMMANDMESSAGECLEANER_H_ -#define FRAMEWORK_IPC_COMMANDMESSAGECLEANER_H_ -#include - -namespace messagetypes { -// Implemented in config. -void clearMissionMessage(CommandMessage* message); -} - -class CommandMessageCleaner { -public: - static void clearCommandMessage(CommandMessage* message); -}; - - -#endif /* FRAMEWORK_IPC_COMMANDMESSAGECLEANER_H_ */ +#ifndef FRAMEWORK_IPC_COMMANDMESSAGECLEANER_H_ +#define FRAMEWORK_IPC_COMMANDMESSAGECLEANER_H_ +#include "../ipc/CommandMessage.h" + +namespace messagetypes { +// Implemented in config. +void clearMissionMessage(CommandMessage* message); +} + +class CommandMessageCleaner { +public: + static void clearCommandMessage(CommandMessage* message); +}; + + +#endif /* FRAMEWORK_IPC_COMMANDMESSAGECLEANER_H_ */ diff --git a/ipc/CommandMessageIF.h b/ipc/CommandMessageIF.h index 2cb6324e..e5f962ae 100644 --- a/ipc/CommandMessageIF.h +++ b/ipc/CommandMessageIF.h @@ -1,73 +1,73 @@ -#ifndef FRAMEWORK_IPC_COMMANDMESSAGEIF_H_ -#define FRAMEWORK_IPC_COMMANDMESSAGEIF_H_ - -#include -#include -#include - -#define MAKE_COMMAND_ID( number ) ((MESSAGE_ID << 8) + (number)) -typedef uint16_t Command_t; - -class CommandMessageIF { -public: - /** - * Header consists of sender ID and command ID. - */ - static constexpr size_t HEADER_SIZE = MessageQueueMessageIF::HEADER_SIZE + - sizeof(Command_t); - /** - * This minimum size is derived from the interface requirement to be able - * to set a rejected reply, which contains a returnvalue and the initial - * command. - */ - static constexpr size_t MINIMUM_COMMAND_MESSAGE_SIZE = - CommandMessageIF::HEADER_SIZE + sizeof(ReturnValue_t) + - sizeof(Command_t); - - static const uint8_t INTERFACE_ID = CLASS_ID::COMMAND_MESSAGE; - static const ReturnValue_t UNKNOWN_COMMAND = MAKE_RETURN_CODE(0x01); - - static const uint8_t MESSAGE_ID = messagetypes::COMMAND; - //! Used internally, shall be ignored - static const Command_t CMD_NONE = MAKE_COMMAND_ID( 0 ); - static const Command_t REPLY_COMMAND_OK = MAKE_COMMAND_ID( 1 ); - //! Reply indicating that the current command was rejected, - //! par1 should contain the error code - static const Command_t REPLY_REJECTED = MAKE_COMMAND_ID( 2 ); - - virtual ~CommandMessageIF() {}; - - /** - * A command message shall have a uint16_t command ID field. - * @return - */ - virtual Command_t getCommand() const = 0; - /** - * A command message shall have a uint8_t message type ID field. - * @return - */ - virtual uint8_t getMessageType() const = 0; - - /** - * A command message can be rejected and needs to offer a function - * to set a rejected reply - * @param reason - * @param initialCommand - */ - virtual void setReplyRejected(ReturnValue_t reason, - Command_t initialCommand) = 0; - /** - * Corrensonding getter function. - * @param initialCommand - * @return - */ - virtual ReturnValue_t getReplyRejectedReason( - Command_t* initialCommand = nullptr) const = 0; - - virtual void setToUnknownCommand() = 0; - - virtual void clear() = 0; - -}; - -#endif /* FRAMEWORK_IPC_COMMANDMESSAGEIF_H_ */ +#ifndef FRAMEWORK_IPC_COMMANDMESSAGEIF_H_ +#define FRAMEWORK_IPC_COMMANDMESSAGEIF_H_ + +#include "../ipc/MessageQueueMessageIF.h" +#include "../ipc/FwMessageTypes.h" +#include "../returnvalues/HasReturnvaluesIF.h" + +#define MAKE_COMMAND_ID( number ) ((MESSAGE_ID << 8) + (number)) +typedef uint16_t Command_t; + +class CommandMessageIF { +public: + /** + * Header consists of sender ID and command ID. + */ + static constexpr size_t HEADER_SIZE = MessageQueueMessageIF::HEADER_SIZE + + sizeof(Command_t); + /** + * This minimum size is derived from the interface requirement to be able + * to set a rejected reply, which contains a returnvalue and the initial + * command. + */ + static constexpr size_t MINIMUM_COMMAND_MESSAGE_SIZE = + CommandMessageIF::HEADER_SIZE + sizeof(ReturnValue_t) + + sizeof(Command_t); + + static const uint8_t INTERFACE_ID = CLASS_ID::COMMAND_MESSAGE; + static const ReturnValue_t UNKNOWN_COMMAND = MAKE_RETURN_CODE(0x01); + + static const uint8_t MESSAGE_ID = messagetypes::COMMAND; + //! Used internally, shall be ignored + static const Command_t CMD_NONE = MAKE_COMMAND_ID( 0 ); + static const Command_t REPLY_COMMAND_OK = MAKE_COMMAND_ID( 1 ); + //! Reply indicating that the current command was rejected, + //! par1 should contain the error code + static const Command_t REPLY_REJECTED = MAKE_COMMAND_ID( 2 ); + + virtual ~CommandMessageIF() {}; + + /** + * A command message shall have a uint16_t command ID field. + * @return + */ + virtual Command_t getCommand() const = 0; + /** + * A command message shall have a uint8_t message type ID field. + * @return + */ + virtual uint8_t getMessageType() const = 0; + + /** + * A command message can be rejected and needs to offer a function + * to set a rejected reply + * @param reason + * @param initialCommand + */ + virtual void setReplyRejected(ReturnValue_t reason, + Command_t initialCommand) = 0; + /** + * Corrensonding getter function. + * @param initialCommand + * @return + */ + virtual ReturnValue_t getReplyRejectedReason( + Command_t* initialCommand = nullptr) const = 0; + + virtual void setToUnknownCommand() = 0; + + virtual void clear() = 0; + +}; + +#endif /* FRAMEWORK_IPC_COMMANDMESSAGEIF_H_ */ diff --git a/ipc/MessageQueueIF.h b/ipc/MessageQueueIF.h index c0575442..6ae852ea 100644 --- a/ipc/MessageQueueIF.h +++ b/ipc/MessageQueueIF.h @@ -1,142 +1,142 @@ -#ifndef FRAMEWORK_IPC_MESSAGEQUEUEIF_H_ -#define FRAMEWORK_IPC_MESSAGEQUEUEIF_H_ - -// COULDDO: We could support blocking calls -// semaphores are being implemented, which makes this idea even more iteresting. - - -/** - * @defgroup message_queue Message Queue - * @brief Message Queue related software components - */ - -#include -#include -#include -class MessageQueueIF { -public: - static const MessageQueueId_t NO_QUEUE = MessageQueueMessageIF::NO_QUEUE; //!< Ugly hack. - - static const uint8_t INTERFACE_ID = CLASS_ID::MESSAGE_QUEUE_IF; - //! No new messages on the queue - static const ReturnValue_t EMPTY = MAKE_RETURN_CODE(1); - //! No space left for more messages - static const ReturnValue_t FULL = MAKE_RETURN_CODE(2); - //! Returned if a reply method was called without partner - static const ReturnValue_t NO_REPLY_PARTNER = MAKE_RETURN_CODE(3); - //! Returned if the target destination is invalid. - static constexpr ReturnValue_t DESTINVATION_INVALID = MAKE_RETURN_CODE(4); - - virtual ~MessageQueueIF() {} - /** - * @brief This operation sends a message to the last communication partner. - * @details This operation simplifies answering an incoming message by using the stored - * lastParnter information as destination. If there was no message received yet - * (i.e. lastPartner is zero), an error code is returned. - * @param message A pointer to a previously created message, which is sent. - * @return RETURN_OK if ok - * @return NO_REPLY_PARTNER Should return NO_REPLY_PARTNER if partner was found - */ - virtual ReturnValue_t reply( MessageQueueMessageIF* message ) = 0; - - /** - * @brief This function reads available messages from the message queue and returns the sender. - * @details It works identically to the other receiveMessage call, but in addition returns the - * sender's queue id. - * @param message A pointer to a message in which the received data is stored. - * @param receivedFrom A pointer to a queue id in which the sender's id is stored. - */ - virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message, - MessageQueueId_t *receivedFrom) = 0; - - /** - * @brief This function reads available messages from the message queue. - * @details - * If data is available it is stored in the passed message pointer. - * The message's original content is overwritten and the sendFrom - * information is stored in theblastPartner attribute. Else, the lastPartner - * information remains untouched, the message's content is cleared and the - * function returns immediately. - * @param message A pointer to a message in which the received data is stored. - * @return -@c RETURN_OK on success - * -@c MessageQueueIF::EMPTY if queue is empty - */ - virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message) = 0; - /** - * Deletes all pending messages in the queue. - * @param count The number of flushed messages. - * @return RETURN_OK on success. - */ - virtual ReturnValue_t flush(uint32_t* count) = 0; - /** - * @brief This method returns the message queue id of the last communication partner. - */ - virtual MessageQueueId_t getLastPartner() const = 0; - /** - * @brief This method returns the message queue id of this class's message queue. - */ - virtual MessageQueueId_t getId() const = 0; - - /** - * @brief With the sendMessage call, a queue message is sent to a receiving queue. - * @details This method takes the message provided, adds the sentFrom information and passes - * it on to the destination provided with an operating system call. The OS's return - * value is returned. - * @param sendTo This parameter specifies the message queue id to send the message to. - * @param message This is a pointer to a previously created message, which is sent. - * @param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. - * This variable is set to zero by default. - * @param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full (if implemented). - * @return -@c RETURN_OK on success - * -@c MessageQueueIF::FULL if queue is full - */ - virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo, - MessageQueueMessageIF* message, MessageQueueId_t sentFrom, - bool ignoreFault = false ) = 0; - - /** - * @brief This operation sends a message to the given destination. - * @details It directly uses the sendMessage call of the MessageQueueSender parent, but passes its - * queue id as "sentFrom" parameter. - * @param sendTo This parameter specifies the message queue id of the destination message queue. - * @param message A pointer to a previously created message, which is sent. - * @param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. - */ - virtual ReturnValue_t sendMessage( MessageQueueId_t sendTo, - MessageQueueMessageIF* message, bool ignoreFault = false ) = 0; - - /** - * @brief The sendToDefaultFrom method sends a queue message to the default destination. - * @details In all other aspects, it works identical to the sendMessage method. - * @param message This is a pointer to a previously created message, which is sent. - * @param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. - * This variable is set to zero by default. - * @return -@c RETURN_OK on success - * -@c MessageQueueIF::FULL if queue is full - */ - virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessageIF* message, - MessageQueueId_t sentFrom, bool ignoreFault = false ) = 0; - /** - * @brief This operation sends a message to the default destination. - * @details As in the sendMessage method, this function uses the sendToDefault call of the - * Implementation class and adds its queue id as "sentFrom" information. - * @param message A pointer to a previously created message, which is sent. - * @return -@c RETURN_OK on success - * -@c MessageQueueIF::FULL if queue is full - */ - virtual ReturnValue_t sendToDefault( MessageQueueMessageIF* message ) = 0; - /** - * \brief This method is a simple setter for the default destination. - */ - virtual void setDefaultDestination(MessageQueueId_t defaultDestination) = 0; - /** - * \brief This method is a simple getter for the default destination. - */ - virtual MessageQueueId_t getDefaultDestination() const = 0; - - virtual bool isDefaultDestinationSet() const = 0; -}; - - - -#endif /* FRAMEWORK_IPC_MESSAGEQUEUEIF_H_ */ +#ifndef FRAMEWORK_IPC_MESSAGEQUEUEIF_H_ +#define FRAMEWORK_IPC_MESSAGEQUEUEIF_H_ + +// COULDDO: We could support blocking calls +// semaphores are being implemented, which makes this idea even more iteresting. + + +/** + * @defgroup message_queue Message Queue + * @brief Message Queue related software components + */ + +#include "../ipc/MessageQueueMessage.h" +#include "../ipc/MessageQueueSenderIF.h" +#include "../returnvalues/HasReturnvaluesIF.h" +class MessageQueueIF { +public: + static const MessageQueueId_t NO_QUEUE = MessageQueueMessageIF::NO_QUEUE; //!< Ugly hack. + + static const uint8_t INTERFACE_ID = CLASS_ID::MESSAGE_QUEUE_IF; + //! No new messages on the queue + static const ReturnValue_t EMPTY = MAKE_RETURN_CODE(1); + //! No space left for more messages + static const ReturnValue_t FULL = MAKE_RETURN_CODE(2); + //! Returned if a reply method was called without partner + static const ReturnValue_t NO_REPLY_PARTNER = MAKE_RETURN_CODE(3); + //! Returned if the target destination is invalid. + static constexpr ReturnValue_t DESTINVATION_INVALID = MAKE_RETURN_CODE(4); + + virtual ~MessageQueueIF() {} + /** + * @brief This operation sends a message to the last communication partner. + * @details This operation simplifies answering an incoming message by using the stored + * lastParnter information as destination. If there was no message received yet + * (i.e. lastPartner is zero), an error code is returned. + * @param message A pointer to a previously created message, which is sent. + * @return RETURN_OK if ok + * @return NO_REPLY_PARTNER Should return NO_REPLY_PARTNER if partner was found + */ + virtual ReturnValue_t reply( MessageQueueMessageIF* message ) = 0; + + /** + * @brief This function reads available messages from the message queue and returns the sender. + * @details It works identically to the other receiveMessage call, but in addition returns the + * sender's queue id. + * @param message A pointer to a message in which the received data is stored. + * @param receivedFrom A pointer to a queue id in which the sender's id is stored. + */ + virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message, + MessageQueueId_t *receivedFrom) = 0; + + /** + * @brief This function reads available messages from the message queue. + * @details + * If data is available it is stored in the passed message pointer. + * The message's original content is overwritten and the sendFrom + * information is stored in theblastPartner attribute. Else, the lastPartner + * information remains untouched, the message's content is cleared and the + * function returns immediately. + * @param message A pointer to a message in which the received data is stored. + * @return -@c RETURN_OK on success + * -@c MessageQueueIF::EMPTY if queue is empty + */ + virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message) = 0; + /** + * Deletes all pending messages in the queue. + * @param count The number of flushed messages. + * @return RETURN_OK on success. + */ + virtual ReturnValue_t flush(uint32_t* count) = 0; + /** + * @brief This method returns the message queue id of the last communication partner. + */ + virtual MessageQueueId_t getLastPartner() const = 0; + /** + * @brief This method returns the message queue id of this class's message queue. + */ + virtual MessageQueueId_t getId() const = 0; + + /** + * @brief With the sendMessage call, a queue message is sent to a receiving queue. + * @details This method takes the message provided, adds the sentFrom information and passes + * it on to the destination provided with an operating system call. The OS's return + * value is returned. + * @param sendTo This parameter specifies the message queue id to send the message to. + * @param message This is a pointer to a previously created message, which is sent. + * @param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. + * This variable is set to zero by default. + * @param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full (if implemented). + * @return -@c RETURN_OK on success + * -@c MessageQueueIF::FULL if queue is full + */ + virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo, + MessageQueueMessageIF* message, MessageQueueId_t sentFrom, + bool ignoreFault = false ) = 0; + + /** + * @brief This operation sends a message to the given destination. + * @details It directly uses the sendMessage call of the MessageQueueSender parent, but passes its + * queue id as "sentFrom" parameter. + * @param sendTo This parameter specifies the message queue id of the destination message queue. + * @param message A pointer to a previously created message, which is sent. + * @param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. + */ + virtual ReturnValue_t sendMessage( MessageQueueId_t sendTo, + MessageQueueMessageIF* message, bool ignoreFault = false ) = 0; + + /** + * @brief The sendToDefaultFrom method sends a queue message to the default destination. + * @details In all other aspects, it works identical to the sendMessage method. + * @param message This is a pointer to a previously created message, which is sent. + * @param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. + * This variable is set to zero by default. + * @return -@c RETURN_OK on success + * -@c MessageQueueIF::FULL if queue is full + */ + virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessageIF* message, + MessageQueueId_t sentFrom, bool ignoreFault = false ) = 0; + /** + * @brief This operation sends a message to the default destination. + * @details As in the sendMessage method, this function uses the sendToDefault call of the + * Implementation class and adds its queue id as "sentFrom" information. + * @param message A pointer to a previously created message, which is sent. + * @return -@c RETURN_OK on success + * -@c MessageQueueIF::FULL if queue is full + */ + virtual ReturnValue_t sendToDefault( MessageQueueMessageIF* message ) = 0; + /** + * \brief This method is a simple setter for the default destination. + */ + virtual void setDefaultDestination(MessageQueueId_t defaultDestination) = 0; + /** + * \brief This method is a simple getter for the default destination. + */ + virtual MessageQueueId_t getDefaultDestination() const = 0; + + virtual bool isDefaultDestinationSet() const = 0; +}; + + + +#endif /* FRAMEWORK_IPC_MESSAGEQUEUEIF_H_ */ diff --git a/ipc/MessageQueueMessage.cpp b/ipc/MessageQueueMessage.cpp index 0f4d861b..d0032129 100644 --- a/ipc/MessageQueueMessage.cpp +++ b/ipc/MessageQueueMessage.cpp @@ -1,84 +1,84 @@ -#include -#include -#include -#include - -MessageQueueMessage::MessageQueueMessage() : - messageSize(getMinimumMessageSize()) { - memset(this->internalBuffer, 0, sizeof(this->internalBuffer)); -} - -MessageQueueMessage::MessageQueueMessage(uint8_t* data, size_t size) : - messageSize(this->HEADER_SIZE + size) { - if (size <= this->MAX_DATA_SIZE) { - memcpy(this->getData(), data, size); - this->messageSize = this->HEADER_SIZE + size; - } - else { - sif::warning << "MessageQueueMessage: Passed size larger than maximum" - "allowed size! Setting content to 0" << std::endl; - memset(this->internalBuffer, 0, sizeof(this->internalBuffer)); - this->messageSize = this->HEADER_SIZE; - } -} - -MessageQueueMessage::~MessageQueueMessage() { -} - -const uint8_t* MessageQueueMessage::getBuffer() const { - return this->internalBuffer; -} - -uint8_t* MessageQueueMessage::getBuffer() { - return this->internalBuffer; -} - -const uint8_t* MessageQueueMessage::getData() const { - return this->internalBuffer + this->HEADER_SIZE; -} - -uint8_t* MessageQueueMessage::getData() { - return this->internalBuffer + this->HEADER_SIZE; -} - -MessageQueueId_t MessageQueueMessage::getSender() const { - MessageQueueId_t temp_id; - memcpy(&temp_id, this->internalBuffer, sizeof(MessageQueueId_t)); - return temp_id; -} - -void MessageQueueMessage::setSender(MessageQueueId_t setId) { - memcpy(this->internalBuffer, &setId, sizeof(MessageQueueId_t)); -} - -void MessageQueueMessage::print(bool printWholeMessage) { - sif::debug << "MessageQueueMessage content: " << std::endl; - if(printWholeMessage) { - arrayprinter::print(getData(), getMaximumMessageSize()); - } - else { - arrayprinter::print(getData(), getMessageSize()); - } - -} - -void MessageQueueMessage::clear() { - memset(this->getBuffer(), 0, this->MAX_MESSAGE_SIZE); -} - -size_t MessageQueueMessage::getMessageSize() const { - return this->messageSize; -} - -void MessageQueueMessage::setMessageSize(size_t messageSize) { - this->messageSize = messageSize; -} - -size_t MessageQueueMessage::getMinimumMessageSize() const { - return this->MIN_MESSAGE_SIZE; -} - -size_t MessageQueueMessage::getMaximumMessageSize() const { - return this->MAX_MESSAGE_SIZE; -} - +#include "../ipc/MessageQueueMessage.h" +#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../globalfunctions/arrayprinter.h" +#include + +MessageQueueMessage::MessageQueueMessage() : + messageSize(getMinimumMessageSize()) { + memset(this->internalBuffer, 0, sizeof(this->internalBuffer)); +} + +MessageQueueMessage::MessageQueueMessage(uint8_t* data, size_t size) : + messageSize(this->HEADER_SIZE + size) { + if (size <= this->MAX_DATA_SIZE) { + memcpy(this->getData(), data, size); + this->messageSize = this->HEADER_SIZE + size; + } + else { + sif::warning << "MessageQueueMessage: Passed size larger than maximum" + "allowed size! Setting content to 0" << std::endl; + memset(this->internalBuffer, 0, sizeof(this->internalBuffer)); + this->messageSize = this->HEADER_SIZE; + } +} + +MessageQueueMessage::~MessageQueueMessage() { +} + +const uint8_t* MessageQueueMessage::getBuffer() const { + return this->internalBuffer; +} + +uint8_t* MessageQueueMessage::getBuffer() { + return this->internalBuffer; +} + +const uint8_t* MessageQueueMessage::getData() const { + return this->internalBuffer + this->HEADER_SIZE; +} + +uint8_t* MessageQueueMessage::getData() { + return this->internalBuffer + this->HEADER_SIZE; +} + +MessageQueueId_t MessageQueueMessage::getSender() const { + MessageQueueId_t temp_id; + memcpy(&temp_id, this->internalBuffer, sizeof(MessageQueueId_t)); + return temp_id; +} + +void MessageQueueMessage::setSender(MessageQueueId_t setId) { + memcpy(this->internalBuffer, &setId, sizeof(MessageQueueId_t)); +} + +void MessageQueueMessage::print(bool printWholeMessage) { + sif::debug << "MessageQueueMessage content: " << std::endl; + if(printWholeMessage) { + arrayprinter::print(getData(), getMaximumMessageSize()); + } + else { + arrayprinter::print(getData(), getMessageSize()); + } + +} + +void MessageQueueMessage::clear() { + memset(this->getBuffer(), 0, this->MAX_MESSAGE_SIZE); +} + +size_t MessageQueueMessage::getMessageSize() const { + return this->messageSize; +} + +void MessageQueueMessage::setMessageSize(size_t messageSize) { + this->messageSize = messageSize; +} + +size_t MessageQueueMessage::getMinimumMessageSize() const { + return this->MIN_MESSAGE_SIZE; +} + +size_t MessageQueueMessage::getMaximumMessageSize() const { + return this->MAX_MESSAGE_SIZE; +} + diff --git a/ipc/MessageQueueMessage.h b/ipc/MessageQueueMessage.h index 3d5d4283..cf06fde6 100644 --- a/ipc/MessageQueueMessage.h +++ b/ipc/MessageQueueMessage.h @@ -1,150 +1,150 @@ -#ifndef FRAMEWORK_IPC_MESSAGEQUEUEMESSAGE_H_ -#define FRAMEWORK_IPC_MESSAGEQUEUEMESSAGE_H_ - -#include -#include -#include - -/** - * @brief This class is the representation and data organizer - * for interprocess messages. - * @details - * To facilitate and standardize interprocess communication, this class was - * created to handle a lightweight "interprocess message protocol". - * - * It adds a header with the sender's queue id to every sent message and - * defines the maximum total message size. Specialized messages, such as - * device commanding messages, can be created by inheriting from this class - * and filling the buffer provided by getData with additional content. - * - * If larger amounts of data must be sent between processes, the data shall - * be stored in the IPC Store object and only the storage id is passed in a - * queue message.The class is used both to generate and send messages and to - * receive messages from other tasks. - * @ingroup message_queue - */ -class MessageQueueMessage: public MessageQueueMessageIF { -public: - /** - * @brief The class is initialized empty with this constructor. - * @details - * The messageSize attribute is set to the header's size and the whole - * content is set to zero. - */ - MessageQueueMessage(); - /** - * @brief With this constructor the class is initialized with - * the given content. - * @details - * If the passed message size fits into the buffer, the passed data is - * copied to the internal buffer and the messageSize information is set. - * Otherwise, messageSize is set to the header's size and the whole - * content is set to zero. - * @param data The data to be put in the message. - * @param size Size of the data to be copied. Must be smaller than - * MAX_MESSAGE_SIZE and larger than MIN_MESSAGE_SIZE. - */ - MessageQueueMessage(uint8_t* data, size_t size); - - /** - * @brief As no memory is allocated in this class, - * the destructor is empty. - */ - virtual ~MessageQueueMessage(); - - /** - * @brief The size information of each message is stored in - * this attribute. - * @details - * It is public to simplify usage and to allow for passing the size - * address as a pointer. Care must be taken when inheriting from this class, - * as every child class is responsible for managing the size information by - * itself. When using the class to receive a message, the size information - * is updated automatically. - * - * Please note that the minimum size is limited by the size of the header - * while the maximum size is limited by the maximum allowed message size. - */ - size_t messageSize; - /** - * @brief This constant defines the maximum size of the data content, - * excluding the header. - * @details - * It may be changed if necessary, but in general should be kept - * as small as possible. - */ - static const size_t MAX_DATA_SIZE = 24; - - /** - * @brief This constant defines the maximum total size in bytes - * of a sent message. - * @details - * It is the sum of the maximum data and the header size. Be aware that - * this constant is used to define the buffer sizes for every message - * queue in the system. So, a change here may have significant impact on - * the required resources. - */ - static constexpr size_t MAX_MESSAGE_SIZE = MAX_DATA_SIZE + HEADER_SIZE; - /** - * @brief Defines the minimum size of a message where only the - * header is included - */ - static constexpr size_t MIN_MESSAGE_SIZE = HEADER_SIZE; -private: - /** - * @brief This is the internal buffer that contains the - * actual message data. - */ - uint8_t internalBuffer[MAX_MESSAGE_SIZE]; -public: - /** - * @brief This method is used to get the complete data of the message. - */ - const uint8_t* getBuffer() const override; - /** - * @brief This method is used to get the complete data of the message. - */ - uint8_t* getBuffer() override; - /** - * @brief This method is used to fetch the data content of the message. - * @details - * It shall be used by child classes to add data at the right position. - */ - const uint8_t* getData() const override; - /** - * @brief This method is used to fetch the data content of the message. - * @details - * It shall be used by child classes to add data at the right position. - */ - uint8_t* getData() override; - /** - * @brief This method is used to extract the sender's message - * queue id information from a received message. - */ - MessageQueueId_t getSender() const override; - /** - * @brief With this method, the whole content - * and the message size is set to zero. - */ - void clear() override; - - /** - * @brief This method is used to set the sender's message queue id - * information prior to ing the message. - * @param setId - * The message queue id that identifies the sending message queue. - */ - void setSender(MessageQueueId_t setId) override; - - virtual size_t getMessageSize() const override; - virtual void setMessageSize(size_t messageSize) override; - virtual size_t getMinimumMessageSize() const override; - virtual size_t getMaximumMessageSize() const override; - - /** - * @brief This is a debug method that prints the content. - */ - void print(bool printWholeMessage); -}; - -#endif /* MESSAGEQUEUEMESSAGE_H_ */ +#ifndef FRAMEWORK_IPC_MESSAGEQUEUEMESSAGE_H_ +#define FRAMEWORK_IPC_MESSAGEQUEUEMESSAGE_H_ + +#include "../ipc/MessageQueueMessageIF.h" +#include "../ipc/MessageQueueSenderIF.h" +#include + +/** + * @brief This class is the representation and data organizer + * for interprocess messages. + * @details + * To facilitate and standardize interprocess communication, this class was + * created to handle a lightweight "interprocess message protocol". + * + * It adds a header with the sender's queue id to every sent message and + * defines the maximum total message size. Specialized messages, such as + * device commanding messages, can be created by inheriting from this class + * and filling the buffer provided by getData with additional content. + * + * If larger amounts of data must be sent between processes, the data shall + * be stored in the IPC Store object and only the storage id is passed in a + * queue message.The class is used both to generate and send messages and to + * receive messages from other tasks. + * @ingroup message_queue + */ +class MessageQueueMessage: public MessageQueueMessageIF { +public: + /** + * @brief The class is initialized empty with this constructor. + * @details + * The messageSize attribute is set to the header's size and the whole + * content is set to zero. + */ + MessageQueueMessage(); + /** + * @brief With this constructor the class is initialized with + * the given content. + * @details + * If the passed message size fits into the buffer, the passed data is + * copied to the internal buffer and the messageSize information is set. + * Otherwise, messageSize is set to the header's size and the whole + * content is set to zero. + * @param data The data to be put in the message. + * @param size Size of the data to be copied. Must be smaller than + * MAX_MESSAGE_SIZE and larger than MIN_MESSAGE_SIZE. + */ + MessageQueueMessage(uint8_t* data, size_t size); + + /** + * @brief As no memory is allocated in this class, + * the destructor is empty. + */ + virtual ~MessageQueueMessage(); + + /** + * @brief The size information of each message is stored in + * this attribute. + * @details + * It is public to simplify usage and to allow for passing the size + * address as a pointer. Care must be taken when inheriting from this class, + * as every child class is responsible for managing the size information by + * itself. When using the class to receive a message, the size information + * is updated automatically. + * + * Please note that the minimum size is limited by the size of the header + * while the maximum size is limited by the maximum allowed message size. + */ + size_t messageSize; + /** + * @brief This constant defines the maximum size of the data content, + * excluding the header. + * @details + * It may be changed if necessary, but in general should be kept + * as small as possible. + */ + static const size_t MAX_DATA_SIZE = 24; + + /** + * @brief This constant defines the maximum total size in bytes + * of a sent message. + * @details + * It is the sum of the maximum data and the header size. Be aware that + * this constant is used to define the buffer sizes for every message + * queue in the system. So, a change here may have significant impact on + * the required resources. + */ + static constexpr size_t MAX_MESSAGE_SIZE = MAX_DATA_SIZE + HEADER_SIZE; + /** + * @brief Defines the minimum size of a message where only the + * header is included + */ + static constexpr size_t MIN_MESSAGE_SIZE = HEADER_SIZE; +private: + /** + * @brief This is the internal buffer that contains the + * actual message data. + */ + uint8_t internalBuffer[MAX_MESSAGE_SIZE]; +public: + /** + * @brief This method is used to get the complete data of the message. + */ + const uint8_t* getBuffer() const override; + /** + * @brief This method is used to get the complete data of the message. + */ + uint8_t* getBuffer() override; + /** + * @brief This method is used to fetch the data content of the message. + * @details + * It shall be used by child classes to add data at the right position. + */ + const uint8_t* getData() const override; + /** + * @brief This method is used to fetch the data content of the message. + * @details + * It shall be used by child classes to add data at the right position. + */ + uint8_t* getData() override; + /** + * @brief This method is used to extract the sender's message + * queue id information from a received message. + */ + MessageQueueId_t getSender() const override; + /** + * @brief With this method, the whole content + * and the message size is set to zero. + */ + void clear() override; + + /** + * @brief This method is used to set the sender's message queue id + * information prior to ing the message. + * @param setId + * The message queue id that identifies the sending message queue. + */ + void setSender(MessageQueueId_t setId) override; + + virtual size_t getMessageSize() const override; + virtual void setMessageSize(size_t messageSize) override; + virtual size_t getMinimumMessageSize() const override; + virtual size_t getMaximumMessageSize() const override; + + /** + * @brief This is a debug method that prints the content. + */ + void print(bool printWholeMessage); +}; + +#endif /* MESSAGEQUEUEMESSAGE_H_ */ diff --git a/ipc/MessageQueueSenderIF.h b/ipc/MessageQueueSenderIF.h index e4b9670e..80623157 100644 --- a/ipc/MessageQueueSenderIF.h +++ b/ipc/MessageQueueSenderIF.h @@ -1,25 +1,25 @@ -#ifndef FRAMEWORK_IPC_MESSAGEQUEUESENDERIF_H_ -#define FRAMEWORK_IPC_MESSAGEQUEUESENDERIF_H_ - -#include -#include - -class MessageQueueSenderIF { -public: - - virtual ~MessageQueueSenderIF() {} - - /** - * Allows sending messages without actually "owning" a message queue. - * Not sure whether this is actually a good idea. - */ - static ReturnValue_t sendMessage(MessageQueueId_t sendTo, - MessageQueueMessageIF* message, - MessageQueueId_t sentFrom = MessageQueueMessageIF::NO_QUEUE, - bool ignoreFault = false); -private: - MessageQueueSenderIF() {} -}; - - -#endif /* FRAMEWORK_IPC_MESSAGEQUEUESENDERIF_H_ */ +#ifndef FRAMEWORK_IPC_MESSAGEQUEUESENDERIF_H_ +#define FRAMEWORK_IPC_MESSAGEQUEUESENDERIF_H_ + +#include "../ipc/MessageQueueMessageIF.h" +#include "../objectmanager/ObjectManagerIF.h" + +class MessageQueueSenderIF { +public: + + virtual ~MessageQueueSenderIF() {} + + /** + * Allows sending messages without actually "owning" a message queue. + * Not sure whether this is actually a good idea. + */ + static ReturnValue_t sendMessage(MessageQueueId_t sendTo, + MessageQueueMessageIF* message, + MessageQueueId_t sentFrom = MessageQueueMessageIF::NO_QUEUE, + bool ignoreFault = false); +private: + MessageQueueSenderIF() {} +}; + + +#endif /* FRAMEWORK_IPC_MESSAGEQUEUESENDERIF_H_ */ diff --git a/ipc/MutexFactory.h b/ipc/MutexFactory.h index b2e58b6e..91e90907 100644 --- a/ipc/MutexFactory.h +++ b/ipc/MutexFactory.h @@ -1,34 +1,34 @@ -#ifndef FRAMEWORK_IPC_MUTEXFACTORY_H_ -#define FRAMEWORK_IPC_MUTEXFACTORY_H_ - -#include -/** - * Creates Mutex. - * This class is a "singleton" interface, i.e. it provides an - * interface, but also is the base class for a singleton. - */ -class MutexFactory { -public: - virtual ~MutexFactory(); - /** - * Returns the single instance of MutexFactory. - * The implementation of #instance is found in its subclasses. - * Thus, we choose link-time variability of the instance. - */ - static MutexFactory* instance(); - - MutexIF* createMutex(); - - void deleteMutex(MutexIF* mutex); - -private: - /** - * External instantiation is not allowed. - */ - MutexFactory(); - static MutexFactory* factoryInstance; -}; - - - -#endif /* FRAMEWORK_IPC_MUTEXFACTORY_H_ */ +#ifndef FRAMEWORK_IPC_MUTEXFACTORY_H_ +#define FRAMEWORK_IPC_MUTEXFACTORY_H_ + +#include "../ipc/MutexIF.h" +/** + * Creates Mutex. + * This class is a "singleton" interface, i.e. it provides an + * interface, but also is the base class for a singleton. + */ +class MutexFactory { +public: + virtual ~MutexFactory(); + /** + * Returns the single instance of MutexFactory. + * The implementation of #instance is found in its subclasses. + * Thus, we choose link-time variability of the instance. + */ + static MutexFactory* instance(); + + MutexIF* createMutex(); + + void deleteMutex(MutexIF* mutex); + +private: + /** + * External instantiation is not allowed. + */ + MutexFactory(); + static MutexFactory* factoryInstance; +}; + + + +#endif /* FRAMEWORK_IPC_MUTEXFACTORY_H_ */ diff --git a/ipc/MutexHelper.h b/ipc/MutexHelper.h index 52ce51e3..31d8d9ec 100644 --- a/ipc/MutexHelper.h +++ b/ipc/MutexHelper.h @@ -1,30 +1,30 @@ -#ifndef FRAMEWORK_IPC_MUTEXHELPER_H_ -#define FRAMEWORK_IPC_MUTEXHELPER_H_ - -#include -#include - -class MutexHelper { -public: - MutexHelper(MutexIF* mutex, MutexIF::TimeoutType timeoutType = - MutexIF::TimeoutType::BLOCKING, uint32_t timeoutMs = 0) : - internalMutex(mutex) { - ReturnValue_t status = mutex->lockMutex(timeoutType, - timeoutMs); - if(status == MutexIF::MUTEX_TIMEOUT) { - sif::error << "MutexHelper: Lock of mutex failed with timeout of " - << timeoutMs << " milliseconds!" << std::endl; - } - else if(status != HasReturnvaluesIF::RETURN_OK){ - sif::error << "MutexHelper: Lock of Mutex failed with code " << - status << std::endl; - } - } - - ~MutexHelper() { - internalMutex->unlockMutex(); - } -private: - MutexIF* internalMutex; -}; -#endif /* FRAMEWORK_IPC_MUTEXHELPER_H_ */ +#ifndef FRAMEWORK_IPC_MUTEXHELPER_H_ +#define FRAMEWORK_IPC_MUTEXHELPER_H_ + +#include "../ipc/MutexFactory.h" +#include "../serviceinterface/ServiceInterfaceStream.h" + +class MutexHelper { +public: + MutexHelper(MutexIF* mutex, MutexIF::TimeoutType timeoutType = + MutexIF::TimeoutType::BLOCKING, uint32_t timeoutMs = 0) : + internalMutex(mutex) { + ReturnValue_t status = mutex->lockMutex(timeoutType, + timeoutMs); + if(status == MutexIF::MUTEX_TIMEOUT) { + sif::error << "MutexHelper: Lock of mutex failed with timeout of " + << timeoutMs << " milliseconds!" << std::endl; + } + else if(status != HasReturnvaluesIF::RETURN_OK){ + sif::error << "MutexHelper: Lock of Mutex failed with code " << + status << std::endl; + } + } + + ~MutexHelper() { + internalMutex->unlockMutex(); + } +private: + MutexIF* internalMutex; +}; +#endif /* FRAMEWORK_IPC_MUTEXHELPER_H_ */ diff --git a/ipc/MutexIF.h b/ipc/MutexIF.h index b0096a34..7bca4c9d 100644 --- a/ipc/MutexIF.h +++ b/ipc/MutexIF.h @@ -1,89 +1,89 @@ -#ifndef FRAMEWORK_IPC_MUTEXIF_H_ -#define FRAMEWORK_IPC_MUTEXIF_H_ - -#include - -/** - * @brief Common interface for OS Mutex objects which provide MUTual EXclusion. - * @details https://en.wikipedia.org/wiki/Lock_(computer_science) - * @ingroup osal - * @ingroup interface - */ -class MutexIF { -public: - /** - * Different types of timeout for the mutex lock. - */ - enum TimeoutType { - POLLING, //!< If mutex is not available, return immediately - WAITING, //!< Wait a specified time for the mutex to become available - BLOCKING //!< Block indefinitely until the mutex becomes available. - }; - - /** - * Lock the mutex. The timeout value will only be used for - * TimeoutType::WAITING - * @param timeoutType - * @param timeoutMs - * @return - */ - virtual ReturnValue_t lockMutex(TimeoutType timeoutType = - TimeoutType::BLOCKING, uint32_t timeoutMs = 0) = 0; - virtual ReturnValue_t unlockMutex() = 0; - - static const uint8_t INTERFACE_ID = CLASS_ID::MUTEX_IF; - /** - * The system lacked the necessary resources (other than memory) to initialize another mutex. - */ - static const ReturnValue_t NOT_ENOUGH_RESOURCES = MAKE_RETURN_CODE(1); - /** - * Insufficient memory to create or init Mutex - */ - static const ReturnValue_t INSUFFICIENT_MEMORY = MAKE_RETURN_CODE(2); - /** - * Caller does not have enough or right privilege - */ - static const ReturnValue_t NO_PRIVILEGE = MAKE_RETURN_CODE(3); - /** - * Wrong Attribute Setting - */ - static const ReturnValue_t WRONG_ATTRIBUTE_SETTING = MAKE_RETURN_CODE(4); - /** - * The mutex is already locked - */ - static const ReturnValue_t MUTEX_ALREADY_LOCKED = MAKE_RETURN_CODE(5); - /** - * Mutex object not found - */ - static const ReturnValue_t MUTEX_NOT_FOUND = MAKE_RETURN_CODE(6); - /** - * Mutex could not be locked because max amount of recursive locks - */ - static const ReturnValue_t MUTEX_MAX_LOCKS = MAKE_RETURN_CODE(7); - /** - * The current thread already owns this mutex - */ - static const ReturnValue_t CURR_THREAD_ALREADY_OWNS_MUTEX = MAKE_RETURN_CODE(8); - /** - * Current thread does not own this mutex - */ - static const ReturnValue_t CURR_THREAD_DOES_NOT_OWN_MUTEX = MAKE_RETURN_CODE(9); - /** - * The Mutex could not be blocked before timeout - */ - static const ReturnValue_t MUTEX_TIMEOUT = MAKE_RETURN_CODE(10); - /** - * Invalid Mutex ID - */ - static const ReturnValue_t MUTEX_INVALID_ID = MAKE_RETURN_CODE(11); - /** - * Mutex destroyed while waiting - */ - static const ReturnValue_t MUTEX_DESTROYED_WHILE_WAITING = MAKE_RETURN_CODE(12); - - virtual ~MutexIF() {} -}; - - - -#endif /* FRAMEWORK_IPC_MUTEXIF_H_ */ +#ifndef FRAMEWORK_IPC_MUTEXIF_H_ +#define FRAMEWORK_IPC_MUTEXIF_H_ + +#include "../returnvalues/HasReturnvaluesIF.h" + +/** + * @brief Common interface for OS Mutex objects which provide MUTual EXclusion. + * @details https://en.wikipedia.org/wiki/Lock_(computer_science) + * @ingroup osal + * @ingroup interface + */ +class MutexIF { +public: + /** + * Different types of timeout for the mutex lock. + */ + enum TimeoutType { + POLLING, //!< If mutex is not available, return immediately + WAITING, //!< Wait a specified time for the mutex to become available + BLOCKING //!< Block indefinitely until the mutex becomes available. + }; + + /** + * Lock the mutex. The timeout value will only be used for + * TimeoutType::WAITING + * @param timeoutType + * @param timeoutMs + * @return + */ + virtual ReturnValue_t lockMutex(TimeoutType timeoutType = + TimeoutType::BLOCKING, uint32_t timeoutMs = 0) = 0; + virtual ReturnValue_t unlockMutex() = 0; + + static const uint8_t INTERFACE_ID = CLASS_ID::MUTEX_IF; + /** + * The system lacked the necessary resources (other than memory) to initialize another mutex. + */ + static const ReturnValue_t NOT_ENOUGH_RESOURCES = MAKE_RETURN_CODE(1); + /** + * Insufficient memory to create or init Mutex + */ + static const ReturnValue_t INSUFFICIENT_MEMORY = MAKE_RETURN_CODE(2); + /** + * Caller does not have enough or right privilege + */ + static const ReturnValue_t NO_PRIVILEGE = MAKE_RETURN_CODE(3); + /** + * Wrong Attribute Setting + */ + static const ReturnValue_t WRONG_ATTRIBUTE_SETTING = MAKE_RETURN_CODE(4); + /** + * The mutex is already locked + */ + static const ReturnValue_t MUTEX_ALREADY_LOCKED = MAKE_RETURN_CODE(5); + /** + * Mutex object not found + */ + static const ReturnValue_t MUTEX_NOT_FOUND = MAKE_RETURN_CODE(6); + /** + * Mutex could not be locked because max amount of recursive locks + */ + static const ReturnValue_t MUTEX_MAX_LOCKS = MAKE_RETURN_CODE(7); + /** + * The current thread already owns this mutex + */ + static const ReturnValue_t CURR_THREAD_ALREADY_OWNS_MUTEX = MAKE_RETURN_CODE(8); + /** + * Current thread does not own this mutex + */ + static const ReturnValue_t CURR_THREAD_DOES_NOT_OWN_MUTEX = MAKE_RETURN_CODE(9); + /** + * The Mutex could not be blocked before timeout + */ + static const ReturnValue_t MUTEX_TIMEOUT = MAKE_RETURN_CODE(10); + /** + * Invalid Mutex ID + */ + static const ReturnValue_t MUTEX_INVALID_ID = MAKE_RETURN_CODE(11); + /** + * Mutex destroyed while waiting + */ + static const ReturnValue_t MUTEX_DESTROYED_WHILE_WAITING = MAKE_RETURN_CODE(12); + + virtual ~MutexIF() {} +}; + + + +#endif /* FRAMEWORK_IPC_MUTEXIF_H_ */ diff --git a/ipc/QueueFactory.h b/ipc/QueueFactory.h index 09259ae3..8141a3cf 100644 --- a/ipc/QueueFactory.h +++ b/ipc/QueueFactory.h @@ -1,33 +1,33 @@ -#ifndef FRAMEWORK_IPC_QUEUEFACTORY_H_ -#define FRAMEWORK_IPC_QUEUEFACTORY_H_ - -#include -#include -/** - * Creates message queues. - * This class is a "singleton" interface, i.e. it provides an - * interface, but also is the base class for a singleton. - */ -class QueueFactory { -public: - virtual ~QueueFactory(); - /** - * Returns the single instance of QueueFactory. - * The implementation of #instance is found in its subclasses. - * Thus, we choose link-time variability of the instance. - */ - static QueueFactory* instance(); - - MessageQueueIF* createMessageQueue(uint32_t messageDepth = 3, - size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE); - - void deleteMessageQueue(MessageQueueIF* queue); -private: - /** - * External instantiation is not allowed. - */ - QueueFactory(); - static QueueFactory* factoryInstance; -}; - -#endif /* FRAMEWORK_IPC_QUEUEFACTORY_H_ */ +#ifndef FRAMEWORK_IPC_QUEUEFACTORY_H_ +#define FRAMEWORK_IPC_QUEUEFACTORY_H_ + +#include "../ipc/MessageQueueIF.h" +#include +/** + * Creates message queues. + * This class is a "singleton" interface, i.e. it provides an + * interface, but also is the base class for a singleton. + */ +class QueueFactory { +public: + virtual ~QueueFactory(); + /** + * Returns the single instance of QueueFactory. + * The implementation of #instance is found in its subclasses. + * Thus, we choose link-time variability of the instance. + */ + static QueueFactory* instance(); + + MessageQueueIF* createMessageQueue(uint32_t messageDepth = 3, + size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE); + + void deleteMessageQueue(MessageQueueIF* queue); +private: + /** + * External instantiation is not allowed. + */ + QueueFactory(); + static QueueFactory* factoryInstance; +}; + +#endif /* FRAMEWORK_IPC_QUEUEFACTORY_H_ */ diff --git a/memory/AcceptsMemoryMessagesIF.h b/memory/AcceptsMemoryMessagesIF.h index 2b37f1af..044f2236 100644 --- a/memory/AcceptsMemoryMessagesIF.h +++ b/memory/AcceptsMemoryMessagesIF.h @@ -1,21 +1,21 @@ -/** - * @file AcceptsMemoryMessagesIF.h - * @brief This file defines the AcceptsMemoryMessagesIF class. - * @date 11.07.2013 - * @author baetz - */ - -#ifndef ACCEPTSMEMORYMESSAGESIF_H_ -#define ACCEPTSMEMORYMESSAGESIF_H_ - -#include -#include -#include - -class AcceptsMemoryMessagesIF : public HasMemoryIF { -public: - virtual MessageQueueId_t getCommandQueue() const = 0; -}; - - -#endif /* ACCEPTSMEMORYMESSAGESIF_H_ */ +/** + * @file AcceptsMemoryMessagesIF.h + * @brief This file defines the AcceptsMemoryMessagesIF class. + * @date 11.07.2013 + * @author baetz + */ + +#ifndef ACCEPTSMEMORYMESSAGESIF_H_ +#define ACCEPTSMEMORYMESSAGESIF_H_ + +#include "../memory/HasMemoryIF.h" +#include "../memory/MemoryMessage.h" +#include "../ipc/MessageQueueSenderIF.h" + +class AcceptsMemoryMessagesIF : public HasMemoryIF { +public: + virtual MessageQueueId_t getCommandQueue() const = 0; +}; + + +#endif /* ACCEPTSMEMORYMESSAGESIF_H_ */ diff --git a/memory/FileSystemMessage.cpp b/memory/FileSystemMessage.cpp index efbc8009..a1c3955f 100644 --- a/memory/FileSystemMessage.cpp +++ b/memory/FileSystemMessage.cpp @@ -1,28 +1,28 @@ -/* - * FileSystemMessage.cpp - * - * Created on: 19.01.2020 - * Author: Jakob Meier - */ - -#include "FileSystemMessage.h" -#include - -ReturnValue_t FileSystemMessage::setWriteToFileCommand(CommandMessage* message, - MessageQueueId_t replyQueueId, store_address_t storageID) { - message->setCommand(WRITE_TO_FILE); - message->setParameter(replyQueueId); - message->setParameter2(storageID.raw); - return HasReturnvaluesIF::RETURN_OK; -} - -store_address_t FileSystemMessage::getStoreID(const CommandMessage* message) { - store_address_t temp; - temp.raw = message->getParameter2(); - return temp; -} - -MessageQueueId_t FileSystemMessage::getReplyQueueId(const CommandMessage* message){ - return message->getParameter(); -} - +/* + * FileSystemMessage.cpp + * + * Created on: 19.01.2020 + * Author: Jakob Meier + */ + +#include "FileSystemMessage.h" +#include "../objectmanager/ObjectManagerIF.h" + +ReturnValue_t FileSystemMessage::setWriteToFileCommand(CommandMessage* message, + MessageQueueId_t replyQueueId, store_address_t storageID) { + message->setCommand(WRITE_TO_FILE); + message->setParameter(replyQueueId); + message->setParameter2(storageID.raw); + return HasReturnvaluesIF::RETURN_OK; +} + +store_address_t FileSystemMessage::getStoreID(const CommandMessage* message) { + store_address_t temp; + temp.raw = message->getParameter2(); + return temp; +} + +MessageQueueId_t FileSystemMessage::getReplyQueueId(const CommandMessage* message){ + return message->getParameter(); +} + diff --git a/memory/FileSystemMessage.h b/memory/FileSystemMessage.h index 9f9c1496..9ef9a2f4 100644 --- a/memory/FileSystemMessage.h +++ b/memory/FileSystemMessage.h @@ -1,30 +1,30 @@ -/* - * FileSystemMessage.h - * - * Created on: 19.01.2020 - * Author: Jakob Meier - */ - -#ifndef FRAMEWORK_MEMORY_FILESYSTEMMESSAGE_H_ -#define FRAMEWORK_MEMORY_FILESYSTEMMESSAGE_H_ - -#include -#include -#include - -class FileSystemMessage { -private: - FileSystemMessage(); //A private ctor inhibits instantiation -public: - static const uint8_t MESSAGE_ID = messagetypes::FILE_SYSTEM_MESSAGE; - static const Command_t CREATE_FILE = MAKE_COMMAND_ID( 0x01 ); - static const Command_t DELETE_FILE = MAKE_COMMAND_ID( 0x02 ); - static const Command_t WRITE_TO_FILE = MAKE_COMMAND_ID( 0x80 ); - - static ReturnValue_t setWriteToFileCommand(CommandMessage* message, MessageQueueId_t replyToQueue, store_address_t storageID ); - static store_address_t getStoreID( const CommandMessage* message ); - static MessageQueueId_t getReplyQueueId(const CommandMessage* message); - -}; - -#endif /* FRAMEWORK_MEMORY_FILESYSTEMMESSAGE_H_ */ +/* + * FileSystemMessage.h + * + * Created on: 19.01.2020 + * Author: Jakob Meier + */ + +#ifndef FRAMEWORK_MEMORY_FILESYSTEMMESSAGE_H_ +#define FRAMEWORK_MEMORY_FILESYSTEMMESSAGE_H_ + +#include "../ipc/CommandMessage.h" +#include "../storagemanager/StorageManagerIF.h" +#include "../objectmanager/SystemObject.h" + +class FileSystemMessage { +private: + FileSystemMessage(); //A private ctor inhibits instantiation +public: + static const uint8_t MESSAGE_ID = messagetypes::FILE_SYSTEM_MESSAGE; + static const Command_t CREATE_FILE = MAKE_COMMAND_ID( 0x01 ); + static const Command_t DELETE_FILE = MAKE_COMMAND_ID( 0x02 ); + static const Command_t WRITE_TO_FILE = MAKE_COMMAND_ID( 0x80 ); + + static ReturnValue_t setWriteToFileCommand(CommandMessage* message, MessageQueueId_t replyToQueue, store_address_t storageID ); + static store_address_t getStoreID( const CommandMessage* message ); + static MessageQueueId_t getReplyQueueId(const CommandMessage* message); + +}; + +#endif /* FRAMEWORK_MEMORY_FILESYSTEMMESSAGE_H_ */ diff --git a/memory/HasFileSystemIF.h b/memory/HasFileSystemIF.h index 8b66f88b..49a2ae54 100644 --- a/memory/HasFileSystemIF.h +++ b/memory/HasFileSystemIF.h @@ -1,36 +1,36 @@ -/* - * HasFileSystemIF.h - * - * Created on: 19.01.2020 - * Author: Jakob Meier - */ - -#ifndef FRAMEWORK_MEMORY_HASFILESYSTEMIF_H_ -#define FRAMEWORK_MEMORY_HASFILESYSTEMIF_H_ - -#include - -class HasFileSystemIF { -public: - - virtual ~HasFileSystemIF() {} - /** - * Function to get the MessageQueueId_t of the implementing object - * @return MessageQueueId_t of the object - */ - virtual MessageQueueId_t getCommandQueue() const = 0; - /** - * Function to write to a file - * @param dirname Directory of the file - * @param filename The filename of the file - * @param data The data to write to the file - * @param size The size of the data to write - * @param packetNumber Counts the number of packets. For large files the write procedure must be split in multiple calls to writeToFile - */ - virtual ReturnValue_t writeToFile(const char* dirname, char* filename, const uint8_t* data, uint32_t size, uint16_t packetNumber) = 0; - virtual ReturnValue_t createFile(const char* dirname, const char* filename, const uint8_t* data, uint32_t size) = 0; - virtual ReturnValue_t deleteFile(const char* dirname, const char* filename) = 0; -}; - - -#endif /* FRAMEWORK_MEMORY_HASFILESYSTEMIF_H_ */ +/* + * HasFileSystemIF.h + * + * Created on: 19.01.2020 + * Author: Jakob Meier + */ + +#ifndef FRAMEWORK_MEMORY_HASFILESYSTEMIF_H_ +#define FRAMEWORK_MEMORY_HASFILESYSTEMIF_H_ + +#include "../returnvalues/HasReturnvaluesIF.h" + +class HasFileSystemIF { +public: + + virtual ~HasFileSystemIF() {} + /** + * Function to get the MessageQueueId_t of the implementing object + * @return MessageQueueId_t of the object + */ + virtual MessageQueueId_t getCommandQueue() const = 0; + /** + * Function to write to a file + * @param dirname Directory of the file + * @param filename The filename of the file + * @param data The data to write to the file + * @param size The size of the data to write + * @param packetNumber Counts the number of packets. For large files the write procedure must be split in multiple calls to writeToFile + */ + virtual ReturnValue_t writeToFile(const char* dirname, char* filename, const uint8_t* data, uint32_t size, uint16_t packetNumber) = 0; + virtual ReturnValue_t createFile(const char* dirname, const char* filename, const uint8_t* data, uint32_t size) = 0; + virtual ReturnValue_t deleteFile(const char* dirname, const char* filename) = 0; +}; + + +#endif /* FRAMEWORK_MEMORY_HASFILESYSTEMIF_H_ */ diff --git a/memory/HasMemoryIF.h b/memory/HasMemoryIF.h index cd6e6665..788a86b6 100644 --- a/memory/HasMemoryIF.h +++ b/memory/HasMemoryIF.h @@ -1,47 +1,47 @@ -#ifndef HASMEMORYIF_H_ -#define HASMEMORYIF_H_ - -#include - -class HasMemoryIF { -public: - static const uint8_t INTERFACE_ID = CLASS_ID::HAS_MEMORY_IF; - static const ReturnValue_t DO_IT_MYSELF = MAKE_RETURN_CODE(1); - static const ReturnValue_t POINTS_TO_VARIABLE = MAKE_RETURN_CODE(2); - static const ReturnValue_t POINTS_TO_MEMORY = MAKE_RETURN_CODE(3); - static const ReturnValue_t ACTIVITY_COMPLETED = MAKE_RETURN_CODE(4); - static const ReturnValue_t POINTS_TO_VECTOR_UINT8 = MAKE_RETURN_CODE(5); - static const ReturnValue_t POINTS_TO_VECTOR_UINT16 = MAKE_RETURN_CODE(6); - static const ReturnValue_t POINTS_TO_VECTOR_UINT32 = MAKE_RETURN_CODE(7); - static const ReturnValue_t POINTS_TO_VECTOR_FLOAT = MAKE_RETURN_CODE(8); - static const ReturnValue_t DUMP_NOT_SUPPORTED = MAKE_RETURN_CODE(0xA0); - static const ReturnValue_t INVALID_SIZE = MAKE_RETURN_CODE(0xE0); - static const ReturnValue_t INVALID_ADDRESS = MAKE_RETURN_CODE(0xE1); - static const ReturnValue_t INVALID_CONTENT = MAKE_RETURN_CODE(0xE2); - static const ReturnValue_t UNALIGNED_ACCESS = MAKE_RETURN_CODE(0xE3); - static const ReturnValue_t WRITE_PROTECTED = MAKE_RETURN_CODE(0xE4); -// static const ReturnValue_t TARGET_BUSY = MAKE_RETURN_CODE(0xE5); - virtual ~HasMemoryIF() {} - virtual ReturnValue_t handleMemoryLoad(uint32_t address, const uint8_t* data, uint32_t size, uint8_t** dataPointer) = 0; - virtual ReturnValue_t handleMemoryDump(uint32_t address, uint32_t size, uint8_t** dataPointer, uint8_t* dumpTarget ) = 0; - /** - * Sets the address of the memory, if possible. - * startAddress is a proposal for an address, or the base address if multiple addresses are set. - */ - virtual ReturnValue_t setAddress( uint32_t* startAddress ) { return HasReturnvaluesIF::RETURN_FAILED; } - static bool memAccessWasSuccessful(ReturnValue_t result) { - switch (result) { - case DO_IT_MYSELF: - case POINTS_TO_MEMORY: - case POINTS_TO_VARIABLE: - case HasReturnvaluesIF::RETURN_OK: - case ACTIVITY_COMPLETED: - return true; - default: - return false; - } - } -}; - - -#endif /* HASMEMORYIF_H_ */ +#ifndef HASMEMORYIF_H_ +#define HASMEMORYIF_H_ + +#include "../returnvalues/HasReturnvaluesIF.h" + +class HasMemoryIF { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::HAS_MEMORY_IF; + static const ReturnValue_t DO_IT_MYSELF = MAKE_RETURN_CODE(1); + static const ReturnValue_t POINTS_TO_VARIABLE = MAKE_RETURN_CODE(2); + static const ReturnValue_t POINTS_TO_MEMORY = MAKE_RETURN_CODE(3); + static const ReturnValue_t ACTIVITY_COMPLETED = MAKE_RETURN_CODE(4); + static const ReturnValue_t POINTS_TO_VECTOR_UINT8 = MAKE_RETURN_CODE(5); + static const ReturnValue_t POINTS_TO_VECTOR_UINT16 = MAKE_RETURN_CODE(6); + static const ReturnValue_t POINTS_TO_VECTOR_UINT32 = MAKE_RETURN_CODE(7); + static const ReturnValue_t POINTS_TO_VECTOR_FLOAT = MAKE_RETURN_CODE(8); + static const ReturnValue_t DUMP_NOT_SUPPORTED = MAKE_RETURN_CODE(0xA0); + static const ReturnValue_t INVALID_SIZE = MAKE_RETURN_CODE(0xE0); + static const ReturnValue_t INVALID_ADDRESS = MAKE_RETURN_CODE(0xE1); + static const ReturnValue_t INVALID_CONTENT = MAKE_RETURN_CODE(0xE2); + static const ReturnValue_t UNALIGNED_ACCESS = MAKE_RETURN_CODE(0xE3); + static const ReturnValue_t WRITE_PROTECTED = MAKE_RETURN_CODE(0xE4); +// static const ReturnValue_t TARGET_BUSY = MAKE_RETURN_CODE(0xE5); + virtual ~HasMemoryIF() {} + virtual ReturnValue_t handleMemoryLoad(uint32_t address, const uint8_t* data, uint32_t size, uint8_t** dataPointer) = 0; + virtual ReturnValue_t handleMemoryDump(uint32_t address, uint32_t size, uint8_t** dataPointer, uint8_t* dumpTarget ) = 0; + /** + * Sets the address of the memory, if possible. + * startAddress is a proposal for an address, or the base address if multiple addresses are set. + */ + virtual ReturnValue_t setAddress( uint32_t* startAddress ) { return HasReturnvaluesIF::RETURN_FAILED; } + static bool memAccessWasSuccessful(ReturnValue_t result) { + switch (result) { + case DO_IT_MYSELF: + case POINTS_TO_MEMORY: + case POINTS_TO_VARIABLE: + case HasReturnvaluesIF::RETURN_OK: + case ACTIVITY_COMPLETED: + return true; + default: + return false; + } + } +}; + + +#endif /* HASMEMORYIF_H_ */ diff --git a/memory/MemoryHelper.cpp b/memory/MemoryHelper.cpp index b07f450c..c74b7d9f 100644 --- a/memory/MemoryHelper.cpp +++ b/memory/MemoryHelper.cpp @@ -1,193 +1,193 @@ -#include -#include -#include -#include -#include -#include - -MemoryHelper::MemoryHelper(HasMemoryIF* workOnThis, - MessageQueueIF* useThisQueue): - workOnThis(workOnThis), queueToUse(useThisQueue), ipcStore(nullptr), - ipcAddress(), lastCommand(CommandMessage::CMD_NONE), busy(false) { -} - -ReturnValue_t MemoryHelper::handleMemoryCommand(CommandMessage* message) { - lastSender = message->getSender(); - lastCommand = message->getCommand(); - if (busy) { - sif::debug << "MemHelper: Busy!" << std::endl; - } - switch (lastCommand) { - case MemoryMessage::CMD_MEMORY_DUMP: - handleMemoryCheckOrDump(message); - return RETURN_OK; - case MemoryMessage::CMD_MEMORY_LOAD: - handleMemoryLoad(message); - return RETURN_OK; - case MemoryMessage::CMD_MEMORY_CHECK: - handleMemoryCheckOrDump(message); - return RETURN_OK; - default: - lastCommand = CommandMessage::CMD_NONE; - return UNKNOWN_CMD; - } -} - -void MemoryHelper::completeLoad(ReturnValue_t errorCode, - const uint8_t* dataToCopy, const uint32_t size, uint8_t* copyHere) { - busy = false; - switch (errorCode) { - case HasMemoryIF::DO_IT_MYSELF: - busy = true; - return; - case HasMemoryIF::POINTS_TO_MEMORY: - memcpy(copyHere, dataToCopy, size); - break; - case HasMemoryIF::POINTS_TO_VARIABLE: - EndianConverter::convertBigEndian(copyHere, dataToCopy, size); - break; - case HasMemoryIF::ACTIVITY_COMPLETED: - case RETURN_OK: - break; - default: - ipcStore->deleteData(ipcAddress); - CommandMessage reply; - MemoryMessage::setMemoryReplyFailed(&reply, errorCode, - MemoryMessage::CMD_MEMORY_LOAD); - queueToUse->sendMessage(lastSender, &reply); - return; - } - //Only reached on success - CommandMessage reply( CommandMessage::REPLY_COMMAND_OK, 0, 0); - queueToUse->sendMessage(lastSender, &reply); - ipcStore->deleteData(ipcAddress); -} - -void MemoryHelper::completeDump(ReturnValue_t errorCode, - const uint8_t* dataToCopy, const uint32_t size) { - busy = false; - CommandMessage reply; - MemoryMessage::setMemoryReplyFailed(&reply, errorCode, lastCommand); - switch (errorCode) { - case HasMemoryIF::DO_IT_MYSELF: - busy = true; - return; - case HasReturnvaluesIF::RETURN_OK: - case HasMemoryIF::POINTS_TO_MEMORY: - case HasMemoryIF::POINTS_TO_VARIABLE: - //"data" must be valid pointer! - if (errorCode == HasMemoryIF::POINTS_TO_VARIABLE) { - EndianConverter::convertBigEndian(reservedSpaceInIPC, dataToCopy, size); - } else { - memcpy(reservedSpaceInIPC, dataToCopy, size); - } - /* NO BREAK falls through*/ - case HasMemoryIF::ACTIVITY_COMPLETED: - switch (lastCommand) { - case MemoryMessage::CMD_MEMORY_DUMP: { - MemoryMessage::setMemoryDumpReply(&reply, ipcAddress); - break; - } - case MemoryMessage::CMD_MEMORY_CHECK: { - uint16_t crc = CRC::crc16ccitt(reservedSpaceInIPC, size); - //Delete data immediately, was temporary. - ipcStore->deleteData(ipcAddress); - MemoryMessage::setMemoryCheckReply(&reply, crc); - break; - } - default: - //This should never happen! - //Is it ok to send message? Otherwise: return; - ipcStore->deleteData(ipcAddress); - reply.setParameter(STATE_MISMATCH); - break; - } - break; - case HasMemoryIF::DUMP_NOT_SUPPORTED: - if (lastCommand == MemoryMessage::CMD_MEMORY_CHECK){ - MemoryMessage::setMemoryCheckReply(&reply, 0); - MemoryMessage::setCrcReturnValue(&reply,HasMemoryIF::DUMP_NOT_SUPPORTED); - } - ipcStore->deleteData(ipcAddress); - break; - default: - //Reply is already set to REJECTED. - ipcStore->deleteData(ipcAddress); - break; - } - if (queueToUse->sendMessage(lastSender, &reply) != RETURN_OK) { - reply.clear(); - } -} - -void MemoryHelper::swapMatrixCopy(uint8_t* out, const uint8_t *in, - uint32_t totalSize, uint8_t datatypeSize) { - if (totalSize % datatypeSize != 0){ - return; - } - - while (totalSize > 0){ - EndianConverter::convertBigEndian(out,in,datatypeSize); - out += datatypeSize; - in += datatypeSize; - totalSize -= datatypeSize; - } -} - -MemoryHelper::~MemoryHelper() { - //Nothing to destroy -} - -void MemoryHelper::handleMemoryLoad(CommandMessage* message) { - uint32_t address = MemoryMessage::getAddress(message); - ipcAddress = MemoryMessage::getStoreID(message); - const uint8_t* p_data = NULL; - uint8_t* dataPointer = NULL; - size_t size = 0; - ReturnValue_t returnCode = ipcStore->getData(ipcAddress, &p_data, &size); - if (returnCode == RETURN_OK) { - returnCode = workOnThis->handleMemoryLoad(address, p_data, size, - &dataPointer); - completeLoad(returnCode, p_data, size, dataPointer); - } else { - //At least inform sender. - CommandMessage reply; - MemoryMessage::setMemoryReplyFailed(&reply, returnCode, - MemoryMessage::CMD_MEMORY_LOAD); - queueToUse->sendMessage(lastSender, &reply); - } -} - -void MemoryHelper::handleMemoryCheckOrDump(CommandMessage* message) { - uint32_t address = MemoryMessage::getAddress(message); - uint32_t size = MemoryMessage::getLength(message); - uint8_t* dataPointer = NULL; - ReturnValue_t returnCode = ipcStore->getFreeElement(&ipcAddress, size, - &reservedSpaceInIPC); - if (returnCode == RETURN_OK) { - returnCode = workOnThis->handleMemoryDump(address, size, &dataPointer, - reservedSpaceInIPC); - completeDump(returnCode, dataPointer, size); - } else { - CommandMessage reply; - MemoryMessage::setMemoryReplyFailed(&reply, returnCode, lastCommand); - queueToUse->sendMessage(lastSender, &reply); - } -} - -ReturnValue_t MemoryHelper::initialize(MessageQueueIF* queueToUse_) { - if(queueToUse_ == nullptr) { - return HasReturnvaluesIF::RETURN_FAILED; - } - this->queueToUse = queueToUse_; - return initialize(); -} - -ReturnValue_t MemoryHelper::initialize() { - ipcStore = objectManager->get(objects::IPC_STORE); - if (ipcStore != nullptr) { - return RETURN_OK; - } else { - return RETURN_FAILED; - } -} +#include "../globalfunctions/CRC.h" +#include "../memory/MemoryHelper.h" +#include "../memory/MemoryMessage.h" +#include "../objectmanager/ObjectManagerIF.h" +#include "../serialize/EndianConverter.h" +#include "../serviceinterface/ServiceInterfaceStream.h" + +MemoryHelper::MemoryHelper(HasMemoryIF* workOnThis, + MessageQueueIF* useThisQueue): + workOnThis(workOnThis), queueToUse(useThisQueue), ipcStore(nullptr), + ipcAddress(), lastCommand(CommandMessage::CMD_NONE), busy(false) { +} + +ReturnValue_t MemoryHelper::handleMemoryCommand(CommandMessage* message) { + lastSender = message->getSender(); + lastCommand = message->getCommand(); + if (busy) { + sif::debug << "MemHelper: Busy!" << std::endl; + } + switch (lastCommand) { + case MemoryMessage::CMD_MEMORY_DUMP: + handleMemoryCheckOrDump(message); + return RETURN_OK; + case MemoryMessage::CMD_MEMORY_LOAD: + handleMemoryLoad(message); + return RETURN_OK; + case MemoryMessage::CMD_MEMORY_CHECK: + handleMemoryCheckOrDump(message); + return RETURN_OK; + default: + lastCommand = CommandMessage::CMD_NONE; + return UNKNOWN_CMD; + } +} + +void MemoryHelper::completeLoad(ReturnValue_t errorCode, + const uint8_t* dataToCopy, const uint32_t size, uint8_t* copyHere) { + busy = false; + switch (errorCode) { + case HasMemoryIF::DO_IT_MYSELF: + busy = true; + return; + case HasMemoryIF::POINTS_TO_MEMORY: + memcpy(copyHere, dataToCopy, size); + break; + case HasMemoryIF::POINTS_TO_VARIABLE: + EndianConverter::convertBigEndian(copyHere, dataToCopy, size); + break; + case HasMemoryIF::ACTIVITY_COMPLETED: + case RETURN_OK: + break; + default: + ipcStore->deleteData(ipcAddress); + CommandMessage reply; + MemoryMessage::setMemoryReplyFailed(&reply, errorCode, + MemoryMessage::CMD_MEMORY_LOAD); + queueToUse->sendMessage(lastSender, &reply); + return; + } + //Only reached on success + CommandMessage reply( CommandMessage::REPLY_COMMAND_OK, 0, 0); + queueToUse->sendMessage(lastSender, &reply); + ipcStore->deleteData(ipcAddress); +} + +void MemoryHelper::completeDump(ReturnValue_t errorCode, + const uint8_t* dataToCopy, const uint32_t size) { + busy = false; + CommandMessage reply; + MemoryMessage::setMemoryReplyFailed(&reply, errorCode, lastCommand); + switch (errorCode) { + case HasMemoryIF::DO_IT_MYSELF: + busy = true; + return; + case HasReturnvaluesIF::RETURN_OK: + case HasMemoryIF::POINTS_TO_MEMORY: + case HasMemoryIF::POINTS_TO_VARIABLE: + //"data" must be valid pointer! + if (errorCode == HasMemoryIF::POINTS_TO_VARIABLE) { + EndianConverter::convertBigEndian(reservedSpaceInIPC, dataToCopy, size); + } else { + memcpy(reservedSpaceInIPC, dataToCopy, size); + } + /* NO BREAK falls through*/ + case HasMemoryIF::ACTIVITY_COMPLETED: + switch (lastCommand) { + case MemoryMessage::CMD_MEMORY_DUMP: { + MemoryMessage::setMemoryDumpReply(&reply, ipcAddress); + break; + } + case MemoryMessage::CMD_MEMORY_CHECK: { + uint16_t crc = CRC::crc16ccitt(reservedSpaceInIPC, size); + //Delete data immediately, was temporary. + ipcStore->deleteData(ipcAddress); + MemoryMessage::setMemoryCheckReply(&reply, crc); + break; + } + default: + //This should never happen! + //Is it ok to send message? Otherwise: return; + ipcStore->deleteData(ipcAddress); + reply.setParameter(STATE_MISMATCH); + break; + } + break; + case HasMemoryIF::DUMP_NOT_SUPPORTED: + if (lastCommand == MemoryMessage::CMD_MEMORY_CHECK){ + MemoryMessage::setMemoryCheckReply(&reply, 0); + MemoryMessage::setCrcReturnValue(&reply,HasMemoryIF::DUMP_NOT_SUPPORTED); + } + ipcStore->deleteData(ipcAddress); + break; + default: + //Reply is already set to REJECTED. + ipcStore->deleteData(ipcAddress); + break; + } + if (queueToUse->sendMessage(lastSender, &reply) != RETURN_OK) { + reply.clear(); + } +} + +void MemoryHelper::swapMatrixCopy(uint8_t* out, const uint8_t *in, + uint32_t totalSize, uint8_t datatypeSize) { + if (totalSize % datatypeSize != 0){ + return; + } + + while (totalSize > 0){ + EndianConverter::convertBigEndian(out,in,datatypeSize); + out += datatypeSize; + in += datatypeSize; + totalSize -= datatypeSize; + } +} + +MemoryHelper::~MemoryHelper() { + //Nothing to destroy +} + +void MemoryHelper::handleMemoryLoad(CommandMessage* message) { + uint32_t address = MemoryMessage::getAddress(message); + ipcAddress = MemoryMessage::getStoreID(message); + const uint8_t* p_data = NULL; + uint8_t* dataPointer = NULL; + size_t size = 0; + ReturnValue_t returnCode = ipcStore->getData(ipcAddress, &p_data, &size); + if (returnCode == RETURN_OK) { + returnCode = workOnThis->handleMemoryLoad(address, p_data, size, + &dataPointer); + completeLoad(returnCode, p_data, size, dataPointer); + } else { + //At least inform sender. + CommandMessage reply; + MemoryMessage::setMemoryReplyFailed(&reply, returnCode, + MemoryMessage::CMD_MEMORY_LOAD); + queueToUse->sendMessage(lastSender, &reply); + } +} + +void MemoryHelper::handleMemoryCheckOrDump(CommandMessage* message) { + uint32_t address = MemoryMessage::getAddress(message); + uint32_t size = MemoryMessage::getLength(message); + uint8_t* dataPointer = NULL; + ReturnValue_t returnCode = ipcStore->getFreeElement(&ipcAddress, size, + &reservedSpaceInIPC); + if (returnCode == RETURN_OK) { + returnCode = workOnThis->handleMemoryDump(address, size, &dataPointer, + reservedSpaceInIPC); + completeDump(returnCode, dataPointer, size); + } else { + CommandMessage reply; + MemoryMessage::setMemoryReplyFailed(&reply, returnCode, lastCommand); + queueToUse->sendMessage(lastSender, &reply); + } +} + +ReturnValue_t MemoryHelper::initialize(MessageQueueIF* queueToUse_) { + if(queueToUse_ == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + this->queueToUse = queueToUse_; + return initialize(); +} + +ReturnValue_t MemoryHelper::initialize() { + ipcStore = objectManager->get(objects::IPC_STORE); + if (ipcStore != nullptr) { + return RETURN_OK; + } else { + return RETURN_FAILED; + } +} diff --git a/memory/MemoryHelper.h b/memory/MemoryHelper.h index da6b9bdb..90dbafb4 100644 --- a/memory/MemoryHelper.h +++ b/memory/MemoryHelper.h @@ -1,37 +1,37 @@ -#ifndef FRAMEWORK_MEMORY_MEMORYHELPER_H_ -#define FRAMEWORK_MEMORY_MEMORYHELPER_H_ -#include -#include -#include -#include -#include - -class MemoryHelper : public HasReturnvaluesIF { -public: - static const uint8_t INTERFACE_ID = CLASS_ID::MEMORY_HELPER; - static const ReturnValue_t UNKNOWN_CMD = MAKE_RETURN_CODE(0xE0); - static const ReturnValue_t INVALID_ADDRESS = MAKE_RETURN_CODE(0xE1); - static const ReturnValue_t INVALID_SIZE = MAKE_RETURN_CODE(0xE2); - static const ReturnValue_t STATE_MISMATCH = MAKE_RETURN_CODE(0xE3); -private: - HasMemoryIF* workOnThis; - MessageQueueIF* queueToUse; - StorageManagerIF* ipcStore = nullptr; - store_address_t ipcAddress; - Command_t lastCommand; - MessageQueueId_t lastSender = MessageQueueIF::NO_QUEUE; - uint8_t* reservedSpaceInIPC = nullptr; - bool busy; - void handleMemoryLoad(CommandMessage* message); - void handleMemoryCheckOrDump(CommandMessage* message); - ReturnValue_t initialize(); -public: - ReturnValue_t handleMemoryCommand(CommandMessage* message); - void completeLoad( ReturnValue_t errorCode, const uint8_t* dataToCopy = NULL, const uint32_t size = 0, uint8_t* copyHere = NULL ); - void completeDump( ReturnValue_t errorCode, const uint8_t* dataToCopy = NULL, const uint32_t size = 0); - void swapMatrixCopy( uint8_t *out, const uint8_t *in, uint32_t totalSize, uint8_t datatypeSize); - ReturnValue_t initialize(MessageQueueIF* queueToUse_); - MemoryHelper( HasMemoryIF* workOnThis, MessageQueueIF* useThisQueue ); - ~MemoryHelper(); -}; -#endif /* MEMORYHELPER_H_ */ +#ifndef FRAMEWORK_MEMORY_MEMORYHELPER_H_ +#define FRAMEWORK_MEMORY_MEMORYHELPER_H_ +#include "../ipc/CommandMessage.h" +#include "../memory/AcceptsMemoryMessagesIF.h" +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../storagemanager/StorageManagerIF.h" +#include "../ipc/MessageQueueIF.h" + +class MemoryHelper : public HasReturnvaluesIF { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::MEMORY_HELPER; + static const ReturnValue_t UNKNOWN_CMD = MAKE_RETURN_CODE(0xE0); + static const ReturnValue_t INVALID_ADDRESS = MAKE_RETURN_CODE(0xE1); + static const ReturnValue_t INVALID_SIZE = MAKE_RETURN_CODE(0xE2); + static const ReturnValue_t STATE_MISMATCH = MAKE_RETURN_CODE(0xE3); +private: + HasMemoryIF* workOnThis; + MessageQueueIF* queueToUse; + StorageManagerIF* ipcStore = nullptr; + store_address_t ipcAddress; + Command_t lastCommand; + MessageQueueId_t lastSender = MessageQueueIF::NO_QUEUE; + uint8_t* reservedSpaceInIPC = nullptr; + bool busy; + void handleMemoryLoad(CommandMessage* message); + void handleMemoryCheckOrDump(CommandMessage* message); + ReturnValue_t initialize(); +public: + ReturnValue_t handleMemoryCommand(CommandMessage* message); + void completeLoad( ReturnValue_t errorCode, const uint8_t* dataToCopy = NULL, const uint32_t size = 0, uint8_t* copyHere = NULL ); + void completeDump( ReturnValue_t errorCode, const uint8_t* dataToCopy = NULL, const uint32_t size = 0); + void swapMatrixCopy( uint8_t *out, const uint8_t *in, uint32_t totalSize, uint8_t datatypeSize); + ReturnValue_t initialize(MessageQueueIF* queueToUse_); + MemoryHelper( HasMemoryIF* workOnThis, MessageQueueIF* useThisQueue ); + ~MemoryHelper(); +}; +#endif /* MEMORYHELPER_H_ */ diff --git a/memory/MemoryMessage.cpp b/memory/MemoryMessage.cpp index f978ed4e..16a60502 100644 --- a/memory/MemoryMessage.cpp +++ b/memory/MemoryMessage.cpp @@ -1,112 +1,112 @@ -#include -#include -MemoryMessage::MemoryMessage() { -} - -uint32_t MemoryMessage::getAddress(const CommandMessage* message) { - return message->getParameter(); -} - -store_address_t MemoryMessage::getStoreID(const CommandMessage* message) { - store_address_t temp; - temp.raw = message->getParameter2(); - return temp; -} - -uint32_t MemoryMessage::getLength(const CommandMessage* message) { - return message->getParameter2(); -} - -ReturnValue_t MemoryMessage::setMemoryDumpCommand(CommandMessage* message, - uint32_t address, uint32_t length) { - message->setCommand(CMD_MEMORY_DUMP); - message->setParameter( address ); - message->setParameter2( length ); - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t MemoryMessage::setMemoryDumpReply(CommandMessage* message, store_address_t storageID) { - message->setCommand(REPLY_MEMORY_DUMP); - message->setParameter2( storageID.raw ); - return HasReturnvaluesIF::RETURN_OK; -} - -void MemoryMessage::setMemoryLoadCommand(CommandMessage* message, - uint32_t address, store_address_t storageID) { - message->setCommand(CMD_MEMORY_LOAD); - message->setParameter( address ); - message->setParameter2( storageID.raw ); -} - -ReturnValue_t MemoryMessage::getErrorCode(const CommandMessage* message) { - return message->getParameter(); -} - -void MemoryMessage::clear(CommandMessage* message) { - switch (message->getCommand()) { - case CMD_MEMORY_LOAD: - case REPLY_MEMORY_DUMP: { - StorageManagerIF *ipcStore = objectManager->get( - objects::IPC_STORE); - if (ipcStore != NULL) { - ipcStore->deleteData(getStoreID(message)); - } - } - /* NO BREAK falls through*/ - case CMD_MEMORY_DUMP: - case CMD_MEMORY_CHECK: - case REPLY_MEMORY_CHECK: - case END_OF_MEMORY_COPY: - message->setCommand(CommandMessage::CMD_NONE); - message->setParameter(0); - message->setParameter2(0); - break; - } -} - -ReturnValue_t MemoryMessage::setMemoryCheckCommand(CommandMessage* message, - uint32_t address, uint32_t length) { - message->setCommand(CMD_MEMORY_CHECK); - message->setParameter( address ); - message->setParameter2( length ); - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t MemoryMessage::setMemoryCheckReply(CommandMessage* message, - uint16_t crc) { - message->setCommand(REPLY_MEMORY_CHECK); - message->setParameter( crc ); - return HasReturnvaluesIF::RETURN_OK; -} - -void MemoryMessage::setCrcReturnValue(CommandMessage* message, ReturnValue_t returnValue){ - message->setParameter(returnValue<<16); -}; - -uint16_t MemoryMessage::getCrc(const CommandMessage* message) { - return (uint16_t)(message->getParameter()); -} - -ReturnValue_t MemoryMessage::getCrcReturnValue(const CommandMessage* message){ - return (message->getParameter()>>16); -} - -Command_t MemoryMessage::getInitialCommand(const CommandMessage* message) { - return message->getParameter2(); -} - -ReturnValue_t MemoryMessage::setMemoryReplyFailed(CommandMessage* message, - ReturnValue_t errorCode, Command_t initialCommand) { - message->setCommand(REPLY_MEMORY_FAILED); - message->setParameter(errorCode); - message->setParameter2(initialCommand); - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t MemoryMessage::setMemoryCopyEnd(CommandMessage* message) { - message->setCommand(END_OF_MEMORY_COPY); - message->setParameter(0); - message->setParameter2(0); - return HasReturnvaluesIF::RETURN_OK; -} - +#include "../memory/MemoryMessage.h" +#include "../objectmanager/ObjectManagerIF.h" +MemoryMessage::MemoryMessage() { +} + +uint32_t MemoryMessage::getAddress(const CommandMessage* message) { + return message->getParameter(); +} + +store_address_t MemoryMessage::getStoreID(const CommandMessage* message) { + store_address_t temp; + temp.raw = message->getParameter2(); + return temp; +} + +uint32_t MemoryMessage::getLength(const CommandMessage* message) { + return message->getParameter2(); +} + +ReturnValue_t MemoryMessage::setMemoryDumpCommand(CommandMessage* message, + uint32_t address, uint32_t length) { + message->setCommand(CMD_MEMORY_DUMP); + message->setParameter( address ); + message->setParameter2( length ); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t MemoryMessage::setMemoryDumpReply(CommandMessage* message, store_address_t storageID) { + message->setCommand(REPLY_MEMORY_DUMP); + message->setParameter2( storageID.raw ); + return HasReturnvaluesIF::RETURN_OK; +} + +void MemoryMessage::setMemoryLoadCommand(CommandMessage* message, + uint32_t address, store_address_t storageID) { + message->setCommand(CMD_MEMORY_LOAD); + message->setParameter( address ); + message->setParameter2( storageID.raw ); +} + +ReturnValue_t MemoryMessage::getErrorCode(const CommandMessage* message) { + return message->getParameter(); +} + +void MemoryMessage::clear(CommandMessage* message) { + switch (message->getCommand()) { + case CMD_MEMORY_LOAD: + case REPLY_MEMORY_DUMP: { + StorageManagerIF *ipcStore = objectManager->get( + objects::IPC_STORE); + if (ipcStore != NULL) { + ipcStore->deleteData(getStoreID(message)); + } + } + /* NO BREAK falls through*/ + case CMD_MEMORY_DUMP: + case CMD_MEMORY_CHECK: + case REPLY_MEMORY_CHECK: + case END_OF_MEMORY_COPY: + message->setCommand(CommandMessage::CMD_NONE); + message->setParameter(0); + message->setParameter2(0); + break; + } +} + +ReturnValue_t MemoryMessage::setMemoryCheckCommand(CommandMessage* message, + uint32_t address, uint32_t length) { + message->setCommand(CMD_MEMORY_CHECK); + message->setParameter( address ); + message->setParameter2( length ); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t MemoryMessage::setMemoryCheckReply(CommandMessage* message, + uint16_t crc) { + message->setCommand(REPLY_MEMORY_CHECK); + message->setParameter( crc ); + return HasReturnvaluesIF::RETURN_OK; +} + +void MemoryMessage::setCrcReturnValue(CommandMessage* message, ReturnValue_t returnValue){ + message->setParameter(returnValue<<16); +}; + +uint16_t MemoryMessage::getCrc(const CommandMessage* message) { + return (uint16_t)(message->getParameter()); +} + +ReturnValue_t MemoryMessage::getCrcReturnValue(const CommandMessage* message){ + return (message->getParameter()>>16); +} + +Command_t MemoryMessage::getInitialCommand(const CommandMessage* message) { + return message->getParameter2(); +} + +ReturnValue_t MemoryMessage::setMemoryReplyFailed(CommandMessage* message, + ReturnValue_t errorCode, Command_t initialCommand) { + message->setCommand(REPLY_MEMORY_FAILED); + message->setParameter(errorCode); + message->setParameter2(initialCommand); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t MemoryMessage::setMemoryCopyEnd(CommandMessage* message) { + message->setCommand(END_OF_MEMORY_COPY); + message->setParameter(0); + message->setParameter2(0); + return HasReturnvaluesIF::RETURN_OK; +} + diff --git a/memory/MemoryMessage.h b/memory/MemoryMessage.h index e2c87ca3..af936c1f 100644 --- a/memory/MemoryMessage.h +++ b/memory/MemoryMessage.h @@ -1,39 +1,39 @@ -#ifndef MEMORYMESSAGE_H_ -#define MEMORYMESSAGE_H_ - -#include -#include - - -class MemoryMessage { -private: - MemoryMessage(); //A private ctor inhibits instantiation -public: - static const uint8_t MESSAGE_ID = messagetypes::MEMORY; - static const Command_t CMD_MEMORY_LOAD = MAKE_COMMAND_ID( 0x01 ); - static const Command_t CMD_MEMORY_DUMP = MAKE_COMMAND_ID( 0x02 ); - static const Command_t CMD_MEMORY_CHECK = MAKE_COMMAND_ID( 0x03 ); - static const Command_t REPLY_MEMORY_DUMP = MAKE_COMMAND_ID( 0x10 ); - static const Command_t REPLY_MEMORY_CHECK = MAKE_COMMAND_ID( 0x30 ); - static const Command_t REPLY_MEMORY_FAILED = MAKE_COMMAND_ID( 0xE0 ); - static const Command_t END_OF_MEMORY_COPY = MAKE_COMMAND_ID(0xF0); - - static uint32_t getAddress( const CommandMessage* message ); - static store_address_t getStoreID( const CommandMessage* message ); - static uint32_t getLength( const CommandMessage* message ); - static ReturnValue_t getErrorCode( const CommandMessage* message ); - static ReturnValue_t setMemoryDumpCommand( CommandMessage* message, uint32_t address, uint32_t length ); - static ReturnValue_t setMemoryDumpReply( CommandMessage* message, store_address_t storageID ); - static void setMemoryLoadCommand( CommandMessage* message, uint32_t address, store_address_t storageID ); - static ReturnValue_t setMemoryCheckCommand( CommandMessage* message, uint32_t address, uint32_t length ); - static ReturnValue_t setMemoryCheckReply( CommandMessage* message, uint16_t crc ); - static ReturnValue_t setMemoryReplyFailed( CommandMessage* message, ReturnValue_t errorCode, Command_t initialCommand ); - static ReturnValue_t setMemoryCopyEnd( CommandMessage* message); - static void setCrcReturnValue(CommandMessage*, ReturnValue_t returnValue); - static uint16_t getCrc( const CommandMessage* message ); - static ReturnValue_t getCrcReturnValue(const CommandMessage* message); - static Command_t getInitialCommand( const CommandMessage* message ); - static void clear(CommandMessage* message); -}; - -#endif /* MEMORYMESSAGE_H_ */ +#ifndef MEMORYMESSAGE_H_ +#define MEMORYMESSAGE_H_ + +#include "../ipc/CommandMessage.h" +#include "../storagemanager/StorageManagerIF.h" + + +class MemoryMessage { +private: + MemoryMessage(); //A private ctor inhibits instantiation +public: + static const uint8_t MESSAGE_ID = messagetypes::MEMORY; + static const Command_t CMD_MEMORY_LOAD = MAKE_COMMAND_ID( 0x01 ); + static const Command_t CMD_MEMORY_DUMP = MAKE_COMMAND_ID( 0x02 ); + static const Command_t CMD_MEMORY_CHECK = MAKE_COMMAND_ID( 0x03 ); + static const Command_t REPLY_MEMORY_DUMP = MAKE_COMMAND_ID( 0x10 ); + static const Command_t REPLY_MEMORY_CHECK = MAKE_COMMAND_ID( 0x30 ); + static const Command_t REPLY_MEMORY_FAILED = MAKE_COMMAND_ID( 0xE0 ); + static const Command_t END_OF_MEMORY_COPY = MAKE_COMMAND_ID(0xF0); + + static uint32_t getAddress( const CommandMessage* message ); + static store_address_t getStoreID( const CommandMessage* message ); + static uint32_t getLength( const CommandMessage* message ); + static ReturnValue_t getErrorCode( const CommandMessage* message ); + static ReturnValue_t setMemoryDumpCommand( CommandMessage* message, uint32_t address, uint32_t length ); + static ReturnValue_t setMemoryDumpReply( CommandMessage* message, store_address_t storageID ); + static void setMemoryLoadCommand( CommandMessage* message, uint32_t address, store_address_t storageID ); + static ReturnValue_t setMemoryCheckCommand( CommandMessage* message, uint32_t address, uint32_t length ); + static ReturnValue_t setMemoryCheckReply( CommandMessage* message, uint16_t crc ); + static ReturnValue_t setMemoryReplyFailed( CommandMessage* message, ReturnValue_t errorCode, Command_t initialCommand ); + static ReturnValue_t setMemoryCopyEnd( CommandMessage* message); + static void setCrcReturnValue(CommandMessage*, ReturnValue_t returnValue); + static uint16_t getCrc( const CommandMessage* message ); + static ReturnValue_t getCrcReturnValue(const CommandMessage* message); + static Command_t getInitialCommand( const CommandMessage* message ); + static void clear(CommandMessage* message); +}; + +#endif /* MEMORYMESSAGE_H_ */ diff --git a/memory/MemoryProxyIF.h b/memory/MemoryProxyIF.h index d325ba4e..a30165c3 100644 --- a/memory/MemoryProxyIF.h +++ b/memory/MemoryProxyIF.h @@ -1,22 +1,22 @@ -#ifndef FRAMEWORK_MEMORY_MEMORYPROXYIF_H_ -#define FRAMEWORK_MEMORY_MEMORYPROXYIF_H_ - -#include - -/** - * This was a nice idea to transparently forward incoming messages to another object. - * But it doesn't work like that. - */ -class MemoryProxyIF : public AcceptsMemoryMessagesIF { -public: - virtual MessageQueueId_t getProxyQueue() const = 0; - MessageQueueId_t getCommandQueue() const { - return getProxyQueue(); - } - virtual ~MemoryProxyIF() {} - -}; - - - -#endif /* FRAMEWORK_MEMORY_MEMORYPROXYIF_H_ */ +#ifndef FRAMEWORK_MEMORY_MEMORYPROXYIF_H_ +#define FRAMEWORK_MEMORY_MEMORYPROXYIF_H_ + +#include "../memory/AcceptsMemoryMessagesIF.h" + +/** + * This was a nice idea to transparently forward incoming messages to another object. + * But it doesn't work like that. + */ +class MemoryProxyIF : public AcceptsMemoryMessagesIF { +public: + virtual MessageQueueId_t getProxyQueue() const = 0; + MessageQueueId_t getCommandQueue() const { + return getProxyQueue(); + } + virtual ~MemoryProxyIF() {} + +}; + + + +#endif /* FRAMEWORK_MEMORY_MEMORYPROXYIF_H_ */ diff --git a/modes/HasModesIF.h b/modes/HasModesIF.h index 263b0a87..eade3613 100644 --- a/modes/HasModesIF.h +++ b/modes/HasModesIF.h @@ -1,57 +1,57 @@ -/** - * @file HasModesIF.h - * @brief This file defines the HasModesIF class. - * @date 20.06.2013 - * @author baetz - */ - -#ifndef HASMODESIF_H_ -#define HASMODESIF_H_ - -#include -#include -#include -#include -#include - - -class HasModesIF { - friend class ModeHelper; -public: - static const uint8_t INTERFACE_ID = CLASS_ID::HAS_MODES_IF; - static const ReturnValue_t INVALID_MODE = MAKE_RETURN_CODE(0x01); - static const ReturnValue_t TRANS_NOT_ALLOWED = MAKE_RETURN_CODE(0x02); - static const ReturnValue_t IN_TRANSITION = MAKE_RETURN_CODE(0x03); - static const ReturnValue_t INVALID_SUBMODE = MAKE_RETURN_CODE(0x04); - - static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SYSTEM_MANAGER; - static const Event CHANGING_MODE = MAKE_EVENT(0, SEVERITY::INFO); //!< An object announces changing the mode. p1: target mode. p2: target submode - static const Event MODE_INFO = MAKE_EVENT(1, SEVERITY::INFO); //!< An Object announces its mode; parameter1 is mode, parameter2 is submode - static const Event FALLBACK_FAILED = MAKE_EVENT(2, SEVERITY::HIGH); - static const Event MODE_TRANSITION_FAILED = MAKE_EVENT(3, SEVERITY::LOW); - static const Event CANT_KEEP_MODE = MAKE_EVENT(4, SEVERITY::HIGH); - static const Event OBJECT_IN_INVALID_MODE = MAKE_EVENT(5, SEVERITY::LOW); //!< Indicates a bug or configuration failure: Object is in a mode it should never be in. - static const Event FORCING_MODE = MAKE_EVENT(6, SEVERITY::MEDIUM); //!< The mode is changed, but for some reason, the change is forced, i.e. EXTERNAL_CONTROL ignored. p1: target mode. p2: target submode - static const Event MODE_CMD_REJECTED = MAKE_EVENT(7, SEVERITY::LOW); //!< A mode command was rejected by the called object. Par1: called object id, Par2: return code. - - static const Mode_t MODE_ON = 1; //!< The device is powered and ready to perform operations. In this mode, no commands are sent by the device handler itself, but direct commands van be commanded and will be interpreted - static const Mode_t MODE_OFF = 0; //!< The device is powered off. The only command accepted in this mode is a mode change to on. - static const Submode_t SUBMODE_NONE = 0; //!< To avoid checks against magic number "0". - virtual ~HasModesIF() { - } - virtual MessageQueueId_t getCommandQueue() const = 0; - virtual void getMode(Mode_t *mode, Submode_t *submode) = 0; -protected: - virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, - uint32_t *msToReachTheMode) { - return HasReturnvaluesIF::RETURN_FAILED; - } - virtual void startTransition(Mode_t mode, Submode_t submode) { - } - virtual void setToExternalControl() { - } - virtual void announceMode(bool recursive) { - } -}; - -#endif /* HASMODESIF_H_ */ +/** + * @file HasModesIF.h + * @brief This file defines the HasModesIF class. + * @date 20.06.2013 + * @author baetz + */ + +#ifndef HASMODESIF_H_ +#define HASMODESIF_H_ + +#include "../events/Event.h" +#include "../modes/ModeHelper.h" +#include "../modes/ModeMessage.h" +#include "../returnvalues/HasReturnvaluesIF.h" +#include + + +class HasModesIF { + friend class ModeHelper; +public: + static const uint8_t INTERFACE_ID = CLASS_ID::HAS_MODES_IF; + static const ReturnValue_t INVALID_MODE = MAKE_RETURN_CODE(0x01); + static const ReturnValue_t TRANS_NOT_ALLOWED = MAKE_RETURN_CODE(0x02); + static const ReturnValue_t IN_TRANSITION = MAKE_RETURN_CODE(0x03); + static const ReturnValue_t INVALID_SUBMODE = MAKE_RETURN_CODE(0x04); + + static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SYSTEM_MANAGER; + static const Event CHANGING_MODE = MAKE_EVENT(0, SEVERITY::INFO); //!< An object announces changing the mode. p1: target mode. p2: target submode + static const Event MODE_INFO = MAKE_EVENT(1, SEVERITY::INFO); //!< An Object announces its mode; parameter1 is mode, parameter2 is submode + static const Event FALLBACK_FAILED = MAKE_EVENT(2, SEVERITY::HIGH); + static const Event MODE_TRANSITION_FAILED = MAKE_EVENT(3, SEVERITY::LOW); + static const Event CANT_KEEP_MODE = MAKE_EVENT(4, SEVERITY::HIGH); + static const Event OBJECT_IN_INVALID_MODE = MAKE_EVENT(5, SEVERITY::LOW); //!< Indicates a bug or configuration failure: Object is in a mode it should never be in. + static const Event FORCING_MODE = MAKE_EVENT(6, SEVERITY::MEDIUM); //!< The mode is changed, but for some reason, the change is forced, i.e. EXTERNAL_CONTROL ignored. p1: target mode. p2: target submode + static const Event MODE_CMD_REJECTED = MAKE_EVENT(7, SEVERITY::LOW); //!< A mode command was rejected by the called object. Par1: called object id, Par2: return code. + + static const Mode_t MODE_ON = 1; //!< The device is powered and ready to perform operations. In this mode, no commands are sent by the device handler itself, but direct commands van be commanded and will be interpreted + static const Mode_t MODE_OFF = 0; //!< The device is powered off. The only command accepted in this mode is a mode change to on. + static const Submode_t SUBMODE_NONE = 0; //!< To avoid checks against magic number "0". + virtual ~HasModesIF() { + } + virtual MessageQueueId_t getCommandQueue() const = 0; + virtual void getMode(Mode_t *mode, Submode_t *submode) = 0; +protected: + virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, + uint32_t *msToReachTheMode) { + return HasReturnvaluesIF::RETURN_FAILED; + } + virtual void startTransition(Mode_t mode, Submode_t submode) { + } + virtual void setToExternalControl() { + } + virtual void announceMode(bool recursive) { + } +}; + +#endif /* HASMODESIF_H_ */ diff --git a/modes/ModeHelper.cpp b/modes/ModeHelper.cpp index 030f1db3..d6cbf2c9 100644 --- a/modes/ModeHelper.cpp +++ b/modes/ModeHelper.cpp @@ -1,135 +1,135 @@ -#include -#include -#include - -ModeHelper::ModeHelper(HasModesIF *owner) : - commandedMode(HasModesIF::MODE_OFF), - commandedSubmode(HasModesIF::SUBMODE_NONE), - owner(owner), forced(false) {} - -ModeHelper::~ModeHelper() { - -} - -ReturnValue_t ModeHelper::handleModeCommand(CommandMessage* command) { - CommandMessage reply; - Mode_t mode; - Submode_t submode; - switch (command->getCommand()) { - case ModeMessage::CMD_MODE_COMMAND_FORCED: - forced = true; - /* NO BREAK falls through*/ - case ModeMessage::CMD_MODE_COMMAND: { - mode = ModeMessage::getMode(command); - submode = ModeMessage::getSubmode(command); - uint32_t timeout; - ReturnValue_t result = owner->checkModeCommand(mode, submode, &timeout); - if (result != HasReturnvaluesIF::RETURN_OK) { - ModeMessage::cantReachMode(&reply, result); - MessageQueueSenderIF::sendMessage(command->getSender(), &reply, - owner->getCommandQueue()); - break; - } - //Free to start transition - theOneWhoCommandedAMode = command->getSender(); - commandedMode = mode; - commandedSubmode = submode; - - if ((parentQueueId != MessageQueueMessageIF::NO_QUEUE) - && (theOneWhoCommandedAMode != parentQueueId)) { - owner->setToExternalControl(); - } - - countdown.setTimeout(timeout); - owner->startTransition(mode, submode); - } - break; - case ModeMessage::CMD_MODE_READ: { - owner->getMode(&mode, &submode); - ModeMessage::setModeMessage(&reply, ModeMessage::REPLY_MODE_REPLY, mode, - submode); - MessageQueueSenderIF::sendMessage(command->getSender(), &reply, - owner->getCommandQueue()); - } - break; - case ModeMessage::CMD_MODE_ANNOUNCE: - owner->announceMode(false); - break; - case ModeMessage::CMD_MODE_ANNOUNCE_RECURSIVELY: - owner->announceMode(true); - break; - default: - return HasReturnvaluesIF::RETURN_FAILED; - } - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t ModeHelper::initialize(MessageQueueId_t parentQueueId) { - setParentQueue(parentQueueId); - return initialize(); -} - -void ModeHelper::modeChanged(Mode_t ownerMode, Submode_t ownerSubmode) { - forced = false; - sendModeReplyMessage(ownerMode, ownerSubmode); - sendModeInfoMessage(ownerMode, ownerSubmode); - theOneWhoCommandedAMode = MessageQueueMessageIF::NO_QUEUE; -} - -void ModeHelper::sendModeReplyMessage(Mode_t ownerMode, - Submode_t ownerSubmode) { - CommandMessage reply; - if (theOneWhoCommandedAMode != MessageQueueMessageIF::NO_QUEUE) - { - if (ownerMode != commandedMode or ownerSubmode != commandedSubmode) - { - ModeMessage::setModeMessage(&reply, - ModeMessage::REPLY_WRONG_MODE_REPLY, ownerMode, - ownerSubmode); - } - else - { - ModeMessage::setModeMessage(&reply, ModeMessage::REPLY_MODE_REPLY, - ownerMode, ownerSubmode); - } - MessageQueueSenderIF::sendMessage(theOneWhoCommandedAMode, &reply, - owner->getCommandQueue()); - } -} - -void ModeHelper::sendModeInfoMessage(Mode_t ownerMode, - Submode_t ownerSubmode) { - CommandMessage reply; - if (theOneWhoCommandedAMode != parentQueueId - and parentQueueId != MessageQueueMessageIF::NO_QUEUE) - { - ModeMessage::setModeMessage(&reply, ModeMessage::REPLY_MODE_INFO, - ownerMode, ownerSubmode); - MessageQueueSenderIF::sendMessage(parentQueueId, &reply, - owner->getCommandQueue()); - } -} - -void ModeHelper::startTimer(uint32_t timeoutMs) { - countdown.setTimeout(timeoutMs); -} - -void ModeHelper::setParentQueue(MessageQueueId_t parentQueueId) { - this->parentQueueId = parentQueueId; -} - -ReturnValue_t ModeHelper::initialize(void) { - return HasReturnvaluesIF::RETURN_OK; -} - -bool ModeHelper::isTimedOut() { - return countdown.hasTimedOut(); -} - -bool ModeHelper::isForced() { - return forced; -} - -void ModeHelper::setForced(bool forced) { - this->forced = forced; -} +#include "../modes/HasModesIF.h" +#include "../modes/ModeHelper.h" +#include "../serviceinterface/ServiceInterfaceStream.h" + +ModeHelper::ModeHelper(HasModesIF *owner) : + commandedMode(HasModesIF::MODE_OFF), + commandedSubmode(HasModesIF::SUBMODE_NONE), + owner(owner), forced(false) {} + +ModeHelper::~ModeHelper() { + +} + +ReturnValue_t ModeHelper::handleModeCommand(CommandMessage* command) { + CommandMessage reply; + Mode_t mode; + Submode_t submode; + switch (command->getCommand()) { + case ModeMessage::CMD_MODE_COMMAND_FORCED: + forced = true; + /* NO BREAK falls through*/ + case ModeMessage::CMD_MODE_COMMAND: { + mode = ModeMessage::getMode(command); + submode = ModeMessage::getSubmode(command); + uint32_t timeout; + ReturnValue_t result = owner->checkModeCommand(mode, submode, &timeout); + if (result != HasReturnvaluesIF::RETURN_OK) { + ModeMessage::cantReachMode(&reply, result); + MessageQueueSenderIF::sendMessage(command->getSender(), &reply, + owner->getCommandQueue()); + break; + } + //Free to start transition + theOneWhoCommandedAMode = command->getSender(); + commandedMode = mode; + commandedSubmode = submode; + + if ((parentQueueId != MessageQueueMessageIF::NO_QUEUE) + && (theOneWhoCommandedAMode != parentQueueId)) { + owner->setToExternalControl(); + } + + countdown.setTimeout(timeout); + owner->startTransition(mode, submode); + } + break; + case ModeMessage::CMD_MODE_READ: { + owner->getMode(&mode, &submode); + ModeMessage::setModeMessage(&reply, ModeMessage::REPLY_MODE_REPLY, mode, + submode); + MessageQueueSenderIF::sendMessage(command->getSender(), &reply, + owner->getCommandQueue()); + } + break; + case ModeMessage::CMD_MODE_ANNOUNCE: + owner->announceMode(false); + break; + case ModeMessage::CMD_MODE_ANNOUNCE_RECURSIVELY: + owner->announceMode(true); + break; + default: + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t ModeHelper::initialize(MessageQueueId_t parentQueueId) { + setParentQueue(parentQueueId); + return initialize(); +} + +void ModeHelper::modeChanged(Mode_t ownerMode, Submode_t ownerSubmode) { + forced = false; + sendModeReplyMessage(ownerMode, ownerSubmode); + sendModeInfoMessage(ownerMode, ownerSubmode); + theOneWhoCommandedAMode = MessageQueueMessageIF::NO_QUEUE; +} + +void ModeHelper::sendModeReplyMessage(Mode_t ownerMode, + Submode_t ownerSubmode) { + CommandMessage reply; + if (theOneWhoCommandedAMode != MessageQueueMessageIF::NO_QUEUE) + { + if (ownerMode != commandedMode or ownerSubmode != commandedSubmode) + { + ModeMessage::setModeMessage(&reply, + ModeMessage::REPLY_WRONG_MODE_REPLY, ownerMode, + ownerSubmode); + } + else + { + ModeMessage::setModeMessage(&reply, ModeMessage::REPLY_MODE_REPLY, + ownerMode, ownerSubmode); + } + MessageQueueSenderIF::sendMessage(theOneWhoCommandedAMode, &reply, + owner->getCommandQueue()); + } +} + +void ModeHelper::sendModeInfoMessage(Mode_t ownerMode, + Submode_t ownerSubmode) { + CommandMessage reply; + if (theOneWhoCommandedAMode != parentQueueId + and parentQueueId != MessageQueueMessageIF::NO_QUEUE) + { + ModeMessage::setModeMessage(&reply, ModeMessage::REPLY_MODE_INFO, + ownerMode, ownerSubmode); + MessageQueueSenderIF::sendMessage(parentQueueId, &reply, + owner->getCommandQueue()); + } +} + +void ModeHelper::startTimer(uint32_t timeoutMs) { + countdown.setTimeout(timeoutMs); +} + +void ModeHelper::setParentQueue(MessageQueueId_t parentQueueId) { + this->parentQueueId = parentQueueId; +} + +ReturnValue_t ModeHelper::initialize(void) { + return HasReturnvaluesIF::RETURN_OK; +} + +bool ModeHelper::isTimedOut() { + return countdown.hasTimedOut(); +} + +bool ModeHelper::isForced() { + return forced; +} + +void ModeHelper::setForced(bool forced) { + this->forced = forced; +} diff --git a/modes/ModeHelper.h b/modes/ModeHelper.h index b7f5868d..1e51bce5 100644 --- a/modes/ModeHelper.h +++ b/modes/ModeHelper.h @@ -1,53 +1,53 @@ -#ifndef MODEHELPER_H_ -#define MODEHELPER_H_ - -#include -#include -#include -#include - -class HasModesIF; - -class ModeHelper { -public: - MessageQueueId_t theOneWhoCommandedAMode = MessageQueueIF::NO_QUEUE; - Mode_t commandedMode; - Submode_t commandedSubmode; - - ModeHelper(HasModesIF *owner); - virtual ~ModeHelper(); - - ReturnValue_t handleModeCommand(CommandMessage *message); - - /** - * - * @param parentQueue the Queue id of the parent object. Set to 0 if no parent present - */ - void setParentQueue(MessageQueueId_t parentQueueId); - - ReturnValue_t initialize(MessageQueueId_t parentQueueId); - - ReturnValue_t initialize(void); //void is there to stop eclipse CODAN from falsely reporting an error - - void modeChanged(Mode_t mode, Submode_t submode); - - void startTimer(uint32_t timeoutMs); - - bool isTimedOut(); - - bool isForced(); - - void setForced(bool forced); -protected: - HasModesIF *owner; - MessageQueueId_t parentQueueId = MessageQueueIF::NO_QUEUE; - - Countdown countdown; - - bool forced; -private: - void sendModeReplyMessage(Mode_t ownerMode, Submode_t ownerSubmode); - void sendModeInfoMessage(Mode_t ownerMode, Submode_t ownerSubmode); -}; - -#endif /* MODEHELPER_H_ */ +#ifndef MODEHELPER_H_ +#define MODEHELPER_H_ + +#include "../ipc/MessageQueueIF.h" +#include "../modes/ModeMessage.h" +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../timemanager/Countdown.h" + +class HasModesIF; + +class ModeHelper { +public: + MessageQueueId_t theOneWhoCommandedAMode = MessageQueueIF::NO_QUEUE; + Mode_t commandedMode; + Submode_t commandedSubmode; + + ModeHelper(HasModesIF *owner); + virtual ~ModeHelper(); + + ReturnValue_t handleModeCommand(CommandMessage *message); + + /** + * + * @param parentQueue the Queue id of the parent object. Set to 0 if no parent present + */ + void setParentQueue(MessageQueueId_t parentQueueId); + + ReturnValue_t initialize(MessageQueueId_t parentQueueId); + + ReturnValue_t initialize(void); //void is there to stop eclipse CODAN from falsely reporting an error + + void modeChanged(Mode_t mode, Submode_t submode); + + void startTimer(uint32_t timeoutMs); + + bool isTimedOut(); + + bool isForced(); + + void setForced(bool forced); +protected: + HasModesIF *owner; + MessageQueueId_t parentQueueId = MessageQueueIF::NO_QUEUE; + + Countdown countdown; + + bool forced; +private: + void sendModeReplyMessage(Mode_t ownerMode, Submode_t ownerSubmode); + void sendModeInfoMessage(Mode_t ownerMode, Submode_t ownerSubmode); +}; + +#endif /* MODEHELPER_H_ */ diff --git a/modes/ModeMessage.cpp b/modes/ModeMessage.cpp index 1d3baad5..de3fc69c 100644 --- a/modes/ModeMessage.cpp +++ b/modes/ModeMessage.cpp @@ -1,31 +1,31 @@ -#include - -Mode_t ModeMessage::getMode(const CommandMessage* message) { - return message->getParameter(); -} - -Submode_t ModeMessage::getSubmode(const CommandMessage* message) { - return message->getParameter2(); -} - -ReturnValue_t ModeMessage::setModeMessage(CommandMessage* message, Command_t command, - Mode_t mode, Submode_t submode) { - message->setCommand( command ); - message->setParameter( mode ); - message->setParameter2( submode ); - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t ModeMessage::getCantReachModeReason(const CommandMessage* message) { - return message->getParameter(); -} - -void ModeMessage::clear(CommandMessage* message) { - message->setCommand(CommandMessage::CMD_NONE); -} - -void ModeMessage::cantReachMode(CommandMessage* message, ReturnValue_t reason) { - message->setCommand(REPLY_CANT_REACH_MODE); - message->setParameter(reason); - message->setParameter2(0); -} +#include "../modes/ModeMessage.h" + +Mode_t ModeMessage::getMode(const CommandMessage* message) { + return message->getParameter(); +} + +Submode_t ModeMessage::getSubmode(const CommandMessage* message) { + return message->getParameter2(); +} + +ReturnValue_t ModeMessage::setModeMessage(CommandMessage* message, Command_t command, + Mode_t mode, Submode_t submode) { + message->setCommand( command ); + message->setParameter( mode ); + message->setParameter2( submode ); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t ModeMessage::getCantReachModeReason(const CommandMessage* message) { + return message->getParameter(); +} + +void ModeMessage::clear(CommandMessage* message) { + message->setCommand(CommandMessage::CMD_NONE); +} + +void ModeMessage::cantReachMode(CommandMessage* message, ReturnValue_t reason) { + message->setCommand(REPLY_CANT_REACH_MODE); + message->setParameter(reason); + message->setParameter2(0); +} diff --git a/modes/ModeMessage.h b/modes/ModeMessage.h index 675c614b..63624b1d 100644 --- a/modes/ModeMessage.h +++ b/modes/ModeMessage.h @@ -1,40 +1,40 @@ -/** - * @file ModeMessage.h - * @brief This file defines the ModeMessage class. - * @date 17.07.2013 - * @author baetz - */ - -#ifndef MODEMESSAGE_H_ -#define MODEMESSAGE_H_ - -#include - -typedef uint32_t Mode_t; -typedef uint8_t Submode_t; - -class ModeMessage { -private: - ModeMessage(); -public: - static const uint8_t MESSAGE_ID = messagetypes::MODE_COMMAND; - static const Command_t CMD_MODE_COMMAND = MAKE_COMMAND_ID(0x01);//!> Command to set the specified Mode, replies are: REPLY_MODE_REPLY, REPLY_WRONG_MODE_REPLY, and REPLY_REJECTED; don't add any replies, as this will break the subsystem mode machine!! - static const Command_t CMD_MODE_COMMAND_FORCED = MAKE_COMMAND_ID(0xF1);//!> Command to set the specified Mode, regardless of external control flag, replies are: REPLY_MODE_REPLY, REPLY_WRONG_MODE_REPLY, and REPLY_REJECTED; don't add any replies, as this will break the subsystem mode machine!! - static const Command_t REPLY_MODE_REPLY = MAKE_COMMAND_ID(0x02);//!> Reply to a CMD_MODE_COMMAND or CMD_MODE_READ - static const Command_t REPLY_MODE_INFO = MAKE_COMMAND_ID(0x03); //!> Unrequested info about the current mode (used for composites to inform their container of a changed mode) - static const Command_t REPLY_CANT_REACH_MODE = MAKE_COMMAND_ID(0x04); //!> Reply in case a mode command can't be executed. Par1: returnCode, Par2: 0 - static const Command_t REPLY_WRONG_MODE_REPLY = MAKE_COMMAND_ID(0x05);//!> Reply to a CMD_MODE_COMMAND, indicating that a mode was commanded and a transition started but was aborted; the parameters contain the mode that was reached - static const Command_t CMD_MODE_READ = MAKE_COMMAND_ID(0x06);//!> Command to read the current mode and reply with a REPLY_MODE_REPLY - static const Command_t CMD_MODE_ANNOUNCE = MAKE_COMMAND_ID(0x07);//!> Command to trigger an ModeInfo Event. This command does NOT have a reply. - static const Command_t CMD_MODE_ANNOUNCE_RECURSIVELY = MAKE_COMMAND_ID(0x08);//!> Command to trigger an ModeInfo Event and to send this command to every child. This command does NOT have a reply. - - static Mode_t getMode(const CommandMessage* message); - static Submode_t getSubmode(const CommandMessage* message); - static ReturnValue_t setModeMessage(CommandMessage* message, - Command_t command, Mode_t mode, Submode_t submode); - static void cantReachMode(CommandMessage* message, ReturnValue_t reason); - static ReturnValue_t getCantReachModeReason(const CommandMessage* message); - static void clear(CommandMessage* message); -}; - -#endif /* MODEMESSAGE_H_ */ +/** + * @file ModeMessage.h + * @brief This file defines the ModeMessage class. + * @date 17.07.2013 + * @author baetz + */ + +#ifndef MODEMESSAGE_H_ +#define MODEMESSAGE_H_ + +#include "../ipc/CommandMessage.h" + +typedef uint32_t Mode_t; +typedef uint8_t Submode_t; + +class ModeMessage { +private: + ModeMessage(); +public: + static const uint8_t MESSAGE_ID = messagetypes::MODE_COMMAND; + static const Command_t CMD_MODE_COMMAND = MAKE_COMMAND_ID(0x01);//!> Command to set the specified Mode, replies are: REPLY_MODE_REPLY, REPLY_WRONG_MODE_REPLY, and REPLY_REJECTED; don't add any replies, as this will break the subsystem mode machine!! + static const Command_t CMD_MODE_COMMAND_FORCED = MAKE_COMMAND_ID(0xF1);//!> Command to set the specified Mode, regardless of external control flag, replies are: REPLY_MODE_REPLY, REPLY_WRONG_MODE_REPLY, and REPLY_REJECTED; don't add any replies, as this will break the subsystem mode machine!! + static const Command_t REPLY_MODE_REPLY = MAKE_COMMAND_ID(0x02);//!> Reply to a CMD_MODE_COMMAND or CMD_MODE_READ + static const Command_t REPLY_MODE_INFO = MAKE_COMMAND_ID(0x03); //!> Unrequested info about the current mode (used for composites to inform their container of a changed mode) + static const Command_t REPLY_CANT_REACH_MODE = MAKE_COMMAND_ID(0x04); //!> Reply in case a mode command can't be executed. Par1: returnCode, Par2: 0 + static const Command_t REPLY_WRONG_MODE_REPLY = MAKE_COMMAND_ID(0x05);//!> Reply to a CMD_MODE_COMMAND, indicating that a mode was commanded and a transition started but was aborted; the parameters contain the mode that was reached + static const Command_t CMD_MODE_READ = MAKE_COMMAND_ID(0x06);//!> Command to read the current mode and reply with a REPLY_MODE_REPLY + static const Command_t CMD_MODE_ANNOUNCE = MAKE_COMMAND_ID(0x07);//!> Command to trigger an ModeInfo Event. This command does NOT have a reply. + static const Command_t CMD_MODE_ANNOUNCE_RECURSIVELY = MAKE_COMMAND_ID(0x08);//!> Command to trigger an ModeInfo Event and to send this command to every child. This command does NOT have a reply. + + static Mode_t getMode(const CommandMessage* message); + static Submode_t getSubmode(const CommandMessage* message); + static ReturnValue_t setModeMessage(CommandMessage* message, + Command_t command, Mode_t mode, Submode_t submode); + static void cantReachMode(CommandMessage* message, ReturnValue_t reason); + static ReturnValue_t getCantReachModeReason(const CommandMessage* message); + static void clear(CommandMessage* message); +}; + +#endif /* MODEMESSAGE_H_ */ diff --git a/monitoring/AbsLimitMonitor.h b/monitoring/AbsLimitMonitor.h index 3525ba2c..6b546bd0 100644 --- a/monitoring/AbsLimitMonitor.h +++ b/monitoring/AbsLimitMonitor.h @@ -1,73 +1,73 @@ -#ifndef FRAMEWORK_MONITORING_ABSLIMITMONITOR_H_ -#define FRAMEWORK_MONITORING_ABSLIMITMONITOR_H_ - -#include -#include - -template -class AbsLimitMonitor: public MonitorBase { -public: - AbsLimitMonitor(object_id_t reporterId, uint8_t monitorId, uint32_t parameterId, - uint16_t confirmationLimit, T limit, Event violationEvent = MonitoringIF::VALUE_OUT_OF_RANGE, bool aboveIsViolation = true) : - MonitorBase(reporterId, monitorId, parameterId, confirmationLimit), limit(limit), violationEvent(violationEvent), aboveIsViolation(aboveIsViolation) { - } - virtual ~AbsLimitMonitor() { - } - virtual ReturnValue_t checkSample(T sample, T* crossedLimit) { - *crossedLimit = limit; - if (aboveIsViolation) { - if ((std::abs(sample) > limit)) { - return MonitoringIF::OUT_OF_RANGE; - } - } else { - if ((std::abs(sample) < limit)) { - return MonitoringIF::OUT_OF_RANGE; - } - } - return HasReturnvaluesIF::RETURN_OK; //We're not out of range. - } - - virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, - ParameterWrapper *parameterWrapper, - const ParameterWrapper *newValues, uint16_t startAtIndex) { - ReturnValue_t result = this->MonitorBase::getParameter(domainId, - parameterId, parameterWrapper, newValues, startAtIndex); - //We'll reuse the DOMAIN_ID of MonitorReporter, as we know the parameterIds used there. - if (result != this->INVALID_MATRIX_ID) { - return result; - } - switch (parameterId) { - case 10: - parameterWrapper->set(this->limit); - break; - default: - return this->INVALID_MATRIX_ID; - } - return HasReturnvaluesIF::RETURN_OK; - } - bool isOutOfLimits() { - if (this->oldState == MonitoringIF::OUT_OF_RANGE) { - return true; - } else { - return false; - } - } - void setLimit(T value) { - limit = value; - } -protected: - void sendTransitionEvent(T currentValue, ReturnValue_t state) { - switch (state) { - case MonitoringIF::OUT_OF_RANGE: - EventManagerIF::triggerEvent(this->reportingId, violationEvent, this->parameterId); - break; - default: - break; - } - } - T limit; - const Event violationEvent; - const bool aboveIsViolation; -}; - -#endif /* FRAMEWORK_MONITORING_ABSLIMITMONITOR_H_ */ +#ifndef FRAMEWORK_MONITORING_ABSLIMITMONITOR_H_ +#define FRAMEWORK_MONITORING_ABSLIMITMONITOR_H_ + +#include "../monitoring/MonitorBase.h" +#include + +template +class AbsLimitMonitor: public MonitorBase { +public: + AbsLimitMonitor(object_id_t reporterId, uint8_t monitorId, uint32_t parameterId, + uint16_t confirmationLimit, T limit, Event violationEvent = MonitoringIF::VALUE_OUT_OF_RANGE, bool aboveIsViolation = true) : + MonitorBase(reporterId, monitorId, parameterId, confirmationLimit), limit(limit), violationEvent(violationEvent), aboveIsViolation(aboveIsViolation) { + } + virtual ~AbsLimitMonitor() { + } + virtual ReturnValue_t checkSample(T sample, T* crossedLimit) { + *crossedLimit = limit; + if (aboveIsViolation) { + if ((std::abs(sample) > limit)) { + return MonitoringIF::OUT_OF_RANGE; + } + } else { + if ((std::abs(sample) < limit)) { + return MonitoringIF::OUT_OF_RANGE; + } + } + return HasReturnvaluesIF::RETURN_OK; //We're not out of range. + } + + virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, + ParameterWrapper *parameterWrapper, + const ParameterWrapper *newValues, uint16_t startAtIndex) { + ReturnValue_t result = this->MonitorBase::getParameter(domainId, + parameterId, parameterWrapper, newValues, startAtIndex); + //We'll reuse the DOMAIN_ID of MonitorReporter, as we know the parameterIds used there. + if (result != this->INVALID_MATRIX_ID) { + return result; + } + switch (parameterId) { + case 10: + parameterWrapper->set(this->limit); + break; + default: + return this->INVALID_MATRIX_ID; + } + return HasReturnvaluesIF::RETURN_OK; + } + bool isOutOfLimits() { + if (this->oldState == MonitoringIF::OUT_OF_RANGE) { + return true; + } else { + return false; + } + } + void setLimit(T value) { + limit = value; + } +protected: + void sendTransitionEvent(T currentValue, ReturnValue_t state) { + switch (state) { + case MonitoringIF::OUT_OF_RANGE: + EventManagerIF::triggerEvent(this->reportingId, violationEvent, this->parameterId); + break; + default: + break; + } + } + T limit; + const Event violationEvent; + const bool aboveIsViolation; +}; + +#endif /* FRAMEWORK_MONITORING_ABSLIMITMONITOR_H_ */ diff --git a/monitoring/HasMonitorsIF.h b/monitoring/HasMonitorsIF.h index 6f1dc1b3..be561efd 100644 --- a/monitoring/HasMonitorsIF.h +++ b/monitoring/HasMonitorsIF.h @@ -1,30 +1,30 @@ -/** - * @file HasMonitorsIF.h - * @brief This file defines the HasMonitorsIF class. - * @date 28.07.2014 - * @author baetz - */ -#ifndef HASMONITORSIF_H_ -#define HASMONITORSIF_H_ - -#include -#include -#include - -class HasMonitorsIF { -public: - static const uint8_t MAX_N_PARAMETER = 10; -// static const uint8_t MAX_N_LIMIT_ID = 10; - virtual ReturnValue_t setCheckingOfParameters(uint8_t checkingStrategy, - bool forOnePid = false, uint32_t parameterId = 0) = 0; - virtual ReturnValue_t modifyParameterMonitor(uint8_t limitType, - uint32_t parameterId, const uint8_t* data, uint32_t size) = 0; - virtual ReturnValue_t modifyObjectMonitor(uint32_t objectId, - const uint8_t* data, const uint32_t size) = 0; - virtual void setAllMonitorsToUnchecked() = 0; - virtual MessageQueueId_t getCommandQueue() const = 0; - virtual ~HasMonitorsIF() { - } -}; - -#endif /* HASMONITORSIF_H_ */ +/** + * @file HasMonitorsIF.h + * @brief This file defines the HasMonitorsIF class. + * @date 28.07.2014 + * @author baetz + */ +#ifndef HASMONITORSIF_H_ +#define HASMONITORSIF_H_ + +#include "../events/EventReportingProxyIF.h" +#include "../objectmanager/ObjectManagerIF.h" +#include "../ipc/MessageQueueSenderIF.h" + +class HasMonitorsIF { +public: + static const uint8_t MAX_N_PARAMETER = 10; +// static const uint8_t MAX_N_LIMIT_ID = 10; + virtual ReturnValue_t setCheckingOfParameters(uint8_t checkingStrategy, + bool forOnePid = false, uint32_t parameterId = 0) = 0; + virtual ReturnValue_t modifyParameterMonitor(uint8_t limitType, + uint32_t parameterId, const uint8_t* data, uint32_t size) = 0; + virtual ReturnValue_t modifyObjectMonitor(uint32_t objectId, + const uint8_t* data, const uint32_t size) = 0; + virtual void setAllMonitorsToUnchecked() = 0; + virtual MessageQueueId_t getCommandQueue() const = 0; + virtual ~HasMonitorsIF() { + } +}; + +#endif /* HASMONITORSIF_H_ */ diff --git a/monitoring/LimitMonitor.h b/monitoring/LimitMonitor.h index c24629a3..465d72e8 100644 --- a/monitoring/LimitMonitor.h +++ b/monitoring/LimitMonitor.h @@ -1,95 +1,95 @@ -#ifndef FRAMEWORK_MONITORING_LIMITMONITOR_H_ -#define FRAMEWORK_MONITORING_LIMITMONITOR_H_ - -#include - -/** - * Variant of a limit checking class. - * Newer version as compared to LimitCheckMonitor. - * Functionality is more or less the same, but does not use - * heavy weight MonitoringIF. - */ -template -class LimitMonitor: public MonitorBase { -public: - LimitMonitor(object_id_t reporterId, uint8_t monitorId, uint32_t parameterId, - uint16_t confirmationLimit, T lowerLimit, T upperLimit, - Event belowLowEvent = MonitoringIF::VALUE_BELOW_LOW_LIMIT, - Event aboveHighEvent = MonitoringIF::VALUE_ABOVE_HIGH_LIMIT) : - MonitorBase(reporterId, monitorId, parameterId, confirmationLimit), - lowerLimit(lowerLimit), upperLimit(upperLimit), belowLowEvent(belowLowEvent), - aboveHighEvent(aboveHighEvent) { - } - - virtual ~LimitMonitor() {} - - virtual ReturnValue_t checkSample(T sample, T* crossedLimit) { - *crossedLimit = 0.0; - if (sample > upperLimit) { - *crossedLimit = upperLimit; - return MonitoringIF::ABOVE_HIGH_LIMIT; - } else if (sample < lowerLimit) { - *crossedLimit = lowerLimit; - return MonitoringIF::BELOW_LOW_LIMIT; - } else { - return HasReturnvaluesIF::RETURN_OK; //Within limits. - } - } - - virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, - ParameterWrapper *parameterWrapper, - const ParameterWrapper *newValues, uint16_t startAtIndex) { - ReturnValue_t result = this->MonitorBase::getParameter(domainId, - parameterId, parameterWrapper, newValues, startAtIndex); - //We'll reuse the DOMAIN_ID of MonitorReporter, as we know the parameterIds used there. - if (result != this->INVALID_MATRIX_ID) { - return result; - } - switch (parameterId) { - case 10: - parameterWrapper->set(this->lowerLimit); - break; - case 11: - parameterWrapper->set(this->upperLimit); - break; - default: - return this->INVALID_MATRIX_ID; - } - return HasReturnvaluesIF::RETURN_OK; - } - bool isOutOfLimits() { - if (this->oldState == MonitoringIF::ABOVE_HIGH_LIMIT || this->oldState == MonitoringIF::BELOW_LOW_LIMIT) { - return true; - } else { - return false; - } - } - - T getLowerLimit() const { - return lowerLimit; - } - - T getUpperLimit() const { - return upperLimit; - } - -protected: - void sendTransitionEvent(T currentValue, ReturnValue_t state) { - switch (state) { - case MonitoringIF::BELOW_LOW_LIMIT: - EventManagerIF::triggerEvent(this->reportingId, belowLowEvent, this->parameterId); - break; - case MonitoringIF::ABOVE_HIGH_LIMIT: - EventManagerIF::triggerEvent(this->reportingId, aboveHighEvent, this->parameterId); - break; - default: - break; - } - } - T lowerLimit; - T upperLimit; - const Event belowLowEvent; - const Event aboveHighEvent; -}; - -#endif /* FRAMEWORK_MONITORING_LIMITMONITOR_H_ */ +#ifndef FRAMEWORK_MONITORING_LIMITMONITOR_H_ +#define FRAMEWORK_MONITORING_LIMITMONITOR_H_ + +#include "../monitoring/MonitorBase.h" + +/** + * Variant of a limit checking class. + * Newer version as compared to LimitCheckMonitor. + * Functionality is more or less the same, but does not use + * heavy weight MonitoringIF. + */ +template +class LimitMonitor: public MonitorBase { +public: + LimitMonitor(object_id_t reporterId, uint8_t monitorId, uint32_t parameterId, + uint16_t confirmationLimit, T lowerLimit, T upperLimit, + Event belowLowEvent = MonitoringIF::VALUE_BELOW_LOW_LIMIT, + Event aboveHighEvent = MonitoringIF::VALUE_ABOVE_HIGH_LIMIT) : + MonitorBase(reporterId, monitorId, parameterId, confirmationLimit), + lowerLimit(lowerLimit), upperLimit(upperLimit), belowLowEvent(belowLowEvent), + aboveHighEvent(aboveHighEvent) { + } + + virtual ~LimitMonitor() {} + + virtual ReturnValue_t checkSample(T sample, T* crossedLimit) { + *crossedLimit = 0.0; + if (sample > upperLimit) { + *crossedLimit = upperLimit; + return MonitoringIF::ABOVE_HIGH_LIMIT; + } else if (sample < lowerLimit) { + *crossedLimit = lowerLimit; + return MonitoringIF::BELOW_LOW_LIMIT; + } else { + return HasReturnvaluesIF::RETURN_OK; //Within limits. + } + } + + virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, + ParameterWrapper *parameterWrapper, + const ParameterWrapper *newValues, uint16_t startAtIndex) { + ReturnValue_t result = this->MonitorBase::getParameter(domainId, + parameterId, parameterWrapper, newValues, startAtIndex); + //We'll reuse the DOMAIN_ID of MonitorReporter, as we know the parameterIds used there. + if (result != this->INVALID_MATRIX_ID) { + return result; + } + switch (parameterId) { + case 10: + parameterWrapper->set(this->lowerLimit); + break; + case 11: + parameterWrapper->set(this->upperLimit); + break; + default: + return this->INVALID_MATRIX_ID; + } + return HasReturnvaluesIF::RETURN_OK; + } + bool isOutOfLimits() { + if (this->oldState == MonitoringIF::ABOVE_HIGH_LIMIT || this->oldState == MonitoringIF::BELOW_LOW_LIMIT) { + return true; + } else { + return false; + } + } + + T getLowerLimit() const { + return lowerLimit; + } + + T getUpperLimit() const { + return upperLimit; + } + +protected: + void sendTransitionEvent(T currentValue, ReturnValue_t state) { + switch (state) { + case MonitoringIF::BELOW_LOW_LIMIT: + EventManagerIF::triggerEvent(this->reportingId, belowLowEvent, this->parameterId); + break; + case MonitoringIF::ABOVE_HIGH_LIMIT: + EventManagerIF::triggerEvent(this->reportingId, aboveHighEvent, this->parameterId); + break; + default: + break; + } + } + T lowerLimit; + T upperLimit; + const Event belowLowEvent; + const Event aboveHighEvent; +}; + +#endif /* FRAMEWORK_MONITORING_LIMITMONITOR_H_ */ diff --git a/monitoring/LimitViolationReporter.cpp b/monitoring/LimitViolationReporter.cpp index 489a8f9e..7869dc2b 100644 --- a/monitoring/LimitViolationReporter.cpp +++ b/monitoring/LimitViolationReporter.cpp @@ -1,60 +1,60 @@ -/** - * @file LimitViolationReporter.cpp - * @brief This file defines the LimitViolationReporter class. - * @date 17.07.2014 - * @author baetz - */ -#include -#include -#include -#include -#include - -ReturnValue_t LimitViolationReporter::sendLimitViolationReport(const SerializeIF* data) { - ReturnValue_t result = checkClassLoaded(); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - store_address_t storeId; - uint8_t* dataTarget = NULL; - size_t maxSize = data->getSerializedSize(); - if (maxSize > MonitoringIF::VIOLATION_REPORT_MAX_SIZE) { - return MonitoringIF::INVALID_SIZE; - } - result = ipcStore->getFreeElement(&storeId, maxSize, - &dataTarget); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - size_t size = 0; - result = data->serialize(&dataTarget, &size, maxSize, SerializeIF::Endianness::BIG); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - CommandMessage report; - MonitoringMessage::setLimitViolationReport(&report, storeId); - return MessageQueueSenderIF::sendMessage(reportQueue, &report); -} - -ReturnValue_t LimitViolationReporter::checkClassLoaded() { - if (reportQueue == 0) { - ReceivesMonitoringReportsIF* receiver = objectManager->get< - ReceivesMonitoringReportsIF>(reportingTarget); - if (receiver == NULL) { - return ObjectManagerIF::NOT_FOUND; - } - reportQueue = receiver->getCommandQueue(); - } - if (ipcStore == NULL) { - ipcStore = objectManager->get(objects::IPC_STORE); - if (ipcStore == NULL) { - return HasReturnvaluesIF::RETURN_FAILED; - } - } - return HasReturnvaluesIF::RETURN_OK; -} - -//Lazy initialization. -MessageQueueId_t LimitViolationReporter::reportQueue = 0; -StorageManagerIF* LimitViolationReporter::ipcStore = NULL; -object_id_t LimitViolationReporter::reportingTarget = 0; +/** + * @file LimitViolationReporter.cpp + * @brief This file defines the LimitViolationReporter class. + * @date 17.07.2014 + * @author baetz + */ +#include "../monitoring/LimitViolationReporter.h" +#include "../monitoring/MonitoringIF.h" +#include "../monitoring/ReceivesMonitoringReportsIF.h" +#include "../objectmanager/ObjectManagerIF.h" +#include "../serialize/SerializeAdapter.h" + +ReturnValue_t LimitViolationReporter::sendLimitViolationReport(const SerializeIF* data) { + ReturnValue_t result = checkClassLoaded(); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + store_address_t storeId; + uint8_t* dataTarget = NULL; + size_t maxSize = data->getSerializedSize(); + if (maxSize > MonitoringIF::VIOLATION_REPORT_MAX_SIZE) { + return MonitoringIF::INVALID_SIZE; + } + result = ipcStore->getFreeElement(&storeId, maxSize, + &dataTarget); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + size_t size = 0; + result = data->serialize(&dataTarget, &size, maxSize, SerializeIF::Endianness::BIG); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + CommandMessage report; + MonitoringMessage::setLimitViolationReport(&report, storeId); + return MessageQueueSenderIF::sendMessage(reportQueue, &report); +} + +ReturnValue_t LimitViolationReporter::checkClassLoaded() { + if (reportQueue == 0) { + ReceivesMonitoringReportsIF* receiver = objectManager->get< + ReceivesMonitoringReportsIF>(reportingTarget); + if (receiver == NULL) { + return ObjectManagerIF::NOT_FOUND; + } + reportQueue = receiver->getCommandQueue(); + } + if (ipcStore == NULL) { + ipcStore = objectManager->get(objects::IPC_STORE); + if (ipcStore == NULL) { + return HasReturnvaluesIF::RETURN_FAILED; + } + } + return HasReturnvaluesIF::RETURN_OK; +} + +//Lazy initialization. +MessageQueueId_t LimitViolationReporter::reportQueue = 0; +StorageManagerIF* LimitViolationReporter::ipcStore = NULL; +object_id_t LimitViolationReporter::reportingTarget = 0; diff --git a/monitoring/LimitViolationReporter.h b/monitoring/LimitViolationReporter.h index 3a9d04dd..53d67b9d 100644 --- a/monitoring/LimitViolationReporter.h +++ b/monitoring/LimitViolationReporter.h @@ -1,31 +1,31 @@ -/** - * @file LimitViolationReporter.h - * @brief This file defines the LimitViolationReporter class. - * @date 17.07.2014 - * @author baetz - */ -#ifndef LIMITVIOLATIONREPORTER_H_ -#define LIMITVIOLATIONREPORTER_H_ - -#include -#include -#include -#include - -namespace Factory{ -void setStaticFrameworkObjectIds(); -} - -class LimitViolationReporter { - friend void (Factory::setStaticFrameworkObjectIds)(); -public: - static ReturnValue_t sendLimitViolationReport(const SerializeIF* data); -private: - static object_id_t reportingTarget; - static MessageQueueId_t reportQueue; - static StorageManagerIF* ipcStore; - static ReturnValue_t checkClassLoaded(); - LimitViolationReporter(); -}; - -#endif /* LIMITVIOLATIONREPORTER_H_ */ +/** + * @file LimitViolationReporter.h + * @brief This file defines the LimitViolationReporter class. + * @date 17.07.2014 + * @author baetz + */ +#ifndef LIMITVIOLATIONREPORTER_H_ +#define LIMITVIOLATIONREPORTER_H_ + +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../serialize/SerializeIF.h" +#include "../storagemanager/StorageManagerIF.h" +#include "../ipc/MessageQueueSenderIF.h" + +namespace Factory{ +void setStaticFrameworkObjectIds(); +} + +class LimitViolationReporter { + friend void (Factory::setStaticFrameworkObjectIds)(); +public: + static ReturnValue_t sendLimitViolationReport(const SerializeIF* data); +private: + static object_id_t reportingTarget; + static MessageQueueId_t reportQueue; + static StorageManagerIF* ipcStore; + static ReturnValue_t checkClassLoaded(); + LimitViolationReporter(); +}; + +#endif /* LIMITVIOLATIONREPORTER_H_ */ diff --git a/monitoring/MonitorBase.h b/monitoring/MonitorBase.h index f18ca4b5..45fe22ec 100644 --- a/monitoring/MonitorBase.h +++ b/monitoring/MonitorBase.h @@ -1,62 +1,62 @@ -#ifndef MONITORBASE_H_ -#define MONITORBASE_H_ - -#include -#include -#include -#include -#include -#include - -/** - * Base class for monitoring of parameters. - * Can be used anywhere, specializations need to implement checkSample and should override sendTransitionEvent. - * Manages state handling, enabling and disabling of events/reports and forwarding of transition - * reports via MonitorReporter. In addition, it provides default implementations for fetching the parameter sample from - * the data pool and a simple confirmation counter. - */ -template -class MonitorBase: public MonitorReporter { -public: - MonitorBase(object_id_t reporterId, uint8_t monitorId, - uint32_t parameterId, uint16_t confirmationLimit) : - MonitorReporter(reporterId, monitorId, parameterId, confirmationLimit) { - } - virtual ~MonitorBase() { - } - virtual ReturnValue_t check() { - //1. Fetch sample of type T, return validity. - T sample = 0; - ReturnValue_t validity = fetchSample(&sample); - - //2. If returning from fetch != OK, parameter is invalid. Report (if oldState is != invalidity). - if (validity != HasReturnvaluesIF::RETURN_OK) { - this->monitorStateIs(validity, sample, 0); - //3. Otherwise, check sample. - } else { - this->oldState = doCheck(sample); - } - return this->oldState; - } - virtual ReturnValue_t doCheck(T sample) { - T crossedLimit = 0.0; - ReturnValue_t currentState = checkSample(sample, &crossedLimit); - return this->monitorStateIs(currentState,sample, crossedLimit); - } - //Abstract or default. - virtual ReturnValue_t checkSample(T sample, T* crossedLimit) = 0; - -protected: - virtual ReturnValue_t fetchSample(T* sample) { - GlobDataSet mySet; - PIDReader parameter(this->parameterId, &mySet); - mySet.read(); - if (!parameter.isValid()) { - return MonitoringIF::INVALID; - } - *sample = parameter.value; - return HasReturnvaluesIF::RETURN_OK; - } -}; - -#endif /* MONITORBASE_H_ */ +#ifndef MONITORBASE_H_ +#define MONITORBASE_H_ + +#include "../datapoolglob/GlobalDataSet.h" +#include "../datapoolglob/PIDReader.h" +#include "../monitoring/LimitViolationReporter.h" +#include "../monitoring/MonitoringIF.h" +#include "../monitoring/MonitoringMessageContent.h" +#include "../monitoring/MonitorReporter.h" + +/** + * Base class for monitoring of parameters. + * Can be used anywhere, specializations need to implement checkSample and should override sendTransitionEvent. + * Manages state handling, enabling and disabling of events/reports and forwarding of transition + * reports via MonitorReporter. In addition, it provides default implementations for fetching the parameter sample from + * the data pool and a simple confirmation counter. + */ +template +class MonitorBase: public MonitorReporter { +public: + MonitorBase(object_id_t reporterId, uint8_t monitorId, + uint32_t parameterId, uint16_t confirmationLimit) : + MonitorReporter(reporterId, monitorId, parameterId, confirmationLimit) { + } + virtual ~MonitorBase() { + } + virtual ReturnValue_t check() { + //1. Fetch sample of type T, return validity. + T sample = 0; + ReturnValue_t validity = fetchSample(&sample); + + //2. If returning from fetch != OK, parameter is invalid. Report (if oldState is != invalidity). + if (validity != HasReturnvaluesIF::RETURN_OK) { + this->monitorStateIs(validity, sample, 0); + //3. Otherwise, check sample. + } else { + this->oldState = doCheck(sample); + } + return this->oldState; + } + virtual ReturnValue_t doCheck(T sample) { + T crossedLimit = 0.0; + ReturnValue_t currentState = checkSample(sample, &crossedLimit); + return this->monitorStateIs(currentState,sample, crossedLimit); + } + //Abstract or default. + virtual ReturnValue_t checkSample(T sample, T* crossedLimit) = 0; + +protected: + virtual ReturnValue_t fetchSample(T* sample) { + GlobDataSet mySet; + PIDReader parameter(this->parameterId, &mySet); + mySet.read(); + if (!parameter.isValid()) { + return MonitoringIF::INVALID; + } + *sample = parameter.value; + return HasReturnvaluesIF::RETURN_OK; + } +}; + +#endif /* MONITORBASE_H_ */ diff --git a/monitoring/MonitorReporter.h b/monitoring/MonitorReporter.h index 6274313f..69bb00ea 100644 --- a/monitoring/MonitorReporter.h +++ b/monitoring/MonitorReporter.h @@ -1,178 +1,178 @@ -#ifndef FRAMEWORK_MONITORING_MONITORREPORTER_H_ -#define FRAMEWORK_MONITORING_MONITORREPORTER_H_ - -#include -#include -#include -#include -#include - -template -class MonitorReporter: public HasParametersIF { -public: - - static const uint8_t ENABLED = 1; - static const uint8_t DISABLED = 0; - - MonitorReporter(object_id_t reportingId, uint8_t monitorId, uint32_t parameterId, uint16_t confirmationLimit) : - monitorId(monitorId), parameterId(parameterId), reportingId( - reportingId), oldState(MonitoringIF::UNCHECKED), reportingEnabled( - ENABLED), eventEnabled(ENABLED), currentCounter(0), confirmationLimit( - confirmationLimit) { - } - - virtual ~MonitorReporter() { - } - - ReturnValue_t monitorStateIs(ReturnValue_t state, T parameterValue = 0, - T crossedLimit = 0) { - if (state != oldState) { - if (isConfirmed(state)) { - if (eventEnabled == ENABLED) { - sendTransitionEvent(parameterValue, state); - } - if (reportingEnabled == ENABLED) { - sendTransitionReport(parameterValue, crossedLimit, state); - } - oldState = state; - } else { - //This is to ensure confirmation works. - //Needs to be reset to be able to confirm against oldState again next time. - return oldState; - } - } else { - resetConfirmation(); - } - return state; - } - - virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, - ParameterWrapper *parameterWrapper, - const ParameterWrapper *newValues, uint16_t startAtIndex) { - if (domainId != monitorId) { - return INVALID_DOMAIN_ID; - } - switch (parameterId) { - case 0: - parameterWrapper->set(this->confirmationLimit); - break; - case 1: - parameterWrapper->set(this->reportingEnabled); - break; - case 2: - parameterWrapper->set(this->eventEnabled); - break; - default: - return INVALID_MATRIX_ID; - } - return HasReturnvaluesIF::RETURN_OK; - } - virtual ReturnValue_t setToUnchecked() { - return setToState(MonitoringIF::UNCHECKED); - } - virtual ReturnValue_t setToInvalid() { - return setToState(MonitoringIF::INVALID); - } - object_id_t getReporterId() const { - return reportingId; - } - - void setEventEnabled(uint8_t eventEnabled) { - this->eventEnabled = eventEnabled; - } - - void setReportingEnabled(uint8_t reportingEnabled) { - this->reportingEnabled = reportingEnabled; - } - - bool isEventEnabled() const { - return (eventEnabled == ENABLED); - } - -protected: - const uint8_t monitorId; - const uint32_t parameterId; - object_id_t reportingId; - ReturnValue_t oldState; - - uint8_t reportingEnabled; - - uint8_t eventEnabled; - - uint16_t currentCounter; - uint16_t confirmationLimit; - - bool isConfirmed(ReturnValue_t state) { - //Confirm INVALID and UNCHECKED immediately. - if (state == MonitoringIF::INVALID - || state == MonitoringIF::UNCHECKED) { - currentCounter = 0; - return true; - } - return doesChildConfirm(state); - } - - /** - * This is the most simple form of confirmation. - * A counter counts any violation and compares the number to maxCounter. - * @param state The state, indicating the type of violation. Not used here. - * @return true if counter > maxCounter, else false. - */ - virtual bool doesChildConfirm(ReturnValue_t state) { - currentCounter += 1; - if (currentCounter > confirmationLimit) { - currentCounter = 0; - return true; - } else { - return false; - } - } - /** - * This method needs to reset the confirmation in case a valid sample was found. - * Here, simply resets the current counter. - */ - virtual void resetConfirmation() { - currentCounter = 0; - } - /** - * Default version of sending transitional events. - * Should be overridden from specialized monitors. - * @param currentValue The current value which was monitored. - * @param state The state the monitor changed to. - */ - virtual void sendTransitionEvent(T currentValue, ReturnValue_t state) { - switch(state) { - case MonitoringIF::UNCHECKED: - case MonitoringIF::UNSELECTED: - case MonitoringIF::INVALID: - case HasReturnvaluesIF::RETURN_OK: - break; - default: - EventManagerIF::triggerEvent(reportingId, MonitoringIF::MONITOR_CHANGED_STATE, state); - break; - } - } - /** - * Default implementation for sending transition report. - * May be overridden, but is seldom necessary. - * @param parameterValue Current value of the parameter - * @param crossedLimit The limit crossed (if applicable). - * @param state Current state the monitor is in. - */ - virtual void sendTransitionReport(T parameterValue, T crossedLimit, ReturnValue_t state) { - MonitoringReportContent report(parameterId, - parameterValue, crossedLimit, oldState, state); - LimitViolationReporter::sendLimitViolationReport(&report); - } - ReturnValue_t setToState(ReturnValue_t state) { - if (oldState != state && reportingEnabled) { - MonitoringReportContent report(parameterId, 0, 0, oldState, - state); - LimitViolationReporter::sendLimitViolationReport(&report); - oldState = state; - } - return HasReturnvaluesIF::RETURN_OK; - } -}; - -#endif /* FRAMEWORK_MONITORING_MONITORREPORTER_H_ */ +#ifndef FRAMEWORK_MONITORING_MONITORREPORTER_H_ +#define FRAMEWORK_MONITORING_MONITORREPORTER_H_ + +#include "../events/EventManagerIF.h" +#include "../monitoring/LimitViolationReporter.h" +#include "../monitoring/MonitoringIF.h" +#include "../monitoring/MonitoringMessageContent.h" +#include "../parameters/HasParametersIF.h" + +template +class MonitorReporter: public HasParametersIF { +public: + + static const uint8_t ENABLED = 1; + static const uint8_t DISABLED = 0; + + MonitorReporter(object_id_t reportingId, uint8_t monitorId, uint32_t parameterId, uint16_t confirmationLimit) : + monitorId(monitorId), parameterId(parameterId), reportingId( + reportingId), oldState(MonitoringIF::UNCHECKED), reportingEnabled( + ENABLED), eventEnabled(ENABLED), currentCounter(0), confirmationLimit( + confirmationLimit) { + } + + virtual ~MonitorReporter() { + } + + ReturnValue_t monitorStateIs(ReturnValue_t state, T parameterValue = 0, + T crossedLimit = 0) { + if (state != oldState) { + if (isConfirmed(state)) { + if (eventEnabled == ENABLED) { + sendTransitionEvent(parameterValue, state); + } + if (reportingEnabled == ENABLED) { + sendTransitionReport(parameterValue, crossedLimit, state); + } + oldState = state; + } else { + //This is to ensure confirmation works. + //Needs to be reset to be able to confirm against oldState again next time. + return oldState; + } + } else { + resetConfirmation(); + } + return state; + } + + virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, + ParameterWrapper *parameterWrapper, + const ParameterWrapper *newValues, uint16_t startAtIndex) { + if (domainId != monitorId) { + return INVALID_DOMAIN_ID; + } + switch (parameterId) { + case 0: + parameterWrapper->set(this->confirmationLimit); + break; + case 1: + parameterWrapper->set(this->reportingEnabled); + break; + case 2: + parameterWrapper->set(this->eventEnabled); + break; + default: + return INVALID_MATRIX_ID; + } + return HasReturnvaluesIF::RETURN_OK; + } + virtual ReturnValue_t setToUnchecked() { + return setToState(MonitoringIF::UNCHECKED); + } + virtual ReturnValue_t setToInvalid() { + return setToState(MonitoringIF::INVALID); + } + object_id_t getReporterId() const { + return reportingId; + } + + void setEventEnabled(uint8_t eventEnabled) { + this->eventEnabled = eventEnabled; + } + + void setReportingEnabled(uint8_t reportingEnabled) { + this->reportingEnabled = reportingEnabled; + } + + bool isEventEnabled() const { + return (eventEnabled == ENABLED); + } + +protected: + const uint8_t monitorId; + const uint32_t parameterId; + object_id_t reportingId; + ReturnValue_t oldState; + + uint8_t reportingEnabled; + + uint8_t eventEnabled; + + uint16_t currentCounter; + uint16_t confirmationLimit; + + bool isConfirmed(ReturnValue_t state) { + //Confirm INVALID and UNCHECKED immediately. + if (state == MonitoringIF::INVALID + || state == MonitoringIF::UNCHECKED) { + currentCounter = 0; + return true; + } + return doesChildConfirm(state); + } + + /** + * This is the most simple form of confirmation. + * A counter counts any violation and compares the number to maxCounter. + * @param state The state, indicating the type of violation. Not used here. + * @return true if counter > maxCounter, else false. + */ + virtual bool doesChildConfirm(ReturnValue_t state) { + currentCounter += 1; + if (currentCounter > confirmationLimit) { + currentCounter = 0; + return true; + } else { + return false; + } + } + /** + * This method needs to reset the confirmation in case a valid sample was found. + * Here, simply resets the current counter. + */ + virtual void resetConfirmation() { + currentCounter = 0; + } + /** + * Default version of sending transitional events. + * Should be overridden from specialized monitors. + * @param currentValue The current value which was monitored. + * @param state The state the monitor changed to. + */ + virtual void sendTransitionEvent(T currentValue, ReturnValue_t state) { + switch(state) { + case MonitoringIF::UNCHECKED: + case MonitoringIF::UNSELECTED: + case MonitoringIF::INVALID: + case HasReturnvaluesIF::RETURN_OK: + break; + default: + EventManagerIF::triggerEvent(reportingId, MonitoringIF::MONITOR_CHANGED_STATE, state); + break; + } + } + /** + * Default implementation for sending transition report. + * May be overridden, but is seldom necessary. + * @param parameterValue Current value of the parameter + * @param crossedLimit The limit crossed (if applicable). + * @param state Current state the monitor is in. + */ + virtual void sendTransitionReport(T parameterValue, T crossedLimit, ReturnValue_t state) { + MonitoringReportContent report(parameterId, + parameterValue, crossedLimit, oldState, state); + LimitViolationReporter::sendLimitViolationReport(&report); + } + ReturnValue_t setToState(ReturnValue_t state) { + if (oldState != state && reportingEnabled) { + MonitoringReportContent report(parameterId, 0, 0, oldState, + state); + LimitViolationReporter::sendLimitViolationReport(&report); + oldState = state; + } + return HasReturnvaluesIF::RETURN_OK; + } +}; + +#endif /* FRAMEWORK_MONITORING_MONITORREPORTER_H_ */ diff --git a/monitoring/MonitoringIF.h b/monitoring/MonitoringIF.h index d2d62f35..a4c0666c 100644 --- a/monitoring/MonitoringIF.h +++ b/monitoring/MonitoringIF.h @@ -1,67 +1,67 @@ -#ifndef MONITORINGIF_H_ -#define MONITORINGIF_H_ - -#include -#include -#include - -class MonitoringIF : public SerializeIF { -public: - static const uint8_t VIOLATION_REPORT_MAX_SIZE = 32; - static const uint8_t LIMIT_TYPE_NO_TYPE = 0xFF; - static const uint8_t LIMIT_TYPE_LIMIT_CHECK = 0; - static const uint8_t LIMIT_TYPE_DELTA_CHECK = 1; - static const uint8_t LIMIT_TYPE_ABSOLUTE_CHECK = 2; - static const uint8_t LIMIT_TYPE_OBJECT = 128; - - static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::FDIR_2; - static const Event MONITOR_CHANGED_STATE = MAKE_EVENT(1, SEVERITY::LOW); - static const Event VALUE_BELOW_LOW_LIMIT = MAKE_EVENT(2, SEVERITY::LOW); - static const Event VALUE_ABOVE_HIGH_LIMIT = MAKE_EVENT(3, SEVERITY::LOW); - static const Event VALUE_OUT_OF_RANGE = MAKE_EVENT(4, SEVERITY::LOW); - - static const uint8_t INTERFACE_ID = CLASS_ID::LIMITS_IF; - static const ReturnValue_t UNCHECKED = MAKE_RETURN_CODE(1); - static const ReturnValue_t INVALID = MAKE_RETURN_CODE(2); - static const ReturnValue_t UNSELECTED = MAKE_RETURN_CODE(3); - static const ReturnValue_t BELOW_LOW_LIMIT = MAKE_RETURN_CODE(4); -// static const ReturnValue_t CHECKING_STATUS_BELOW_LOW_THRESHOLD = MAKE_RETURN_CODE(4); -// static const ReturnValue_t CHECKING_STATUS_ABOVE_HIGH_THRESHOLD = MAKE_RETURN_CODE(5); - static const ReturnValue_t ABOVE_HIGH_LIMIT = MAKE_RETURN_CODE(5); - static const ReturnValue_t UNEXPECTED_VALUE = MAKE_RETURN_CODE(6); - static const ReturnValue_t OUT_OF_RANGE = MAKE_RETURN_CODE(7); - - - static const ReturnValue_t FIRST_SAMPLE = MAKE_RETURN_CODE(0xA0); - static const ReturnValue_t INVALID_SIZE = MAKE_RETURN_CODE(0xE0); - static const ReturnValue_t WRONG_TYPE = MAKE_RETURN_CODE(0xE1); - static const ReturnValue_t WRONG_PID = MAKE_RETURN_CODE(0xE2); - static const ReturnValue_t WRONG_LIMIT_ID = MAKE_RETURN_CODE(0xE3); - static const ReturnValue_t MONITOR_NOT_FOUND = MAKE_RETURN_CODE(0xEE); - - static const uint8_t REPORT_NONE = 0; - static const uint8_t REPORT_EVENTS_ONLY = 1; - static const uint8_t REPORT_REPORTS_ONLY = 2; - static const uint8_t REPORT_ALL = 3; - -// static const ReturnValue_t STILL_IN_LOW_WARNING = MAKE_RETURN_CODE(0x11); -// static const ReturnValue_t STILL_IN_LOW_LIMIT = MAKE_RETURN_CODE(0x12); -// static const ReturnValue_t STILL_IN_HIGH_WARNING = MAKE_RETURN_CODE(0x13); -// static const ReturnValue_t STILL_IN_HIGH_LIMIT = MAKE_RETURN_CODE(0x14); -// static const ReturnValue_t VARIABLE_IS_INVALID = MAKE_RETURN_CODE(0xE0); -// static const ReturnValue_t INVALID_SIZE = MAKE_RETURN_CODE(0xE1); -// static const ReturnValue_t INVALID_ID = MAKE_RETURN_CODE(0xE2); - virtual ReturnValue_t check() = 0; - virtual ReturnValue_t setLimits( uint8_t type, const uint8_t* data, uint32_t size) = 0; - virtual ReturnValue_t setChecking(uint8_t strategy) = 0; - virtual ReturnValue_t setToUnchecked() = 0; - virtual uint8_t getLimitType() const = 0; - virtual uint32_t getLimitId() const = 0; -// virtual ReturnValue_t setEventReporting(bool active) = 0; - virtual ~MonitoringIF() { - } -}; - - - -#endif /* MONITORINGIF_H_ */ +#ifndef MONITORINGIF_H_ +#define MONITORINGIF_H_ + +#include "../memory/HasMemoryIF.h" +#include "../monitoring/MonitoringMessage.h" +#include "../serialize/SerializeIF.h" + +class MonitoringIF : public SerializeIF { +public: + static const uint8_t VIOLATION_REPORT_MAX_SIZE = 32; + static const uint8_t LIMIT_TYPE_NO_TYPE = 0xFF; + static const uint8_t LIMIT_TYPE_LIMIT_CHECK = 0; + static const uint8_t LIMIT_TYPE_DELTA_CHECK = 1; + static const uint8_t LIMIT_TYPE_ABSOLUTE_CHECK = 2; + static const uint8_t LIMIT_TYPE_OBJECT = 128; + + static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::FDIR_2; + static const Event MONITOR_CHANGED_STATE = MAKE_EVENT(1, SEVERITY::LOW); + static const Event VALUE_BELOW_LOW_LIMIT = MAKE_EVENT(2, SEVERITY::LOW); + static const Event VALUE_ABOVE_HIGH_LIMIT = MAKE_EVENT(3, SEVERITY::LOW); + static const Event VALUE_OUT_OF_RANGE = MAKE_EVENT(4, SEVERITY::LOW); + + static const uint8_t INTERFACE_ID = CLASS_ID::LIMITS_IF; + static const ReturnValue_t UNCHECKED = MAKE_RETURN_CODE(1); + static const ReturnValue_t INVALID = MAKE_RETURN_CODE(2); + static const ReturnValue_t UNSELECTED = MAKE_RETURN_CODE(3); + static const ReturnValue_t BELOW_LOW_LIMIT = MAKE_RETURN_CODE(4); +// static const ReturnValue_t CHECKING_STATUS_BELOW_LOW_THRESHOLD = MAKE_RETURN_CODE(4); +// static const ReturnValue_t CHECKING_STATUS_ABOVE_HIGH_THRESHOLD = MAKE_RETURN_CODE(5); + static const ReturnValue_t ABOVE_HIGH_LIMIT = MAKE_RETURN_CODE(5); + static const ReturnValue_t UNEXPECTED_VALUE = MAKE_RETURN_CODE(6); + static const ReturnValue_t OUT_OF_RANGE = MAKE_RETURN_CODE(7); + + + static const ReturnValue_t FIRST_SAMPLE = MAKE_RETURN_CODE(0xA0); + static const ReturnValue_t INVALID_SIZE = MAKE_RETURN_CODE(0xE0); + static const ReturnValue_t WRONG_TYPE = MAKE_RETURN_CODE(0xE1); + static const ReturnValue_t WRONG_PID = MAKE_RETURN_CODE(0xE2); + static const ReturnValue_t WRONG_LIMIT_ID = MAKE_RETURN_CODE(0xE3); + static const ReturnValue_t MONITOR_NOT_FOUND = MAKE_RETURN_CODE(0xEE); + + static const uint8_t REPORT_NONE = 0; + static const uint8_t REPORT_EVENTS_ONLY = 1; + static const uint8_t REPORT_REPORTS_ONLY = 2; + static const uint8_t REPORT_ALL = 3; + +// static const ReturnValue_t STILL_IN_LOW_WARNING = MAKE_RETURN_CODE(0x11); +// static const ReturnValue_t STILL_IN_LOW_LIMIT = MAKE_RETURN_CODE(0x12); +// static const ReturnValue_t STILL_IN_HIGH_WARNING = MAKE_RETURN_CODE(0x13); +// static const ReturnValue_t STILL_IN_HIGH_LIMIT = MAKE_RETURN_CODE(0x14); +// static const ReturnValue_t VARIABLE_IS_INVALID = MAKE_RETURN_CODE(0xE0); +// static const ReturnValue_t INVALID_SIZE = MAKE_RETURN_CODE(0xE1); +// static const ReturnValue_t INVALID_ID = MAKE_RETURN_CODE(0xE2); + virtual ReturnValue_t check() = 0; + virtual ReturnValue_t setLimits( uint8_t type, const uint8_t* data, uint32_t size) = 0; + virtual ReturnValue_t setChecking(uint8_t strategy) = 0; + virtual ReturnValue_t setToUnchecked() = 0; + virtual uint8_t getLimitType() const = 0; + virtual uint32_t getLimitId() const = 0; +// virtual ReturnValue_t setEventReporting(bool active) = 0; + virtual ~MonitoringIF() { + } +}; + + + +#endif /* MONITORINGIF_H_ */ diff --git a/monitoring/MonitoringMessage.cpp b/monitoring/MonitoringMessage.cpp index 77919bfe..9edf16d5 100644 --- a/monitoring/MonitoringMessage.cpp +++ b/monitoring/MonitoringMessage.cpp @@ -1,38 +1,38 @@ -#include -#include - -MonitoringMessage::~MonitoringMessage() { -} - -void MonitoringMessage::setLimitViolationReport(CommandMessage* message, - store_address_t storeId) { - setTypicalMessage(message, LIMIT_VIOLATION_REPORT, storeId); -} - -void MonitoringMessage::setTypicalMessage(CommandMessage* message, - Command_t type, store_address_t storeId) { - message->setCommand(type); - message->setParameter2(storeId.raw); -} - -store_address_t MonitoringMessage::getStoreId(const CommandMessage* message) { - store_address_t temp; - temp.raw = message->getParameter2(); - return temp; -} - -void MonitoringMessage::clear(CommandMessage* message) { - message->setCommand(CommandMessage::CMD_NONE); - switch (message->getCommand()) { - case MonitoringMessage::LIMIT_VIOLATION_REPORT: { - StorageManagerIF *ipcStore = objectManager->get( - objects::IPC_STORE); - if (ipcStore != NULL) { - ipcStore->deleteData(getStoreId(message)); - } - break; - } - default: - break; - } -} +#include "../monitoring/MonitoringMessage.h" +#include "../objectmanager/ObjectManagerIF.h" + +MonitoringMessage::~MonitoringMessage() { +} + +void MonitoringMessage::setLimitViolationReport(CommandMessage* message, + store_address_t storeId) { + setTypicalMessage(message, LIMIT_VIOLATION_REPORT, storeId); +} + +void MonitoringMessage::setTypicalMessage(CommandMessage* message, + Command_t type, store_address_t storeId) { + message->setCommand(type); + message->setParameter2(storeId.raw); +} + +store_address_t MonitoringMessage::getStoreId(const CommandMessage* message) { + store_address_t temp; + temp.raw = message->getParameter2(); + return temp; +} + +void MonitoringMessage::clear(CommandMessage* message) { + message->setCommand(CommandMessage::CMD_NONE); + switch (message->getCommand()) { + case MonitoringMessage::LIMIT_VIOLATION_REPORT: { + StorageManagerIF *ipcStore = objectManager->get( + objects::IPC_STORE); + if (ipcStore != NULL) { + ipcStore->deleteData(getStoreId(message)); + } + break; + } + default: + break; + } +} diff --git a/monitoring/MonitoringMessage.h b/monitoring/MonitoringMessage.h index 793e1fbf..55d3ea5c 100644 --- a/monitoring/MonitoringMessage.h +++ b/monitoring/MonitoringMessage.h @@ -1,21 +1,21 @@ -#ifndef MONITORINGMESSAGE_H_ -#define MONITORINGMESSAGE_H_ - -#include -#include - -class MonitoringMessage: public CommandMessage { -public: - static const uint8_t MESSAGE_ID = messagetypes::MONITORING; - //Object id could be useful, but we better manage that on service level (register potential reporters). - static const Command_t LIMIT_VIOLATION_REPORT = MAKE_COMMAND_ID(10); - virtual ~MonitoringMessage(); - static void setLimitViolationReport(CommandMessage* message, store_address_t storeId); - static void clear(CommandMessage* message); - static store_address_t getStoreId(const CommandMessage* message); - static void setTypicalMessage(CommandMessage* message, Command_t type, store_address_t storeId); - -}; - - -#endif /* MONITORINGMESSAGE_H_ */ +#ifndef MONITORINGMESSAGE_H_ +#define MONITORINGMESSAGE_H_ + +#include "../ipc/CommandMessage.h" +#include "../storagemanager/StorageManagerIF.h" + +class MonitoringMessage: public CommandMessage { +public: + static const uint8_t MESSAGE_ID = messagetypes::MONITORING; + //Object id could be useful, but we better manage that on service level (register potential reporters). + static const Command_t LIMIT_VIOLATION_REPORT = MAKE_COMMAND_ID(10); + virtual ~MonitoringMessage(); + static void setLimitViolationReport(CommandMessage* message, store_address_t storeId); + static void clear(CommandMessage* message); + static store_address_t getStoreId(const CommandMessage* message); + static void setTypicalMessage(CommandMessage* message, Command_t type, store_address_t storeId); + +}; + + +#endif /* MONITORINGMESSAGE_H_ */ diff --git a/monitoring/MonitoringMessageContent.h b/monitoring/MonitoringMessageContent.h index 7e1aca62..a0934c14 100644 --- a/monitoring/MonitoringMessageContent.h +++ b/monitoring/MonitoringMessageContent.h @@ -1,77 +1,77 @@ -#ifndef MONITORINGMESSAGECONTENT_H_ -#define MONITORINGMESSAGECONTENT_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Factory{ -void setStaticFrameworkObjectIds(); -} - -//PID(uint32_t), TYPE, LIMIT_ID, value,limitValue, previous, later, timestamp -template -class MonitoringReportContent: public SerialLinkedListAdapter { - friend void (Factory::setStaticFrameworkObjectIds)(); -public: - SerializeElement monitorId; - SerializeElement parameterId; - SerializeElement parameterValue; - SerializeElement limitValue; - SerializeElement oldState; - SerializeElement newState; - uint8_t rawTimestamp[TimeStamperIF::MISSION_TIMESTAMP_SIZE]; - SerializeElement> timestampSerializer; - TimeStamperIF* timeStamper; - MonitoringReportContent() : - SerialLinkedListAdapter( - LinkedElement::Iterator(¶meterId)), monitorId(0), parameterId( - 0), parameterValue(0), limitValue(0), oldState(0), newState( - 0), rawTimestamp( { 0 }), timestampSerializer(rawTimestamp, - sizeof(rawTimestamp)), timeStamper(NULL) { - setAllNext(); - } - MonitoringReportContent(uint32_t setPID, T value, T limitValue, - ReturnValue_t oldState, ReturnValue_t newState) : - SerialLinkedListAdapter( - LinkedElement::Iterator(¶meterId)), monitorId(0), parameterId( - setPID), parameterValue(value), limitValue(limitValue), oldState( - oldState), newState(newState), timestampSerializer(rawTimestamp, - sizeof(rawTimestamp)), timeStamper(NULL) { - setAllNext(); - if (checkAndSetStamper()) { - timeStamper->addTimeStamp(rawTimestamp, sizeof(rawTimestamp)); - } - } -private: - - static object_id_t timeStamperId; - void setAllNext() { - parameterId.setNext(¶meterValue); - parameterValue.setNext(&limitValue); - limitValue.setNext(&oldState); - oldState.setNext(&newState); - newState.setNext(×tampSerializer); - } - bool checkAndSetStamper() { - if (timeStamper == NULL) { - timeStamper = objectManager->get( timeStamperId ); - if ( timeStamper == NULL ) { - sif::error << "MonitoringReportContent::checkAndSetStamper: " - "Stamper not found!" << std::endl; - return false; - } - } - return true; - } -}; -template -object_id_t MonitoringReportContent::timeStamperId = 0; - -#endif /* MONITORINGMESSAGECONTENT_H_ */ +#ifndef MONITORINGMESSAGECONTENT_H_ +#define MONITORINGMESSAGECONTENT_H_ + +#include "../monitoring/HasMonitorsIF.h" +#include "../monitoring/MonitoringIF.h" +#include "../objectmanager/ObjectManagerIF.h" +#include "../serialize/SerialBufferAdapter.h" +#include "../serialize/SerialFixedArrayListAdapter.h" +#include "../serialize/SerializeElement.h" +#include "../serialize/SerialLinkedListAdapter.h" +#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../timemanager/TimeStamperIF.h" + +namespace Factory{ +void setStaticFrameworkObjectIds(); +} + +//PID(uint32_t), TYPE, LIMIT_ID, value,limitValue, previous, later, timestamp +template +class MonitoringReportContent: public SerialLinkedListAdapter { + friend void (Factory::setStaticFrameworkObjectIds)(); +public: + SerializeElement monitorId; + SerializeElement parameterId; + SerializeElement parameterValue; + SerializeElement limitValue; + SerializeElement oldState; + SerializeElement newState; + uint8_t rawTimestamp[TimeStamperIF::MISSION_TIMESTAMP_SIZE]; + SerializeElement> timestampSerializer; + TimeStamperIF* timeStamper; + MonitoringReportContent() : + SerialLinkedListAdapter( + LinkedElement::Iterator(¶meterId)), monitorId(0), parameterId( + 0), parameterValue(0), limitValue(0), oldState(0), newState( + 0), rawTimestamp( { 0 }), timestampSerializer(rawTimestamp, + sizeof(rawTimestamp)), timeStamper(NULL) { + setAllNext(); + } + MonitoringReportContent(uint32_t setPID, T value, T limitValue, + ReturnValue_t oldState, ReturnValue_t newState) : + SerialLinkedListAdapter( + LinkedElement::Iterator(¶meterId)), monitorId(0), parameterId( + setPID), parameterValue(value), limitValue(limitValue), oldState( + oldState), newState(newState), timestampSerializer(rawTimestamp, + sizeof(rawTimestamp)), timeStamper(NULL) { + setAllNext(); + if (checkAndSetStamper()) { + timeStamper->addTimeStamp(rawTimestamp, sizeof(rawTimestamp)); + } + } +private: + + static object_id_t timeStamperId; + void setAllNext() { + parameterId.setNext(¶meterValue); + parameterValue.setNext(&limitValue); + limitValue.setNext(&oldState); + oldState.setNext(&newState); + newState.setNext(×tampSerializer); + } + bool checkAndSetStamper() { + if (timeStamper == NULL) { + timeStamper = objectManager->get( timeStamperId ); + if ( timeStamper == NULL ) { + sif::error << "MonitoringReportContent::checkAndSetStamper: " + "Stamper not found!" << std::endl; + return false; + } + } + return true; + } +}; +template +object_id_t MonitoringReportContent::timeStamperId = 0; + +#endif /* MONITORINGMESSAGECONTENT_H_ */ diff --git a/monitoring/ReceivesMonitoringReportsIF.h b/monitoring/ReceivesMonitoringReportsIF.h index 42c365c1..16595f33 100644 --- a/monitoring/ReceivesMonitoringReportsIF.h +++ b/monitoring/ReceivesMonitoringReportsIF.h @@ -1,15 +1,15 @@ -#ifndef RECEIVESMONITORINGREPORTSIF_H_ -#define RECEIVESMONITORINGREPORTSIF_H_ - -#include - -class ReceivesMonitoringReportsIF { -public: - virtual MessageQueueId_t getCommandQueue() const = 0; - virtual ~ReceivesMonitoringReportsIF() { - } -}; - - - -#endif /* RECEIVESMONITORINGREPORTSIF_H_ */ +#ifndef RECEIVESMONITORINGREPORTSIF_H_ +#define RECEIVESMONITORINGREPORTSIF_H_ + +#include "../ipc/MessageQueueSenderIF.h" + +class ReceivesMonitoringReportsIF { +public: + virtual MessageQueueId_t getCommandQueue() const = 0; + virtual ~ReceivesMonitoringReportsIF() { + } +}; + + + +#endif /* RECEIVESMONITORINGREPORTSIF_H_ */ diff --git a/monitoring/TriplexMonitor.h b/monitoring/TriplexMonitor.h index 9a2e69c3..6f190361 100644 --- a/monitoring/TriplexMonitor.h +++ b/monitoring/TriplexMonitor.h @@ -1,155 +1,155 @@ -#ifndef FRAMEWORK_MONITORING_TRIPLEXMONITOR_H_ -#define FRAMEWORK_MONITORING_TRIPLEXMONITOR_H_ - -#include -#include -#include -#include -#include - - -//SHOULDDO: This is by far not perfect. Could be merged with new Monitor classes. But still, it's over-engineering. -template -class TriplexMonitor : public HasParametersIF { -public: - static const uint8_t INTERFACE_ID = CLASS_ID::TRIPLE_REDUNDACY_CHECK; - static const ReturnValue_t NOT_ENOUGH_SENSORS = MAKE_RETURN_CODE(1); - static const ReturnValue_t LOWEST_VALUE_OOL = MAKE_RETURN_CODE(2); - static const ReturnValue_t HIGHEST_VALUE_OOL = MAKE_RETURN_CODE(3); - static const ReturnValue_t BOTH_VALUES_OOL = MAKE_RETURN_CODE(4); - static const ReturnValue_t DUPLEX_OOL = MAKE_RETURN_CODE(5); - - static const uint8_t THREE = 3; - - TriplexMonitor(const uint32_t parameterIds[3], uint8_t domainId, const T initialLimit, - Event eventTripleCheck, Event eventDualCheck) : - values(parameterIds, &dataSet), limit(initialLimit), eventTripleCheck( - eventTripleCheck), eventDualCheck(eventDualCheck), healthTable( - NULL), domainId(domainId) { - - } - virtual ~TriplexMonitor() { - } - ReturnValue_t check() { - dataSet.read(); - //check health and validity - uint8_t availableIndex[2] = { 0, 0 }; - bool first = true; - uint8_t nAvailable = 0; - for (uint8_t count = 0; count < THREE; count++) { - if (values[count].isValid() && checkObjectHealthState(count)) { - if (first) { - availableIndex[0] = count; - first = false; - } else { - //Might be filled twice, but then it's not needed anyway. - availableIndex[1] = count; - } - nAvailable++; - } - } - ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; - switch (nAvailable) { - case 3: - result = doTriplexMonitoring(); - break; - case 2: - result = doDuplexMonitoring(availableIndex); - break; - default: - result = NOT_ENOUGH_SENSORS; - break; - } - dataSet.commit(); - return result; - } - ReturnValue_t initialize() { - healthTable = objectManager->get(objects::HEALTH_TABLE); - if (healthTable == NULL) { - return HasReturnvaluesIF::RETURN_FAILED; - } - return HasReturnvaluesIF::RETURN_OK; - } - - ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, - ParameterWrapper *parameterWrapper, - const ParameterWrapper *newValues, uint16_t startAtIndex) { - if (domainId != this->domainId) { - return INVALID_DOMAIN_ID; - } - switch (parameterId) { - case 0: - parameterWrapper->set(limit); - break; - default: - return INVALID_MATRIX_ID; - } - return HasReturnvaluesIF::RETURN_OK; - } - -protected: - DataSet dataSet; - PIDReaderList values; - T limit; - Event eventTripleCheck; - Event eventDualCheck; - HealthTableIF* healthTable; - uint8_t domainId; - ReturnValue_t doTriplexMonitoring() { - ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; - //Find middle value, by ordering indices - uint8_t index[3] = { 0, 1, 2 }; - if (values[index[0]].value > values[index[1]].value) { - std::swap(index[0], index[1]); - } - if (values[index[0]].value > values[index[2]].value) { - std::swap(index[0], index[2]); - } - if (values[index[1]].value > values[index[2]].value) { - std::swap(index[1], index[2]); - } - //Test if smallest value is out-of-limit. - if (values[index[0]] < (values[index[1]] - limit)) { - EventManagerIF::triggerEvent(getRefereneceObject(index[0]), - eventTripleCheck, LOWEST_VALUE_OOL, 0); - result = LOWEST_VALUE_OOL; - } - //Test if largest value is out-of-limit. - if (values[index[2]] > (values[index[1]] + limit)) { - EventManagerIF::triggerEvent(getRefereneceObject(index[2]), - eventTripleCheck, HIGHEST_VALUE_OOL, 0); - if (result == HasReturnvaluesIF::RETURN_OK) { - result = HIGHEST_VALUE_OOL; - } else { - result = BOTH_VALUES_OOL; - } - } - return result; - } - - ReturnValue_t doDuplexMonitoring(uint8_t index[2]) { - T mean = (values[index[0]] + values[index[1]]) / 2; - if (values[index[0]] > values[index[1]]) { - if (values[index[0]] > (mean + limit)) { - EventManagerIF::triggerEvent(getRefereneceObject(index[0]), - eventDualCheck, 0, 0); - EventManagerIF::triggerEvent(getRefereneceObject(index[1]), - eventDualCheck, 0, 0); - return DUPLEX_OOL; - } - } else { - if (values[index[1]] > (mean + limit)) { - EventManagerIF::triggerEvent(getRefereneceObject(index[0]), - eventDualCheck, 0, 0); - EventManagerIF::triggerEvent(getRefereneceObject(index[1]), - eventDualCheck, 0, 0); - return DUPLEX_OOL; - } - } - return HasReturnvaluesIF::RETURN_OK; - } - virtual bool checkObjectHealthState(uint8_t valueIndex) = 0; - virtual object_id_t getRefereneceObject(uint8_t valueIndex) = 0; -}; - -#endif /* FRAMEWORK_MONITORING_TRIPLEXMONITOR_H_ */ +#ifndef FRAMEWORK_MONITORING_TRIPLEXMONITOR_H_ +#define FRAMEWORK_MONITORING_TRIPLEXMONITOR_H_ + +#include "../datapool/DataSet.h" +#include "../datapool/PIDReaderList.h" +#include "../health/HealthTableIF.h" +#include "../parameters/HasParametersIF.h" +#include "../objectmanager/ObjectManagerIF.h" + + +//SHOULDDO: This is by far not perfect. Could be merged with new Monitor classes. But still, it's over-engineering. +template +class TriplexMonitor : public HasParametersIF { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::TRIPLE_REDUNDACY_CHECK; + static const ReturnValue_t NOT_ENOUGH_SENSORS = MAKE_RETURN_CODE(1); + static const ReturnValue_t LOWEST_VALUE_OOL = MAKE_RETURN_CODE(2); + static const ReturnValue_t HIGHEST_VALUE_OOL = MAKE_RETURN_CODE(3); + static const ReturnValue_t BOTH_VALUES_OOL = MAKE_RETURN_CODE(4); + static const ReturnValue_t DUPLEX_OOL = MAKE_RETURN_CODE(5); + + static const uint8_t THREE = 3; + + TriplexMonitor(const uint32_t parameterIds[3], uint8_t domainId, const T initialLimit, + Event eventTripleCheck, Event eventDualCheck) : + values(parameterIds, &dataSet), limit(initialLimit), eventTripleCheck( + eventTripleCheck), eventDualCheck(eventDualCheck), healthTable( + NULL), domainId(domainId) { + + } + virtual ~TriplexMonitor() { + } + ReturnValue_t check() { + dataSet.read(); + //check health and validity + uint8_t availableIndex[2] = { 0, 0 }; + bool first = true; + uint8_t nAvailable = 0; + for (uint8_t count = 0; count < THREE; count++) { + if (values[count].isValid() && checkObjectHealthState(count)) { + if (first) { + availableIndex[0] = count; + first = false; + } else { + //Might be filled twice, but then it's not needed anyway. + availableIndex[1] = count; + } + nAvailable++; + } + } + ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; + switch (nAvailable) { + case 3: + result = doTriplexMonitoring(); + break; + case 2: + result = doDuplexMonitoring(availableIndex); + break; + default: + result = NOT_ENOUGH_SENSORS; + break; + } + dataSet.commit(); + return result; + } + ReturnValue_t initialize() { + healthTable = objectManager->get(objects::HEALTH_TABLE); + if (healthTable == NULL) { + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; + } + + ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, + ParameterWrapper *parameterWrapper, + const ParameterWrapper *newValues, uint16_t startAtIndex) { + if (domainId != this->domainId) { + return INVALID_DOMAIN_ID; + } + switch (parameterId) { + case 0: + parameterWrapper->set(limit); + break; + default: + return INVALID_MATRIX_ID; + } + return HasReturnvaluesIF::RETURN_OK; + } + +protected: + DataSet dataSet; + PIDReaderList values; + T limit; + Event eventTripleCheck; + Event eventDualCheck; + HealthTableIF* healthTable; + uint8_t domainId; + ReturnValue_t doTriplexMonitoring() { + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + //Find middle value, by ordering indices + uint8_t index[3] = { 0, 1, 2 }; + if (values[index[0]].value > values[index[1]].value) { + std::swap(index[0], index[1]); + } + if (values[index[0]].value > values[index[2]].value) { + std::swap(index[0], index[2]); + } + if (values[index[1]].value > values[index[2]].value) { + std::swap(index[1], index[2]); + } + //Test if smallest value is out-of-limit. + if (values[index[0]] < (values[index[1]] - limit)) { + EventManagerIF::triggerEvent(getRefereneceObject(index[0]), + eventTripleCheck, LOWEST_VALUE_OOL, 0); + result = LOWEST_VALUE_OOL; + } + //Test if largest value is out-of-limit. + if (values[index[2]] > (values[index[1]] + limit)) { + EventManagerIF::triggerEvent(getRefereneceObject(index[2]), + eventTripleCheck, HIGHEST_VALUE_OOL, 0); + if (result == HasReturnvaluesIF::RETURN_OK) { + result = HIGHEST_VALUE_OOL; + } else { + result = BOTH_VALUES_OOL; + } + } + return result; + } + + ReturnValue_t doDuplexMonitoring(uint8_t index[2]) { + T mean = (values[index[0]] + values[index[1]]) / 2; + if (values[index[0]] > values[index[1]]) { + if (values[index[0]] > (mean + limit)) { + EventManagerIF::triggerEvent(getRefereneceObject(index[0]), + eventDualCheck, 0, 0); + EventManagerIF::triggerEvent(getRefereneceObject(index[1]), + eventDualCheck, 0, 0); + return DUPLEX_OOL; + } + } else { + if (values[index[1]] > (mean + limit)) { + EventManagerIF::triggerEvent(getRefereneceObject(index[0]), + eventDualCheck, 0, 0); + EventManagerIF::triggerEvent(getRefereneceObject(index[1]), + eventDualCheck, 0, 0); + return DUPLEX_OOL; + } + } + return HasReturnvaluesIF::RETURN_OK; + } + virtual bool checkObjectHealthState(uint8_t valueIndex) = 0; + virtual object_id_t getRefereneceObject(uint8_t valueIndex) = 0; +}; + +#endif /* FRAMEWORK_MONITORING_TRIPLEXMONITOR_H_ */ diff --git a/monitoring/TwoValueLimitMonitor.h b/monitoring/TwoValueLimitMonitor.h index c17ad433..ac0ef1ee 100644 --- a/monitoring/TwoValueLimitMonitor.h +++ b/monitoring/TwoValueLimitMonitor.h @@ -1,44 +1,44 @@ -#ifndef FRAMEWORK_MONITORING_TWOVALUELIMITMONITOR_H_ -#define FRAMEWORK_MONITORING_TWOVALUELIMITMONITOR_H_ - -#include - -template -class TwoValueLimitMonitor: public LimitMonitor { -public: - TwoValueLimitMonitor(object_id_t reporterId, uint8_t monitorId, - uint32_t lowParameterId, uint32_t highParameterId, - uint16_t confirmationLimit, T lowerLimit, T upperLimit, - Event belowLowEvent = MonitoringIF::VALUE_BELOW_LOW_LIMIT, - Event aboveHighEvent = MonitoringIF::VALUE_ABOVE_HIGH_LIMIT) : - LimitMonitor(reporterId, monitorId, lowParameterId, - confirmationLimit, lowerLimit, upperLimit, belowLowEvent, - aboveHighEvent), highValueParameterId(highParameterId) { - } - virtual ~TwoValueLimitMonitor() { - } - ReturnValue_t doCheck(T lowSample, T highSample) { - T crossedLimit; - ReturnValue_t currentState = this->checkSample(lowSample, &crossedLimit); - if (currentState != HasReturnvaluesIF::RETURN_OK) { - return this->monitorStateIs(currentState, lowSample, crossedLimit); - } - currentState = this->checkSample(highSample, &crossedLimit); - return this->monitorStateIs(currentState, highSample, crossedLimit); - } -protected: - virtual void sendTransitionReport(T parameterValue, T crossedLimit, - ReturnValue_t state) { - uint32_t usedParameterId = this->parameterId; - if (state == MonitoringIF::ABOVE_HIGH_LIMIT) { - usedParameterId = this->highValueParameterId; - } - MonitoringReportContent report(usedParameterId, parameterValue, - crossedLimit, this->oldState, state); - LimitViolationReporter::sendLimitViolationReport(&report); - } -private: - const uint32_t highValueParameterId; -}; - -#endif /* FRAMEWORK_MONITORING_TWOVALUELIMITMONITOR_H_ */ +#ifndef FRAMEWORK_MONITORING_TWOVALUELIMITMONITOR_H_ +#define FRAMEWORK_MONITORING_TWOVALUELIMITMONITOR_H_ + +#include "../monitoring/LimitMonitor.h" + +template +class TwoValueLimitMonitor: public LimitMonitor { +public: + TwoValueLimitMonitor(object_id_t reporterId, uint8_t monitorId, + uint32_t lowParameterId, uint32_t highParameterId, + uint16_t confirmationLimit, T lowerLimit, T upperLimit, + Event belowLowEvent = MonitoringIF::VALUE_BELOW_LOW_LIMIT, + Event aboveHighEvent = MonitoringIF::VALUE_ABOVE_HIGH_LIMIT) : + LimitMonitor(reporterId, monitorId, lowParameterId, + confirmationLimit, lowerLimit, upperLimit, belowLowEvent, + aboveHighEvent), highValueParameterId(highParameterId) { + } + virtual ~TwoValueLimitMonitor() { + } + ReturnValue_t doCheck(T lowSample, T highSample) { + T crossedLimit; + ReturnValue_t currentState = this->checkSample(lowSample, &crossedLimit); + if (currentState != HasReturnvaluesIF::RETURN_OK) { + return this->monitorStateIs(currentState, lowSample, crossedLimit); + } + currentState = this->checkSample(highSample, &crossedLimit); + return this->monitorStateIs(currentState, highSample, crossedLimit); + } +protected: + virtual void sendTransitionReport(T parameterValue, T crossedLimit, + ReturnValue_t state) { + uint32_t usedParameterId = this->parameterId; + if (state == MonitoringIF::ABOVE_HIGH_LIMIT) { + usedParameterId = this->highValueParameterId; + } + MonitoringReportContent report(usedParameterId, parameterValue, + crossedLimit, this->oldState, state); + LimitViolationReporter::sendLimitViolationReport(&report); + } +private: + const uint32_t highValueParameterId; +}; + +#endif /* FRAMEWORK_MONITORING_TWOVALUELIMITMONITOR_H_ */ diff --git a/objectmanager/ObjectManager.cpp b/objectmanager/ObjectManager.cpp index 1c54355a..13d67559 100644 --- a/objectmanager/ObjectManager.cpp +++ b/objectmanager/ObjectManager.cpp @@ -1,108 +1,108 @@ -#include -#include -#include -#include - -ObjectManager::ObjectManager( void (*setProducer)() ): - produceObjects(setProducer) { - //There's nothing special to do in the constructor. -} - - -ObjectManager::~ObjectManager() { - for (auto const& iter : objectList) { - delete iter.second; - } -} - -ReturnValue_t ObjectManager::insert( object_id_t id, SystemObjectIF* object) { - auto returnPair = objectList.emplace(id, object); - if (returnPair.second) { - // sif::debug << "ObjectManager::insert: Object " << std::hex - // << (int)id << std::dec << " inserted." << std::endl; - return this->RETURN_OK; - } else { - sif::error << "ObjectManager::insert: Object id " << std::hex - << (int)id << std::dec << " is already in use!" << std::endl; - sif::error << "Terminating program." << std::endl; - //This is very severe and difficult to handle in other places. - std::exit(INSERTION_FAILED); - } -} - -ReturnValue_t ObjectManager::remove( object_id_t id ) { - if ( this->getSystemObject(id) != NULL ) { - this->objectList.erase( id ); - //sif::debug << "ObjectManager::removeObject: Object " << std::hex - // << (int)id << std::dec << " removed." << std::endl; - return RETURN_OK; - } else { - sif::error << "ObjectManager::removeObject: Requested object " - << std::hex << (int)id << std::dec << " not found." << std::endl; - return NOT_FOUND; - } -} - - - -SystemObjectIF* ObjectManager::getSystemObject( object_id_t id ) { - auto listIter = this->objectList.find( id ); - if (listIter == this->objectList.end() ) { - return nullptr; - } else { - return listIter->second; - } -} - -ObjectManager::ObjectManager() : produceObjects(nullptr) { - -} - -void ObjectManager::initialize() { - if(produceObjects == nullptr) { - sif::error << "ObjectManager::initialize: Passed produceObjects " - "functions is nullptr!" << std::endl; - return; - } - this->produceObjects(); - ReturnValue_t result = RETURN_FAILED; - uint32_t errorCount = 0; - for (auto const& it : objectList) { - result = it.second->initialize(); - if ( result != RETURN_OK ) { - object_id_t var = it.first; - sif::error << "ObjectManager::initialize: Object 0x" << std::hex << - std::setw(8) << std::setfill('0')<< var << " failed to " - "initialize with code 0x" << result << std::dec << - std::setfill(' ') << std::endl; - errorCount++; - } - } - if (errorCount > 0) { - sif::error << "ObjectManager::ObjectManager: Counted " << errorCount - << " failed initializations." << std::endl; - } - //Init was successful. Now check successful interconnections. - errorCount = 0; - for (auto const& it : objectList) { - result = it.second->checkObjectConnections(); - if ( result != RETURN_OK ) { - sif::error << "ObjectManager::ObjectManager: Object " << std::hex << - (int) it.first << " connection check failed with code 0x" - << result << std::dec << std::endl; - errorCount++; - } - } - if (errorCount > 0) { - sif::error << "ObjectManager::ObjectManager: Counted " << errorCount - << " failed connection checks." << std::endl; - } -} - -void ObjectManager::printList() { - std::map::iterator it; - sif::debug << "ObjectManager: Object List contains:" << std::endl; - for (auto const& it : objectList) { - sif::debug << std::hex << it.first << " | " << it.second << std::endl; - } -} +#include "../objectmanager/ObjectManager.h" +#include "../serviceinterface/ServiceInterfaceStream.h" +#include +#include + +ObjectManager::ObjectManager( void (*setProducer)() ): + produceObjects(setProducer) { + //There's nothing special to do in the constructor. +} + + +ObjectManager::~ObjectManager() { + for (auto const& iter : objectList) { + delete iter.second; + } +} + +ReturnValue_t ObjectManager::insert( object_id_t id, SystemObjectIF* object) { + auto returnPair = objectList.emplace(id, object); + if (returnPair.second) { + // sif::debug << "ObjectManager::insert: Object " << std::hex + // << (int)id << std::dec << " inserted." << std::endl; + return this->RETURN_OK; + } else { + sif::error << "ObjectManager::insert: Object id " << std::hex + << (int)id << std::dec << " is already in use!" << std::endl; + sif::error << "Terminating program." << std::endl; + //This is very severe and difficult to handle in other places. + std::exit(INSERTION_FAILED); + } +} + +ReturnValue_t ObjectManager::remove( object_id_t id ) { + if ( this->getSystemObject(id) != NULL ) { + this->objectList.erase( id ); + //sif::debug << "ObjectManager::removeObject: Object " << std::hex + // << (int)id << std::dec << " removed." << std::endl; + return RETURN_OK; + } else { + sif::error << "ObjectManager::removeObject: Requested object " + << std::hex << (int)id << std::dec << " not found." << std::endl; + return NOT_FOUND; + } +} + + + +SystemObjectIF* ObjectManager::getSystemObject( object_id_t id ) { + auto listIter = this->objectList.find( id ); + if (listIter == this->objectList.end() ) { + return nullptr; + } else { + return listIter->second; + } +} + +ObjectManager::ObjectManager() : produceObjects(nullptr) { + +} + +void ObjectManager::initialize() { + if(produceObjects == nullptr) { + sif::error << "ObjectManager::initialize: Passed produceObjects " + "functions is nullptr!" << std::endl; + return; + } + this->produceObjects(); + ReturnValue_t result = RETURN_FAILED; + uint32_t errorCount = 0; + for (auto const& it : objectList) { + result = it.second->initialize(); + if ( result != RETURN_OK ) { + object_id_t var = it.first; + sif::error << "ObjectManager::initialize: Object 0x" << std::hex << + std::setw(8) << std::setfill('0')<< var << " failed to " + "initialize with code 0x" << result << std::dec << + std::setfill(' ') << std::endl; + errorCount++; + } + } + if (errorCount > 0) { + sif::error << "ObjectManager::ObjectManager: Counted " << errorCount + << " failed initializations." << std::endl; + } + //Init was successful. Now check successful interconnections. + errorCount = 0; + for (auto const& it : objectList) { + result = it.second->checkObjectConnections(); + if ( result != RETURN_OK ) { + sif::error << "ObjectManager::ObjectManager: Object " << std::hex << + (int) it.first << " connection check failed with code 0x" + << result << std::dec << std::endl; + errorCount++; + } + } + if (errorCount > 0) { + sif::error << "ObjectManager::ObjectManager: Counted " << errorCount + << " failed connection checks." << std::endl; + } +} + +void ObjectManager::printList() { + std::map::iterator it; + sif::debug << "ObjectManager: Object List contains:" << std::endl; + for (auto const& it : objectList) { + sif::debug << std::hex << it.first << " | " << it.second << std::endl; + } +} diff --git a/objectmanager/ObjectManager.h b/objectmanager/ObjectManager.h index 63451071..0bc525be 100644 --- a/objectmanager/ObjectManager.h +++ b/objectmanager/ObjectManager.h @@ -1,67 +1,67 @@ -/** - * @file ObjectManager.h - * @brief This file contains the implementation of the ObjectManager class - * @date 18.09.2012 - * @author Bastian Baetz - */ - -#ifndef OBJECTMANAGER_H_ -#define OBJECTMANAGER_H_ - -#include -#include -#include - -/** - * @brief This class implements a global object manager. - * @details This manager handles a list of available objects with system-wide - * relevance, such as device handlers, and TM/TC services. Objects can - * be inserted, removed and retrieved from the list. In addition, the - * class holds a so-called factory, that creates and inserts new - * objects if they are not already in the list. This feature automates - * most of the system initialization. - * As the system is static after initialization, no new objects are - * created or inserted into the list after startup. - * \ingroup system_objects - */ -class ObjectManager : public ObjectManagerIF { -private: - //comparison? - /** - * \brief This is the map of all initialized objects in the manager. - * \details Objects in the List must inherit the SystemObjectIF. - */ - std::map objectList; -protected: - SystemObjectIF* getSystemObject( object_id_t id ); - /** - * @brief This attribute is initialized with the factory function - * that creates new objects. - * @details The function is called if an object was requested with - * getSystemObject, but not found in objectList. - * @param The id of the object to be created. - * @return Returns a pointer to the newly created object or NULL. - */ - void (*produceObjects)(); -public: - /** - * @brief Apart from setting the producer function, nothing special - * happens in the constructor. - * @param setProducer A pointer to a factory function. - */ - ObjectManager( void (*produce)() ); - ObjectManager(); - /** - * @brief In the class's destructor, all objects in the list are deleted. - */ - //SHOULDDO: If, for some reason, deleting an ObjectManager instance is required, check if this works. - virtual ~ObjectManager( void ); - ReturnValue_t insert( object_id_t id, SystemObjectIF* object ); - ReturnValue_t remove( object_id_t id ); - void initialize(); - void printList(); -}; - - - -#endif /* OBJECTMANAGER_H_ */ +/** + * @file ObjectManager.h + * @brief This file contains the implementation of the ObjectManager class + * @date 18.09.2012 + * @author Bastian Baetz + */ + +#ifndef OBJECTMANAGER_H_ +#define OBJECTMANAGER_H_ + +#include "../objectmanager/ObjectManagerIF.h" +#include "../objectmanager/SystemObjectIF.h" +#include + +/** + * @brief This class implements a global object manager. + * @details This manager handles a list of available objects with system-wide + * relevance, such as device handlers, and TM/TC services. Objects can + * be inserted, removed and retrieved from the list. In addition, the + * class holds a so-called factory, that creates and inserts new + * objects if they are not already in the list. This feature automates + * most of the system initialization. + * As the system is static after initialization, no new objects are + * created or inserted into the list after startup. + * \ingroup system_objects + */ +class ObjectManager : public ObjectManagerIF { +private: + //comparison? + /** + * \brief This is the map of all initialized objects in the manager. + * \details Objects in the List must inherit the SystemObjectIF. + */ + std::map objectList; +protected: + SystemObjectIF* getSystemObject( object_id_t id ); + /** + * @brief This attribute is initialized with the factory function + * that creates new objects. + * @details The function is called if an object was requested with + * getSystemObject, but not found in objectList. + * @param The id of the object to be created. + * @return Returns a pointer to the newly created object or NULL. + */ + void (*produceObjects)(); +public: + /** + * @brief Apart from setting the producer function, nothing special + * happens in the constructor. + * @param setProducer A pointer to a factory function. + */ + ObjectManager( void (*produce)() ); + ObjectManager(); + /** + * @brief In the class's destructor, all objects in the list are deleted. + */ + //SHOULDDO: If, for some reason, deleting an ObjectManager instance is required, check if this works. + virtual ~ObjectManager( void ); + ReturnValue_t insert( object_id_t id, SystemObjectIF* object ); + ReturnValue_t remove( object_id_t id ); + void initialize(); + void printList(); +}; + + + +#endif /* OBJECTMANAGER_H_ */ diff --git a/objectmanager/ObjectManagerIF.h b/objectmanager/ObjectManagerIF.h index 90a1ce3b..5dfe8e4e 100644 --- a/objectmanager/ObjectManagerIF.h +++ b/objectmanager/ObjectManagerIF.h @@ -1,95 +1,95 @@ -#ifndef FRAMEWORK_OBJECTMANAGER_OBJECTMANAGERIF_H_ -#define FRAMEWORK_OBJECTMANAGER_OBJECTMANAGERIF_H_ - -#include -#include -#include -#include - -/** - * @brief This class provides an interface to the global object manager. - * @details This manager handles a list of available objects with system-wide - * relevance, such as device handlers, and TM/TC services. They can be - * inserted, removed and retrieved from the list. On getting the - * object, the call checks if the object implements the requested - * interface. - * @author Bastian Baetz - * @ingroup system_objects - */ -class ObjectManagerIF : public HasReturnvaluesIF { -public: - static constexpr uint8_t INTERFACE_ID = CLASS_ID::OBJECT_MANAGER_IF; - static constexpr ReturnValue_t INSERTION_FAILED = MAKE_RETURN_CODE( 1 ); - static constexpr ReturnValue_t NOT_FOUND = MAKE_RETURN_CODE( 2 ); - static constexpr ReturnValue_t CHILD_INIT_FAILED = MAKE_RETURN_CODE( 3 ); - static constexpr ReturnValue_t INTERNAL_ERR_REPORTER_UNINIT = MAKE_RETURN_CODE( 4 ); - -protected: - /** - * @brief This method is used to hide the template-based get call from - * a specific implementation. - * @details So, an implementation only has to implement this call. - * @param id The object id of the requested object. - * @return The method returns a pointer to an object implementing (at - * least) the SystemObjectIF, or NULL. - */ - virtual SystemObjectIF* getSystemObject( object_id_t id ) = 0; -public: - /** - * @brief This is the empty virtual destructor as requested by C++ interfaces. - */ - virtual ~ObjectManagerIF( void ) {}; - /** - * @brief With this call, new objects are inserted to the list. - * @details The implementation shall return an error code in case the - * object can't be added (e.g. the id is already in use). - * @param id The new id to be added to the list. - * @param object A pointer to the object to be added. - * @return @li INSERTION_FAILED in case the object could not be inserted. - * @li RETURN_OK in case the object was successfully inserted - */ - virtual ReturnValue_t insert( object_id_t id, SystemObjectIF* object ) = 0; - /** - * @brief With the get call, interfaces of an object can be retrieved in - * a type-safe manner. - * @details With the template-based call, the object list is searched with the - * getSystemObject method and afterwards it is checked, if the object - * implements the requested interface (with a dynamic_cast). - * @param id The object id of the requested object. - * @return The method returns a pointer to an object implementing the - * requested interface, or NULL. - */ - template T* get( object_id_t id ); - /** - * @brief With this call, an object is removed from the list. - * @param id The object id of the object to be removed. - * @return \li NOT_FOUND in case the object was not found - * \li RETURN_OK in case the object was successfully removed - */ - virtual ReturnValue_t remove( object_id_t id ) = 0; - virtual void initialize() = 0; - /** - * @brief This is a debug function, that prints the current content of the - * object list. - */ - virtual void printList() = 0; -}; - - -/** - * @brief This is the forward declaration of the global objectManager instance. - */ -extern ObjectManagerIF *objectManager; - -/*Documentation can be found in the class method declaration above.*/ -template -T* ObjectManagerIF::get( object_id_t id ) { - if(objectManager == nullptr) { - sif::error << "ObjectManagerIF: Global object manager has not " - "been initialized yet!" << std::endl; - } - SystemObjectIF* temp = this->getSystemObject(id); - return dynamic_cast(temp); -} - -#endif /* OBJECTMANAGERIF_H_ */ +#ifndef FRAMEWORK_OBJECTMANAGER_OBJECTMANAGERIF_H_ +#define FRAMEWORK_OBJECTMANAGER_OBJECTMANAGERIF_H_ + +#include "../objectmanager/frameworkObjects.h" +#include "../objectmanager/SystemObjectIF.h" +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../serviceinterface/ServiceInterfaceStream.h" + +/** + * @brief This class provides an interface to the global object manager. + * @details This manager handles a list of available objects with system-wide + * relevance, such as device handlers, and TM/TC services. They can be + * inserted, removed and retrieved from the list. On getting the + * object, the call checks if the object implements the requested + * interface. + * @author Bastian Baetz + * @ingroup system_objects + */ +class ObjectManagerIF : public HasReturnvaluesIF { +public: + static constexpr uint8_t INTERFACE_ID = CLASS_ID::OBJECT_MANAGER_IF; + static constexpr ReturnValue_t INSERTION_FAILED = MAKE_RETURN_CODE( 1 ); + static constexpr ReturnValue_t NOT_FOUND = MAKE_RETURN_CODE( 2 ); + static constexpr ReturnValue_t CHILD_INIT_FAILED = MAKE_RETURN_CODE( 3 ); + static constexpr ReturnValue_t INTERNAL_ERR_REPORTER_UNINIT = MAKE_RETURN_CODE( 4 ); + +protected: + /** + * @brief This method is used to hide the template-based get call from + * a specific implementation. + * @details So, an implementation only has to implement this call. + * @param id The object id of the requested object. + * @return The method returns a pointer to an object implementing (at + * least) the SystemObjectIF, or NULL. + */ + virtual SystemObjectIF* getSystemObject( object_id_t id ) = 0; +public: + /** + * @brief This is the empty virtual destructor as requested by C++ interfaces. + */ + virtual ~ObjectManagerIF( void ) {}; + /** + * @brief With this call, new objects are inserted to the list. + * @details The implementation shall return an error code in case the + * object can't be added (e.g. the id is already in use). + * @param id The new id to be added to the list. + * @param object A pointer to the object to be added. + * @return @li INSERTION_FAILED in case the object could not be inserted. + * @li RETURN_OK in case the object was successfully inserted + */ + virtual ReturnValue_t insert( object_id_t id, SystemObjectIF* object ) = 0; + /** + * @brief With the get call, interfaces of an object can be retrieved in + * a type-safe manner. + * @details With the template-based call, the object list is searched with the + * getSystemObject method and afterwards it is checked, if the object + * implements the requested interface (with a dynamic_cast). + * @param id The object id of the requested object. + * @return The method returns a pointer to an object implementing the + * requested interface, or NULL. + */ + template T* get( object_id_t id ); + /** + * @brief With this call, an object is removed from the list. + * @param id The object id of the object to be removed. + * @return \li NOT_FOUND in case the object was not found + * \li RETURN_OK in case the object was successfully removed + */ + virtual ReturnValue_t remove( object_id_t id ) = 0; + virtual void initialize() = 0; + /** + * @brief This is a debug function, that prints the current content of the + * object list. + */ + virtual void printList() = 0; +}; + + +/** + * @brief This is the forward declaration of the global objectManager instance. + */ +extern ObjectManagerIF *objectManager; + +/*Documentation can be found in the class method declaration above.*/ +template +T* ObjectManagerIF::get( object_id_t id ) { + if(objectManager == nullptr) { + sif::error << "ObjectManagerIF: Global object manager has not " + "been initialized yet!" << std::endl; + } + SystemObjectIF* temp = this->getSystemObject(id); + return dynamic_cast(temp); +} + +#endif /* OBJECTMANAGERIF_H_ */ diff --git a/objectmanager/SystemObject.cpp b/objectmanager/SystemObject.cpp index 85daaa35..e3eb22ee 100644 --- a/objectmanager/SystemObject.cpp +++ b/objectmanager/SystemObject.cpp @@ -1,37 +1,37 @@ -#include -#include -#include - -SystemObject::SystemObject(object_id_t setObjectId, bool doRegister) : - objectId(setObjectId), registered(doRegister) { - if (registered) { - objectManager->insert(objectId, this); - } -} - -SystemObject::~SystemObject() { - if (registered) { - objectManager->remove(objectId); - } -} - -object_id_t SystemObject::getObjectId() const { - return objectId; -} - -void SystemObject::triggerEvent(Event event, uint32_t parameter1, - uint32_t parameter2) { - EventManagerIF::triggerEvent(objectId, event, parameter1, parameter2); -} - -ReturnValue_t SystemObject::initialize() { - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t SystemObject::checkObjectConnections() { - return HasReturnvaluesIF::RETURN_OK; -} - -void SystemObject::forwardEvent(Event event, uint32_t parameter1, uint32_t parameter2) const { - EventManagerIF::triggerEvent(objectId, event, parameter1, parameter2); -} +#include "../events/EventManagerIF.h" +#include "../objectmanager/ObjectManager.h" +#include "../objectmanager/SystemObject.h" + +SystemObject::SystemObject(object_id_t setObjectId, bool doRegister) : + objectId(setObjectId), registered(doRegister) { + if (registered) { + objectManager->insert(objectId, this); + } +} + +SystemObject::~SystemObject() { + if (registered) { + objectManager->remove(objectId); + } +} + +object_id_t SystemObject::getObjectId() const { + return objectId; +} + +void SystemObject::triggerEvent(Event event, uint32_t parameter1, + uint32_t parameter2) { + EventManagerIF::triggerEvent(objectId, event, parameter1, parameter2); +} + +ReturnValue_t SystemObject::initialize() { + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t SystemObject::checkObjectConnections() { + return HasReturnvaluesIF::RETURN_OK; +} + +void SystemObject::forwardEvent(Event event, uint32_t parameter1, uint32_t parameter2) const { + EventManagerIF::triggerEvent(objectId, event, parameter1, parameter2); +} diff --git a/objectmanager/SystemObject.h b/objectmanager/SystemObject.h index 6a1b35b6..fa97aab4 100644 --- a/objectmanager/SystemObject.h +++ b/objectmanager/SystemObject.h @@ -1,61 +1,61 @@ -/** - * @file SystemObject.h - * @brief This file contains the definition of the SystemObject class. - * @date 07.11.2012 - * @author Ulrich Mohr - */ - -#ifndef SYSTEMOBJECT_H_ -#define SYSTEMOBJECT_H_ - -#include -#include -#include -#include - -/** - * @brief This class automates insertion into the ObjectManager and - * management of the object id. - * @details This class is more a base class, which shall be inherited by any - * class that is announced to ObjectManager. It automatically includes - * itself (and therefore the inheriting class) in the object manager's - * list. - * \ingroup system_objects - */ -class SystemObject: public SystemObjectIF { -private: - /** - * @brief This is the id the class instant got assigned. - */ - const object_id_t objectId; - const bool registered; -public: - - /** - * Helper function to send Event Messages to the Event Manager - * @param event - * @param parameter1 - * @param parameter2 - */ - virtual void triggerEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0); - - /** - * @brief The class's constructor. - * @details In the constructor, the object id is set and the class is - * inserted in the object manager. - * @param setObjectId The id the object shall have. - * @param doRegister Determines if the object is registered in the global object manager. - */ - SystemObject(object_id_t setObjectId, bool doRegister = true); - /** - * @brief On destruction, the object removes itself from the list. - */ - virtual ~SystemObject(); - object_id_t getObjectId() const; - virtual ReturnValue_t initialize(); - virtual ReturnValue_t checkObjectConnections(); - - virtual void forwardEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0) const; -}; - -#endif /* SYSTEMOBJECT_H_ */ +/** + * @file SystemObject.h + * @brief This file contains the definition of the SystemObject class. + * @date 07.11.2012 + * @author Ulrich Mohr + */ + +#ifndef SYSTEMOBJECT_H_ +#define SYSTEMOBJECT_H_ + +#include "../events/Event.h" +#include "../events/EventReportingProxyIF.h" +#include "../objectmanager/SystemObjectIF.h" +#include "../timemanager/Clock.h" + +/** + * @brief This class automates insertion into the ObjectManager and + * management of the object id. + * @details This class is more a base class, which shall be inherited by any + * class that is announced to ObjectManager. It automatically includes + * itself (and therefore the inheriting class) in the object manager's + * list. + * \ingroup system_objects + */ +class SystemObject: public SystemObjectIF { +private: + /** + * @brief This is the id the class instant got assigned. + */ + const object_id_t objectId; + const bool registered; +public: + + /** + * Helper function to send Event Messages to the Event Manager + * @param event + * @param parameter1 + * @param parameter2 + */ + virtual void triggerEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0); + + /** + * @brief The class's constructor. + * @details In the constructor, the object id is set and the class is + * inserted in the object manager. + * @param setObjectId The id the object shall have. + * @param doRegister Determines if the object is registered in the global object manager. + */ + SystemObject(object_id_t setObjectId, bool doRegister = true); + /** + * @brief On destruction, the object removes itself from the list. + */ + virtual ~SystemObject(); + object_id_t getObjectId() const; + virtual ReturnValue_t initialize(); + virtual ReturnValue_t checkObjectConnections(); + + virtual void forwardEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0) const; +}; + +#endif /* SYSTEMOBJECT_H_ */ diff --git a/objectmanager/SystemObjectIF.h b/objectmanager/SystemObjectIF.h index b7590509..54a2e866 100644 --- a/objectmanager/SystemObjectIF.h +++ b/objectmanager/SystemObjectIF.h @@ -1,62 +1,62 @@ -#ifndef FRAMEWORK_OBJECTMANAGER_SYSTEMOBJECTIF_H_ -#define FRAMEWORK_OBJECTMANAGER_SYSTEMOBJECTIF_H_ - -#include -#include -#include -/** - * @defgroup system_objects Software System Object Management - * The classes to create System Objects and classes to manage these are - * contained in this group. System Objects are software elements that can be - * controlled externally. They all have a unique object identifier. - */ - -/** - * This is the typedef for object identifiers. - * @ingroup system_objects - */ -typedef uint32_t object_id_t; - -/** - * This interface allows a class to be included in the object manager - * list. - * It does not provide any method definitions, still it is required to - * perform a type check with dynamic_cast. - * @author Bastian Baetz - * @ingroup system_objects - */ -class SystemObjectIF : public EventReportingProxyIF { -public: - /** - * This is a simple getter to return the object identifier. - * @return Returns the object id of this object. - */ - virtual object_id_t getObjectId() const = 0; - /** - * The empty virtual destructor as required for C++ interfaces. - */ - virtual ~SystemObjectIF() {} - /** - * @brief Initializes the object. - * There are initialization steps which can also be done in the constructor. - * However, there is no clean way to get a returnvalue from a constructor. - * Furthermore some components require other system object to be created - * which might not have been built yet. - * Therefore, a two-step initialization resolves this problem and prevents - * circular dependencies of not-fully initialized objects on start up. - * @return - @c RETURN_OK in case the initialization was successful - * - @c RETURN_FAILED otherwise - */ - virtual ReturnValue_t initialize() = 0; - /** - * @brief Checks if all object-object interconnections are satisfying - * for operation. - * Some objects need certain other objects (or a certain number), to be - * registered as children. These checks can be done in this method. - * @return - @c RETURN_OK in case the check was successful - * - @c any other code otherwise - */ - virtual ReturnValue_t checkObjectConnections() = 0; -}; - -#endif /* FRAMEWORK_OBJECTMANAGER_SYSTEMOBJECTIF_H_ */ +#ifndef FRAMEWORK_OBJECTMANAGER_SYSTEMOBJECTIF_H_ +#define FRAMEWORK_OBJECTMANAGER_SYSTEMOBJECTIF_H_ + +#include "../events/EventReportingProxyIF.h" +#include "../returnvalues/HasReturnvaluesIF.h" +#include +/** + * @defgroup system_objects Software System Object Management + * The classes to create System Objects and classes to manage these are + * contained in this group. System Objects are software elements that can be + * controlled externally. They all have a unique object identifier. + */ + +/** + * This is the typedef for object identifiers. + * @ingroup system_objects + */ +typedef uint32_t object_id_t; + +/** + * This interface allows a class to be included in the object manager + * list. + * It does not provide any method definitions, still it is required to + * perform a type check with dynamic_cast. + * @author Bastian Baetz + * @ingroup system_objects + */ +class SystemObjectIF : public EventReportingProxyIF { +public: + /** + * This is a simple getter to return the object identifier. + * @return Returns the object id of this object. + */ + virtual object_id_t getObjectId() const = 0; + /** + * The empty virtual destructor as required for C++ interfaces. + */ + virtual ~SystemObjectIF() {} + /** + * @brief Initializes the object. + * There are initialization steps which can also be done in the constructor. + * However, there is no clean way to get a returnvalue from a constructor. + * Furthermore some components require other system object to be created + * which might not have been built yet. + * Therefore, a two-step initialization resolves this problem and prevents + * circular dependencies of not-fully initialized objects on start up. + * @return - @c RETURN_OK in case the initialization was successful + * - @c RETURN_FAILED otherwise + */ + virtual ReturnValue_t initialize() = 0; + /** + * @brief Checks if all object-object interconnections are satisfying + * for operation. + * Some objects need certain other objects (or a certain number), to be + * registered as children. These checks can be done in this method. + * @return - @c RETURN_OK in case the check was successful + * - @c any other code otherwise + */ + virtual ReturnValue_t checkObjectConnections() = 0; +}; + +#endif /* FRAMEWORK_OBJECTMANAGER_SYSTEMOBJECTIF_H_ */ diff --git a/osal/FreeRTOS/BinSemaphUsingTask.cpp b/osal/FreeRTOS/BinSemaphUsingTask.cpp index d3351888..71c0aba9 100644 --- a/osal/FreeRTOS/BinSemaphUsingTask.cpp +++ b/osal/FreeRTOS/BinSemaphUsingTask.cpp @@ -1,91 +1,91 @@ -#include -#include -#include - -BinarySemaphoreUsingTask::BinarySemaphoreUsingTask() { - handle = TaskManagement::getCurrentTaskHandle(); - if(handle == nullptr) { - sif::error << "Could not retrieve task handle. Please ensure the" - "constructor was called inside a task." << std::endl; - } - xTaskNotifyGive(handle); -} - -BinarySemaphoreUsingTask::~BinarySemaphoreUsingTask() { - // Clear notification value on destruction. - xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite, nullptr); -} - -ReturnValue_t BinarySemaphoreUsingTask::acquire(uint32_t timeoutMs) { - TickType_t timeout = SemaphoreIF::POLLING; - if(timeoutMs == SemaphoreIF::BLOCKING) { - timeout = SemaphoreIF::BLOCKING; - } - else if(timeoutMs > SemaphoreIF::POLLING){ - timeout = pdMS_TO_TICKS(timeoutMs); - } - return acquireWithTickTimeout(timeout); -} - -ReturnValue_t BinarySemaphoreUsingTask::acquireWithTickTimeout( - TickType_t timeoutTicks) { - BaseType_t returncode = ulTaskNotifyTake(pdTRUE, timeoutTicks); - if (returncode == pdPASS) { - return HasReturnvaluesIF::RETURN_OK; - } - else { - return SemaphoreIF::SEMAPHORE_TIMEOUT; - } -} - -ReturnValue_t BinarySemaphoreUsingTask::release() { - return release(this->handle); -} - -ReturnValue_t BinarySemaphoreUsingTask::release( - TaskHandle_t taskHandle) { - if(getSemaphoreCounter(taskHandle) == 1) { - return SemaphoreIF::SEMAPHORE_NOT_OWNED; - } - BaseType_t returncode = xTaskNotifyGive(taskHandle); - if (returncode == pdPASS) { - return HasReturnvaluesIF::RETURN_OK; - } - else { - // This should never happen. - return HasReturnvaluesIF::RETURN_FAILED; - } -} - -TaskHandle_t BinarySemaphoreUsingTask::getTaskHandle() { - return handle; -} - -uint8_t BinarySemaphoreUsingTask::getSemaphoreCounter() const { - return getSemaphoreCounter(this->handle); -} - -uint8_t BinarySemaphoreUsingTask::getSemaphoreCounter( - TaskHandle_t taskHandle) { - uint32_t notificationValue; - xTaskNotifyAndQuery(taskHandle, 0, eNoAction, ¬ificationValue); - return notificationValue; -} - -// Be careful with the stack size here. This is called from an ISR! -ReturnValue_t BinarySemaphoreUsingTask::releaseFromISR( - TaskHandle_t taskHandle, BaseType_t * higherPriorityTaskWoken) { - if(getSemaphoreCounterFromISR(taskHandle, higherPriorityTaskWoken) == 1) { - return SemaphoreIF::SEMAPHORE_NOT_OWNED; - } - vTaskNotifyGiveFromISR(taskHandle, higherPriorityTaskWoken); - return HasReturnvaluesIF::RETURN_OK; -} - -uint8_t BinarySemaphoreUsingTask::getSemaphoreCounterFromISR( - TaskHandle_t taskHandle, BaseType_t* higherPriorityTaskWoken) { - uint32_t notificationValue = 0; - xTaskNotifyAndQueryFromISR(taskHandle, 0, eNoAction, ¬ificationValue, - higherPriorityTaskWoken); - return notificationValue; -} +#include "../../osal/FreeRTOS/BinSemaphUsingTask.h" +#include "../../osal/FreeRTOS/TaskManagement.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" + +BinarySemaphoreUsingTask::BinarySemaphoreUsingTask() { + handle = TaskManagement::getCurrentTaskHandle(); + if(handle == nullptr) { + sif::error << "Could not retrieve task handle. Please ensure the" + "constructor was called inside a task." << std::endl; + } + xTaskNotifyGive(handle); +} + +BinarySemaphoreUsingTask::~BinarySemaphoreUsingTask() { + // Clear notification value on destruction. + xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite, nullptr); +} + +ReturnValue_t BinarySemaphoreUsingTask::acquire(uint32_t timeoutMs) { + TickType_t timeout = SemaphoreIF::POLLING; + if(timeoutMs == SemaphoreIF::BLOCKING) { + timeout = SemaphoreIF::BLOCKING; + } + else if(timeoutMs > SemaphoreIF::POLLING){ + timeout = pdMS_TO_TICKS(timeoutMs); + } + return acquireWithTickTimeout(timeout); +} + +ReturnValue_t BinarySemaphoreUsingTask::acquireWithTickTimeout( + TickType_t timeoutTicks) { + BaseType_t returncode = ulTaskNotifyTake(pdTRUE, timeoutTicks); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } + else { + return SemaphoreIF::SEMAPHORE_TIMEOUT; + } +} + +ReturnValue_t BinarySemaphoreUsingTask::release() { + return release(this->handle); +} + +ReturnValue_t BinarySemaphoreUsingTask::release( + TaskHandle_t taskHandle) { + if(getSemaphoreCounter(taskHandle) == 1) { + return SemaphoreIF::SEMAPHORE_NOT_OWNED; + } + BaseType_t returncode = xTaskNotifyGive(taskHandle); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } + else { + // This should never happen. + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +TaskHandle_t BinarySemaphoreUsingTask::getTaskHandle() { + return handle; +} + +uint8_t BinarySemaphoreUsingTask::getSemaphoreCounter() const { + return getSemaphoreCounter(this->handle); +} + +uint8_t BinarySemaphoreUsingTask::getSemaphoreCounter( + TaskHandle_t taskHandle) { + uint32_t notificationValue; + xTaskNotifyAndQuery(taskHandle, 0, eNoAction, ¬ificationValue); + return notificationValue; +} + +// Be careful with the stack size here. This is called from an ISR! +ReturnValue_t BinarySemaphoreUsingTask::releaseFromISR( + TaskHandle_t taskHandle, BaseType_t * higherPriorityTaskWoken) { + if(getSemaphoreCounterFromISR(taskHandle, higherPriorityTaskWoken) == 1) { + return SemaphoreIF::SEMAPHORE_NOT_OWNED; + } + vTaskNotifyGiveFromISR(taskHandle, higherPriorityTaskWoken); + return HasReturnvaluesIF::RETURN_OK; +} + +uint8_t BinarySemaphoreUsingTask::getSemaphoreCounterFromISR( + TaskHandle_t taskHandle, BaseType_t* higherPriorityTaskWoken) { + uint32_t notificationValue = 0; + xTaskNotifyAndQueryFromISR(taskHandle, 0, eNoAction, ¬ificationValue, + higherPriorityTaskWoken); + return notificationValue; +} diff --git a/osal/FreeRTOS/BinSemaphUsingTask.h b/osal/FreeRTOS/BinSemaphUsingTask.h index 43772e5a..e6989970 100644 --- a/osal/FreeRTOS/BinSemaphUsingTask.h +++ b/osal/FreeRTOS/BinSemaphUsingTask.h @@ -1,75 +1,75 @@ -#ifndef FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ -#define FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ - -#include -#include - -#include -#include - -/** - * @brief Binary Semaphore implementation using the task notification value. - * The notification value should therefore not be used - * for other purposes. - * @details - * Additional information: https://www.freertos.org/RTOS-task-notifications.html - * and general semaphore documentation. - */ -class BinarySemaphoreUsingTask: public SemaphoreIF, - public HasReturnvaluesIF { -public: - static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; - - //! @brief Default ctor - BinarySemaphoreUsingTask(); - //! @brief Default dtor - virtual~ BinarySemaphoreUsingTask(); - - ReturnValue_t acquire(uint32_t timeoutMs = - SemaphoreIF::BLOCKING) override; - ReturnValue_t release() override; - uint8_t getSemaphoreCounter() const override; - static uint8_t getSemaphoreCounter(TaskHandle_t taskHandle); - static uint8_t getSemaphoreCounterFromISR(TaskHandle_t taskHandle, - BaseType_t* higherPriorityTaskWoken); - - /** - * Same as acquire() with timeout in FreeRTOS ticks. - * @param timeoutTicks - * @return - @c RETURN_OK on success - * - @c RETURN_FAILED on failure - */ - ReturnValue_t acquireWithTickTimeout(TickType_t timeoutTicks = - SemaphoreIF::BLOCKING); - - /** - * Get handle to the task related to the semaphore. - * @return - */ - TaskHandle_t getTaskHandle(); - - /** - * Wrapper function to give back semaphore from handle - * @param semaphore - * @return - @c RETURN_OK on success - * - @c RETURN_FAILED on failure - */ - static ReturnValue_t release(TaskHandle_t taskToNotify); - - /** - * Wrapper function to give back semaphore from handle when called from an ISR - * @param semaphore - * @param higherPriorityTaskWoken This will be set to pdPASS if a task with - * a higher priority was unblocked. A context switch should be requested - * from an ISR if this is the case (see TaskManagement functions) - * @return - @c RETURN_OK on success - * - @c RETURN_FAILED on failure - */ - static ReturnValue_t releaseFromISR(TaskHandle_t taskToNotify, - BaseType_t * higherPriorityTaskWoken); - -protected: - TaskHandle_t handle; -}; - -#endif /* FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ */ +#ifndef FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ +#define FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ + +#include "../../returnvalues/HasReturnvaluesIF.h" +#include "../../tasks/SemaphoreIF.h" + +#include +#include + +/** + * @brief Binary Semaphore implementation using the task notification value. + * The notification value should therefore not be used + * for other purposes. + * @details + * Additional information: https://www.freertos.org/RTOS-task-notifications.html + * and general semaphore documentation. + */ +class BinarySemaphoreUsingTask: public SemaphoreIF, + public HasReturnvaluesIF { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; + + //! @brief Default ctor + BinarySemaphoreUsingTask(); + //! @brief Default dtor + virtual~ BinarySemaphoreUsingTask(); + + ReturnValue_t acquire(uint32_t timeoutMs = + SemaphoreIF::BLOCKING) override; + ReturnValue_t release() override; + uint8_t getSemaphoreCounter() const override; + static uint8_t getSemaphoreCounter(TaskHandle_t taskHandle); + static uint8_t getSemaphoreCounterFromISR(TaskHandle_t taskHandle, + BaseType_t* higherPriorityTaskWoken); + + /** + * Same as acquire() with timeout in FreeRTOS ticks. + * @param timeoutTicks + * @return - @c RETURN_OK on success + * - @c RETURN_FAILED on failure + */ + ReturnValue_t acquireWithTickTimeout(TickType_t timeoutTicks = + SemaphoreIF::BLOCKING); + + /** + * Get handle to the task related to the semaphore. + * @return + */ + TaskHandle_t getTaskHandle(); + + /** + * Wrapper function to give back semaphore from handle + * @param semaphore + * @return - @c RETURN_OK on success + * - @c RETURN_FAILED on failure + */ + static ReturnValue_t release(TaskHandle_t taskToNotify); + + /** + * Wrapper function to give back semaphore from handle when called from an ISR + * @param semaphore + * @param higherPriorityTaskWoken This will be set to pdPASS if a task with + * a higher priority was unblocked. A context switch should be requested + * from an ISR if this is the case (see TaskManagement functions) + * @return - @c RETURN_OK on success + * - @c RETURN_FAILED on failure + */ + static ReturnValue_t releaseFromISR(TaskHandle_t taskToNotify, + BaseType_t * higherPriorityTaskWoken); + +protected: + TaskHandle_t handle; +}; + +#endif /* FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ */ diff --git a/osal/FreeRTOS/BinarySemaphore.cpp b/osal/FreeRTOS/BinarySemaphore.cpp index e6d2f92f..8e15b7a5 100644 --- a/osal/FreeRTOS/BinarySemaphore.cpp +++ b/osal/FreeRTOS/BinarySemaphore.cpp @@ -1,11 +1,11 @@ -#include -#include -#include +#include "../../osal/FreeRTOS/BinarySemaphore.h" +#include "../../osal/FreeRTOS/TaskManagement.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" BinarySemaphore::BinarySemaphore() { handle = xSemaphoreCreateBinary(); - if(handle == nullptr) { - sif::error << "Semaphore: Binary semaph creation failure" << std::endl; + if(handle == nullptr) { + sif::error << "Semaphore: Binary semaph creation failure" << std::endl; } // Initiated semaphore must be given before it can be taken. xSemaphoreGive(handle); @@ -84,7 +84,7 @@ uint8_t BinarySemaphore::getSemaphoreCounter() const { SemaphoreHandle_t BinarySemaphore::getSemaphore() { return handle; } - + // Be careful with the stack size here. This is called from an ISR! ReturnValue_t BinarySemaphore::releaseFromISR( @@ -100,4 +100,4 @@ ReturnValue_t BinarySemaphore::releaseFromISR( else { return SemaphoreIF::SEMAPHORE_NOT_OWNED; } -} +} diff --git a/osal/FreeRTOS/BinarySemaphore.h b/osal/FreeRTOS/BinarySemaphore.h index 2a372cd2..4cf270de 100644 --- a/osal/FreeRTOS/BinarySemaphore.h +++ b/osal/FreeRTOS/BinarySemaphore.h @@ -1,8 +1,8 @@ #ifndef FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ #define FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ -#include -#include +#include "../../returnvalues/HasReturnvaluesIF.h" +#include "../../tasks/SemaphoreIF.h" #include #include diff --git a/osal/FreeRTOS/Clock.cpp b/osal/FreeRTOS/Clock.cpp index ec07b662..48d7bc07 100644 --- a/osal/FreeRTOS/Clock.cpp +++ b/osal/FreeRTOS/Clock.cpp @@ -1,196 +1,196 @@ -#include -#include -#include - -#include -#include - -#include -#include - -//TODO sanitize input? -//TODO much of this code can be reused for tick-only systems - -uint16_t Clock::leapSeconds = 0; -MutexIF* Clock::timeMutex = nullptr; - -uint32_t Clock::getTicksPerSecond(void) { - return 1000; -} - -ReturnValue_t Clock::setClock(const TimeOfDay_t* time) { - - timeval time_timeval; - - ReturnValue_t result = convertTimeOfDayToTimeval(time, &time_timeval); - if (result != HasReturnvaluesIF::RETURN_OK){ - return result; - } - - return setClock(&time_timeval); -} - -ReturnValue_t Clock::setClock(const timeval* time) { - timeval uptime = getUptime(); - - timeval offset = *time - uptime; - - Timekeeper::instance()->setOffset(offset); - - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t Clock::getClock_timeval(timeval* time) { - timeval uptime = getUptime(); - - timeval offset = Timekeeper::instance()->getOffset(); - - *time = offset + uptime; - - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t Clock::getUptime(timeval* uptime) { - *uptime = getUptime(); - - return HasReturnvaluesIF::RETURN_OK; -} - -timeval Clock::getUptime() { - TickType_t ticksSinceStart = xTaskGetTickCount(); - return Timekeeper::ticksToTimeval(ticksSinceStart); -} - -ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) { - timeval uptime = getUptime(); - *uptimeMs = uptime.tv_sec * 1000 + uptime.tv_usec / 1000; - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t Clock::getClock_usecs(uint64_t* time) { - timeval time_timeval; - ReturnValue_t result = getClock_timeval(&time_timeval); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - *time = time_timeval.tv_sec * 1000000 + time_timeval.tv_usec; - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) { - timeval time_timeval; - ReturnValue_t result = getClock_timeval(&time_timeval); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - struct tm time_tm; - - gmtime_r(&time_timeval.tv_sec,&time_tm); - - time->year = time_tm.tm_year + 1900; - time->month = time_tm.tm_mon + 1; - time->day = time_tm.tm_mday; - - time->hour = time_tm.tm_hour; - time->minute = time_tm.tm_min; - time->second = time_tm.tm_sec; - - time->usecond = time_timeval.tv_usec; - - - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from, - timeval* to) { - struct tm time_tm; - - time_tm.tm_year = from->year - 1900; - time_tm.tm_mon = from->month - 1; - time_tm.tm_mday = from->day; - - time_tm.tm_hour = from->hour; - time_tm.tm_min = from->minute; - time_tm.tm_sec = from->second; - - time_t seconds = mktime(&time_tm); - - to->tv_sec = seconds; - to->tv_usec = from->usecond; - //Fails in 2038.. - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) { - *JD2000 = (time.tv_sec - 946728000. + time.tv_usec / 1000000.) / 24. - / 3600.; - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) { - //SHOULDDO: works not for dates in the past (might have less leap seconds) - if (timeMutex == nullptr) { - return HasReturnvaluesIF::RETURN_FAILED; - } - - uint16_t leapSeconds; - ReturnValue_t result = getLeapSeconds(&leapSeconds); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - timeval leapSeconds_timeval = { 0, 0 }; - leapSeconds_timeval.tv_sec = leapSeconds; - - //initial offset between UTC and TAI - timeval UTCtoTAI1972 = { 10, 0 }; - - timeval TAItoTT = { 32, 184000 }; - - *tt = utc + leapSeconds_timeval + UTCtoTAI1972 + TAItoTT; - - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) { - if (checkOrCreateClockMutex() != HasReturnvaluesIF::RETURN_OK) { - return HasReturnvaluesIF::RETURN_FAILED; - } - ReturnValue_t result = timeMutex->lockMutex(MutexIF::BLOCKING); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - leapSeconds = leapSeconds_; - - result = timeMutex->unlockMutex(); - return result; -} - -ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) { - if (timeMutex == NULL) { - return HasReturnvaluesIF::RETURN_FAILED; - } - ReturnValue_t result = timeMutex->lockMutex(MutexIF::BLOCKING); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - *leapSeconds_ = leapSeconds; - - result = timeMutex->unlockMutex(); - return result; -} - -ReturnValue_t Clock::checkOrCreateClockMutex() { - if (timeMutex == NULL) { - MutexFactory* mutexFactory = MutexFactory::instance(); - if (mutexFactory == NULL) { - return HasReturnvaluesIF::RETURN_FAILED; - } - timeMutex = mutexFactory->createMutex(); - if (timeMutex == NULL) { - return HasReturnvaluesIF::RETURN_FAILED; - } - } - return HasReturnvaluesIF::RETURN_OK; -} +#include "../../timemanager/Clock.h" +#include "../../globalfunctions/timevalOperations.h" +#include "../../osal/FreeRTOS/Timekeeper.h" + +#include +#include + +#include +#include + +//TODO sanitize input? +//TODO much of this code can be reused for tick-only systems + +uint16_t Clock::leapSeconds = 0; +MutexIF* Clock::timeMutex = nullptr; + +uint32_t Clock::getTicksPerSecond(void) { + return 1000; +} + +ReturnValue_t Clock::setClock(const TimeOfDay_t* time) { + + timeval time_timeval; + + ReturnValue_t result = convertTimeOfDayToTimeval(time, &time_timeval); + if (result != HasReturnvaluesIF::RETURN_OK){ + return result; + } + + return setClock(&time_timeval); +} + +ReturnValue_t Clock::setClock(const timeval* time) { + timeval uptime = getUptime(); + + timeval offset = *time - uptime; + + Timekeeper::instance()->setOffset(offset); + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Clock::getClock_timeval(timeval* time) { + timeval uptime = getUptime(); + + timeval offset = Timekeeper::instance()->getOffset(); + + *time = offset + uptime; + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Clock::getUptime(timeval* uptime) { + *uptime = getUptime(); + + return HasReturnvaluesIF::RETURN_OK; +} + +timeval Clock::getUptime() { + TickType_t ticksSinceStart = xTaskGetTickCount(); + return Timekeeper::ticksToTimeval(ticksSinceStart); +} + +ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) { + timeval uptime = getUptime(); + *uptimeMs = uptime.tv_sec * 1000 + uptime.tv_usec / 1000; + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Clock::getClock_usecs(uint64_t* time) { + timeval time_timeval; + ReturnValue_t result = getClock_timeval(&time_timeval); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + *time = time_timeval.tv_sec * 1000000 + time_timeval.tv_usec; + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) { + timeval time_timeval; + ReturnValue_t result = getClock_timeval(&time_timeval); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + struct tm time_tm; + + gmtime_r(&time_timeval.tv_sec,&time_tm); + + time->year = time_tm.tm_year + 1900; + time->month = time_tm.tm_mon + 1; + time->day = time_tm.tm_mday; + + time->hour = time_tm.tm_hour; + time->minute = time_tm.tm_min; + time->second = time_tm.tm_sec; + + time->usecond = time_timeval.tv_usec; + + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from, + timeval* to) { + struct tm time_tm; + + time_tm.tm_year = from->year - 1900; + time_tm.tm_mon = from->month - 1; + time_tm.tm_mday = from->day; + + time_tm.tm_hour = from->hour; + time_tm.tm_min = from->minute; + time_tm.tm_sec = from->second; + + time_t seconds = mktime(&time_tm); + + to->tv_sec = seconds; + to->tv_usec = from->usecond; + //Fails in 2038.. + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) { + *JD2000 = (time.tv_sec - 946728000. + time.tv_usec / 1000000.) / 24. + / 3600.; + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) { + //SHOULDDO: works not for dates in the past (might have less leap seconds) + if (timeMutex == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + + uint16_t leapSeconds; + ReturnValue_t result = getLeapSeconds(&leapSeconds); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + timeval leapSeconds_timeval = { 0, 0 }; + leapSeconds_timeval.tv_sec = leapSeconds; + + //initial offset between UTC and TAI + timeval UTCtoTAI1972 = { 10, 0 }; + + timeval TAItoTT = { 32, 184000 }; + + *tt = utc + leapSeconds_timeval + UTCtoTAI1972 + TAItoTT; + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) { + if (checkOrCreateClockMutex() != HasReturnvaluesIF::RETURN_OK) { + return HasReturnvaluesIF::RETURN_FAILED; + } + ReturnValue_t result = timeMutex->lockMutex(MutexIF::BLOCKING); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + leapSeconds = leapSeconds_; + + result = timeMutex->unlockMutex(); + return result; +} + +ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) { + if (timeMutex == NULL) { + return HasReturnvaluesIF::RETURN_FAILED; + } + ReturnValue_t result = timeMutex->lockMutex(MutexIF::BLOCKING); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + *leapSeconds_ = leapSeconds; + + result = timeMutex->unlockMutex(); + return result; +} + +ReturnValue_t Clock::checkOrCreateClockMutex() { + if (timeMutex == NULL) { + MutexFactory* mutexFactory = MutexFactory::instance(); + if (mutexFactory == NULL) { + return HasReturnvaluesIF::RETURN_FAILED; + } + timeMutex = mutexFactory->createMutex(); + if (timeMutex == NULL) { + return HasReturnvaluesIF::RETURN_FAILED; + } + } + return HasReturnvaluesIF::RETURN_OK; +} diff --git a/osal/FreeRTOS/CountingSemaphUsingTask.cpp b/osal/FreeRTOS/CountingSemaphUsingTask.cpp index f33c7a0d..333865c8 100644 --- a/osal/FreeRTOS/CountingSemaphUsingTask.cpp +++ b/osal/FreeRTOS/CountingSemaphUsingTask.cpp @@ -1,110 +1,110 @@ -#include -#include -#include - -CountingSemaphoreUsingTask::CountingSemaphoreUsingTask(const uint8_t maxCount, - uint8_t initCount): maxCount(maxCount) { - if(initCount > maxCount) { - sif::error << "CountingSemaphoreUsingTask: Max count bigger than " - "intial cout. Setting initial count to max count." << std::endl; - initCount = maxCount; - } - - handle = TaskManagement::getCurrentTaskHandle(); - if(handle == nullptr) { - sif::error << "CountingSemaphoreUsingTask: Could not retrieve task " - "handle. Please ensure the constructor was called inside a " - "task." << std::endl; - } - - uint32_t oldNotificationValue; - xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite, - &oldNotificationValue); - if(oldNotificationValue != 0) { - sif::warning << "CountinSemaphoreUsingTask: Semaphore initiated but " - "current notification value is not 0. Please ensure the " - "notification value is not used for other purposes!" << std::endl; - } - for(int i = 0; i < initCount; i++) { - xTaskNotifyGive(handle); - } -} - -CountingSemaphoreUsingTask::~CountingSemaphoreUsingTask() { - // Clear notification value on destruction. - // If this is not desired, don't call the destructor - // (or implement a boolean which disables the reset) - xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite, nullptr); -} - -ReturnValue_t CountingSemaphoreUsingTask::acquire(uint32_t timeoutMs) { - TickType_t timeout = SemaphoreIF::POLLING; - if(timeoutMs == SemaphoreIF::BLOCKING) { - timeout = SemaphoreIF::BLOCKING; - } - else if(timeoutMs > SemaphoreIF::POLLING){ - timeout = pdMS_TO_TICKS(timeoutMs); - } - return acquireWithTickTimeout(timeout); - -} - -ReturnValue_t CountingSemaphoreUsingTask::acquireWithTickTimeout( - TickType_t timeoutTicks) { - // Decrement notfication value without resetting it. - BaseType_t oldCount = ulTaskNotifyTake(pdFALSE, timeoutTicks); - if (getSemaphoreCounter() == oldCount - 1) { - return HasReturnvaluesIF::RETURN_OK; - } - else { - return SemaphoreIF::SEMAPHORE_TIMEOUT; - } -} - -ReturnValue_t CountingSemaphoreUsingTask::release() { - if(getSemaphoreCounter() == maxCount) { - return SemaphoreIF::SEMAPHORE_NOT_OWNED; - } - return release(handle); -} - -ReturnValue_t CountingSemaphoreUsingTask::release( - TaskHandle_t taskToNotify) { - BaseType_t returncode = xTaskNotifyGive(taskToNotify); - if (returncode == pdPASS) { - return HasReturnvaluesIF::RETURN_OK; - } - else { - // This should never happen. - return HasReturnvaluesIF::RETURN_FAILED; - } -} - - -uint8_t CountingSemaphoreUsingTask::getSemaphoreCounter() const { - uint32_t notificationValue = 0; - xTaskNotifyAndQuery(handle, 0, eNoAction, ¬ificationValue); - return notificationValue; -} - -TaskHandle_t CountingSemaphoreUsingTask::getTaskHandle() { - return handle; -} - -ReturnValue_t CountingSemaphoreUsingTask::releaseFromISR( - TaskHandle_t taskToNotify, BaseType_t* higherPriorityTaskWoken) { - vTaskNotifyGiveFromISR(taskToNotify, higherPriorityTaskWoken); - return HasReturnvaluesIF::RETURN_OK; -} - -uint8_t CountingSemaphoreUsingTask::getSemaphoreCounterFromISR( - TaskHandle_t task, BaseType_t* higherPriorityTaskWoken) { - uint32_t notificationValue; - xTaskNotifyAndQueryFromISR(task, 0, eNoAction, ¬ificationValue, - higherPriorityTaskWoken); - return notificationValue; -} - -uint8_t CountingSemaphoreUsingTask::getMaxCount() const { - return maxCount; -} +#include "../../osal/FreeRTOS/CountingSemaphUsingTask.h" +#include "../../osal/FreeRTOS/TaskManagement.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" + +CountingSemaphoreUsingTask::CountingSemaphoreUsingTask(const uint8_t maxCount, + uint8_t initCount): maxCount(maxCount) { + if(initCount > maxCount) { + sif::error << "CountingSemaphoreUsingTask: Max count bigger than " + "intial cout. Setting initial count to max count." << std::endl; + initCount = maxCount; + } + + handle = TaskManagement::getCurrentTaskHandle(); + if(handle == nullptr) { + sif::error << "CountingSemaphoreUsingTask: Could not retrieve task " + "handle. Please ensure the constructor was called inside a " + "task." << std::endl; + } + + uint32_t oldNotificationValue; + xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite, + &oldNotificationValue); + if(oldNotificationValue != 0) { + sif::warning << "CountinSemaphoreUsingTask: Semaphore initiated but " + "current notification value is not 0. Please ensure the " + "notification value is not used for other purposes!" << std::endl; + } + for(int i = 0; i < initCount; i++) { + xTaskNotifyGive(handle); + } +} + +CountingSemaphoreUsingTask::~CountingSemaphoreUsingTask() { + // Clear notification value on destruction. + // If this is not desired, don't call the destructor + // (or implement a boolean which disables the reset) + xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite, nullptr); +} + +ReturnValue_t CountingSemaphoreUsingTask::acquire(uint32_t timeoutMs) { + TickType_t timeout = SemaphoreIF::POLLING; + if(timeoutMs == SemaphoreIF::BLOCKING) { + timeout = SemaphoreIF::BLOCKING; + } + else if(timeoutMs > SemaphoreIF::POLLING){ + timeout = pdMS_TO_TICKS(timeoutMs); + } + return acquireWithTickTimeout(timeout); + +} + +ReturnValue_t CountingSemaphoreUsingTask::acquireWithTickTimeout( + TickType_t timeoutTicks) { + // Decrement notfication value without resetting it. + BaseType_t oldCount = ulTaskNotifyTake(pdFALSE, timeoutTicks); + if (getSemaphoreCounter() == oldCount - 1) { + return HasReturnvaluesIF::RETURN_OK; + } + else { + return SemaphoreIF::SEMAPHORE_TIMEOUT; + } +} + +ReturnValue_t CountingSemaphoreUsingTask::release() { + if(getSemaphoreCounter() == maxCount) { + return SemaphoreIF::SEMAPHORE_NOT_OWNED; + } + return release(handle); +} + +ReturnValue_t CountingSemaphoreUsingTask::release( + TaskHandle_t taskToNotify) { + BaseType_t returncode = xTaskNotifyGive(taskToNotify); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } + else { + // This should never happen. + return HasReturnvaluesIF::RETURN_FAILED; + } +} + + +uint8_t CountingSemaphoreUsingTask::getSemaphoreCounter() const { + uint32_t notificationValue = 0; + xTaskNotifyAndQuery(handle, 0, eNoAction, ¬ificationValue); + return notificationValue; +} + +TaskHandle_t CountingSemaphoreUsingTask::getTaskHandle() { + return handle; +} + +ReturnValue_t CountingSemaphoreUsingTask::releaseFromISR( + TaskHandle_t taskToNotify, BaseType_t* higherPriorityTaskWoken) { + vTaskNotifyGiveFromISR(taskToNotify, higherPriorityTaskWoken); + return HasReturnvaluesIF::RETURN_OK; +} + +uint8_t CountingSemaphoreUsingTask::getSemaphoreCounterFromISR( + TaskHandle_t task, BaseType_t* higherPriorityTaskWoken) { + uint32_t notificationValue; + xTaskNotifyAndQueryFromISR(task, 0, eNoAction, ¬ificationValue, + higherPriorityTaskWoken); + return notificationValue; +} + +uint8_t CountingSemaphoreUsingTask::getMaxCount() const { + return maxCount; +} diff --git a/osal/FreeRTOS/CountingSemaphUsingTask.h b/osal/FreeRTOS/CountingSemaphUsingTask.h index f1d82c1d..801e3430 100644 --- a/osal/FreeRTOS/CountingSemaphUsingTask.h +++ b/osal/FreeRTOS/CountingSemaphUsingTask.h @@ -1,100 +1,100 @@ -#ifndef FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_ -#define FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_ - -#include -#include - -extern "C" { -#include -#include -} - -/** - * @brief Couting Semaphore implementation which uses the notification value - * of the task. The notification value should therefore not be used - * for other purposes. - * @details - * Additional information: https://www.freertos.org/RTOS-task-notifications.html - * and general semaphore documentation. - */ -class CountingSemaphoreUsingTask: public SemaphoreIF { -public: - CountingSemaphoreUsingTask(const uint8_t maxCount, uint8_t initCount); - virtual ~CountingSemaphoreUsingTask(); - - /** - * Acquire the counting semaphore. - * If no semaphores are available, the task will be blocked - * for a maximum of #timeoutMs or until one is given back, - * for example by an ISR or another task. - * @param timeoutMs - * @return -@c RETURN_OK on success - * -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout - */ - ReturnValue_t acquire(uint32_t timeoutMs = SemaphoreIF::BLOCKING) override; - - /** - * Release a semaphore, increasing the number of available counting - * semaphores up to the #maxCount value. - * @return -@c RETURN_OK on success - * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if #maxCount semaphores are - * already available. - */ - ReturnValue_t release() override; - - uint8_t getSemaphoreCounter() const override; - /** - * Get the semaphore counter from an ISR. - * @param task - * @param higherPriorityTaskWoken This will be set to pdPASS if a task with - * a higher priority was unblocked. A context switch should be requested - * from an ISR if this is the case (see TaskManagement functions) - * @return - */ - static uint8_t getSemaphoreCounterFromISR(TaskHandle_t task, - BaseType_t* higherPriorityTaskWoken); - - /** - * Acquire with a timeout value in ticks - * @param timeoutTicks - * @return -@c RETURN_OK on success - * -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout - */ - ReturnValue_t acquireWithTickTimeout( - TickType_t timeoutTicks = SemaphoreIF::BLOCKING); - - /** - * Get handle to the task related to the semaphore. - * @return - */ - TaskHandle_t getTaskHandle(); - - /** - * Release semaphore of task by supplying task handle - * @param taskToNotify - * @return -@c RETURN_OK on success - * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if #maxCount semaphores are - * already available. - */ - static ReturnValue_t release(TaskHandle_t taskToNotify); - /** - * Release seamphore of a task from an ISR. - * @param taskToNotify - * @param higherPriorityTaskWoken This will be set to pdPASS if a task with - * a higher priority was unblocked. A context switch should be requested - * from an ISR if this is the case (see TaskManagement functions) - * @return -@c RETURN_OK on success - * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if #maxCount semaphores are - * already available. - */ - static ReturnValue_t releaseFromISR(TaskHandle_t taskToNotify, - BaseType_t* higherPriorityTaskWoken); - - uint8_t getMaxCount() const; - -private: - TaskHandle_t handle; - const uint8_t maxCount; -}; - -#endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_ */ +#ifndef FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_ +#define FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_ + +#include "../../osal/FreeRTOS/CountingSemaphUsingTask.h" +#include "../../tasks/SemaphoreIF.h" + +extern "C" { +#include +#include +} + +/** + * @brief Couting Semaphore implementation which uses the notification value + * of the task. The notification value should therefore not be used + * for other purposes. + * @details + * Additional information: https://www.freertos.org/RTOS-task-notifications.html + * and general semaphore documentation. + */ +class CountingSemaphoreUsingTask: public SemaphoreIF { +public: + CountingSemaphoreUsingTask(const uint8_t maxCount, uint8_t initCount); + virtual ~CountingSemaphoreUsingTask(); + + /** + * Acquire the counting semaphore. + * If no semaphores are available, the task will be blocked + * for a maximum of #timeoutMs or until one is given back, + * for example by an ISR or another task. + * @param timeoutMs + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout + */ + ReturnValue_t acquire(uint32_t timeoutMs = SemaphoreIF::BLOCKING) override; + + /** + * Release a semaphore, increasing the number of available counting + * semaphores up to the #maxCount value. + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if #maxCount semaphores are + * already available. + */ + ReturnValue_t release() override; + + uint8_t getSemaphoreCounter() const override; + /** + * Get the semaphore counter from an ISR. + * @param task + * @param higherPriorityTaskWoken This will be set to pdPASS if a task with + * a higher priority was unblocked. A context switch should be requested + * from an ISR if this is the case (see TaskManagement functions) + * @return + */ + static uint8_t getSemaphoreCounterFromISR(TaskHandle_t task, + BaseType_t* higherPriorityTaskWoken); + + /** + * Acquire with a timeout value in ticks + * @param timeoutTicks + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout + */ + ReturnValue_t acquireWithTickTimeout( + TickType_t timeoutTicks = SemaphoreIF::BLOCKING); + + /** + * Get handle to the task related to the semaphore. + * @return + */ + TaskHandle_t getTaskHandle(); + + /** + * Release semaphore of task by supplying task handle + * @param taskToNotify + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if #maxCount semaphores are + * already available. + */ + static ReturnValue_t release(TaskHandle_t taskToNotify); + /** + * Release seamphore of a task from an ISR. + * @param taskToNotify + * @param higherPriorityTaskWoken This will be set to pdPASS if a task with + * a higher priority was unblocked. A context switch should be requested + * from an ISR if this is the case (see TaskManagement functions) + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if #maxCount semaphores are + * already available. + */ + static ReturnValue_t releaseFromISR(TaskHandle_t taskToNotify, + BaseType_t* higherPriorityTaskWoken); + + uint8_t getMaxCount() const; + +private: + TaskHandle_t handle; + const uint8_t maxCount; +}; + +#endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_ */ diff --git a/osal/FreeRTOS/CountingSemaphore.cpp b/osal/FreeRTOS/CountingSemaphore.cpp index 957f6a31..0b218e54 100644 --- a/osal/FreeRTOS/CountingSemaphore.cpp +++ b/osal/FreeRTOS/CountingSemaphore.cpp @@ -1,43 +1,43 @@ -#include -#include -#include - -#include - -// Make sure #define configUSE_COUNTING_SEMAPHORES 1 is set in -// free FreeRTOSConfig.h file. -CountingSemaphore::CountingSemaphore(const uint8_t maxCount, uint8_t initCount): - maxCount(maxCount), initCount(initCount) { - if(initCount > maxCount) { - sif::error << "CountingSemaphoreUsingTask: Max count bigger than " - "intial cout. Setting initial count to max count." << std::endl; - initCount = maxCount; - } - - handle = xSemaphoreCreateCounting(maxCount, initCount); - if(handle == nullptr) { - sif::error << "CountingSemaphore: Creation failure" << std::endl; - } -} - -CountingSemaphore::CountingSemaphore(CountingSemaphore&& other): - maxCount(other.maxCount), initCount(other.initCount) { - handle = xSemaphoreCreateCounting(other.maxCount, other.initCount); - if(handle == nullptr) { - sif::error << "CountingSemaphore: Creation failure" << std::endl; - } -} - -CountingSemaphore& CountingSemaphore::operator =( - CountingSemaphore&& other) { - handle = xSemaphoreCreateCounting(other.maxCount, other.initCount); - if(handle == nullptr) { - sif::error << "CountingSemaphore: Creation failure" << std::endl; - } - return * this; -} - - -uint8_t CountingSemaphore::getMaxCount() const { - return maxCount; -} +#include "../../osal/FreeRTOS/CountingSemaphore.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "../../osal/FreeRTOS/TaskManagement.h" + +#include + +// Make sure #define configUSE_COUNTING_SEMAPHORES 1 is set in +// free FreeRTOSConfig.h file. +CountingSemaphore::CountingSemaphore(const uint8_t maxCount, uint8_t initCount): + maxCount(maxCount), initCount(initCount) { + if(initCount > maxCount) { + sif::error << "CountingSemaphoreUsingTask: Max count bigger than " + "intial cout. Setting initial count to max count." << std::endl; + initCount = maxCount; + } + + handle = xSemaphoreCreateCounting(maxCount, initCount); + if(handle == nullptr) { + sif::error << "CountingSemaphore: Creation failure" << std::endl; + } +} + +CountingSemaphore::CountingSemaphore(CountingSemaphore&& other): + maxCount(other.maxCount), initCount(other.initCount) { + handle = xSemaphoreCreateCounting(other.maxCount, other.initCount); + if(handle == nullptr) { + sif::error << "CountingSemaphore: Creation failure" << std::endl; + } +} + +CountingSemaphore& CountingSemaphore::operator =( + CountingSemaphore&& other) { + handle = xSemaphoreCreateCounting(other.maxCount, other.initCount); + if(handle == nullptr) { + sif::error << "CountingSemaphore: Creation failure" << std::endl; + } + return * this; +} + + +uint8_t CountingSemaphore::getMaxCount() const { + return maxCount; +} diff --git a/osal/FreeRTOS/CountingSemaphore.h b/osal/FreeRTOS/CountingSemaphore.h index dca3ab0e..9432ed81 100644 --- a/osal/FreeRTOS/CountingSemaphore.h +++ b/osal/FreeRTOS/CountingSemaphore.h @@ -1,34 +1,34 @@ -#ifndef FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ -#define FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ -#include - -/** - * @brief Counting semaphores, which can be acquire more than once. - * @details - * See: https://www.freertos.org/CreateCounting.html - * API of counting semaphores is almost identical to binary semaphores, - * so we just inherit from binary semaphore and provide the respective - * constructors. - */ -class CountingSemaphore: public BinarySemaphore { -public: - CountingSemaphore(const uint8_t maxCount, uint8_t initCount); - //! @brief Copy ctor, disabled - CountingSemaphore(const CountingSemaphore&) = delete; - //! @brief Copy assignment, disabled - CountingSemaphore& operator=(const CountingSemaphore&) = delete; - //! @brief Move ctor - CountingSemaphore (CountingSemaphore &&); - //! @brief Move assignment - CountingSemaphore & operator=(CountingSemaphore &&); - - /* Same API as binary semaphore otherwise. acquire() can be called - * until there are not semaphores left and release() can be called - * until maxCount is reached. */ - uint8_t getMaxCount() const; -private: - const uint8_t maxCount; - uint8_t initCount = 0; -}; - -#endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ */ +#ifndef FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ +#define FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ +#include "../../osal/FreeRTOS/BinarySemaphore.h" + +/** + * @brief Counting semaphores, which can be acquire more than once. + * @details + * See: https://www.freertos.org/CreateCounting.html + * API of counting semaphores is almost identical to binary semaphores, + * so we just inherit from binary semaphore and provide the respective + * constructors. + */ +class CountingSemaphore: public BinarySemaphore { +public: + CountingSemaphore(const uint8_t maxCount, uint8_t initCount); + //! @brief Copy ctor, disabled + CountingSemaphore(const CountingSemaphore&) = delete; + //! @brief Copy assignment, disabled + CountingSemaphore& operator=(const CountingSemaphore&) = delete; + //! @brief Move ctor + CountingSemaphore (CountingSemaphore &&); + //! @brief Move assignment + CountingSemaphore & operator=(CountingSemaphore &&); + + /* Same API as binary semaphore otherwise. acquire() can be called + * until there are not semaphores left and release() can be called + * until maxCount is reached. */ + uint8_t getMaxCount() const; +private: + const uint8_t maxCount; + uint8_t initCount = 0; +}; + +#endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ */ diff --git a/osal/FreeRTOS/FixedTimeslotTask.cpp b/osal/FreeRTOS/FixedTimeslotTask.cpp index 2a7bff9c..769f31e1 100644 --- a/osal/FreeRTOS/FixedTimeslotTask.cpp +++ b/osal/FreeRTOS/FixedTimeslotTask.cpp @@ -1,162 +1,162 @@ -#include "FixedTimeslotTask.h" - -#include - -uint32_t FixedTimeslotTask::deadlineMissedCount = 0; -const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = configMINIMAL_STACK_SIZE; - -FixedTimeslotTask::FixedTimeslotTask(TaskName name, TaskPriority setPriority, - TaskStackSize setStack, TaskPeriod overallPeriod, - void (*setDeadlineMissedFunc)()) : - started(false), handle(NULL), pst(overallPeriod * 1000) { - configSTACK_DEPTH_TYPE stackSize = setStack / sizeof(configSTACK_DEPTH_TYPE); - xTaskCreate(taskEntryPoint, name, stackSize, this, setPriority, &handle); - // All additional attributes are applied to the object. - this->deadlineMissedFunc = setDeadlineMissedFunc; -} - -FixedTimeslotTask::~FixedTimeslotTask() { -} - -void FixedTimeslotTask::taskEntryPoint(void* argument) { - - // The argument is re-interpreted as FixedTimeslotTask. The Task object is - // global, so it is found from any place. - FixedTimeslotTask *originalTask(reinterpret_cast(argument)); - /* Task should not start until explicitly requested, - * but in FreeRTOS, tasks start as soon as they are created if the scheduler - * is running but not if the scheduler is not running. - * To be able to accommodate both cases we check a member which is set in - * #startTask(). If it is not set and we get here, the scheduler was started - * before #startTask() was called and we need to suspend if it is set, - * the scheduler was not running before #startTask() was called and we - * can continue */ - - if (not originalTask->started) { - vTaskSuspend(NULL); - } - - originalTask->taskFunctionality(); - sif::debug << "Polling task " << originalTask->handle - << " returned from taskFunctionality." << std::endl; -} - -void FixedTimeslotTask::missedDeadlineCounter() { - FixedTimeslotTask::deadlineMissedCount++; - if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) { - sif::error << "PST missed " << FixedTimeslotTask::deadlineMissedCount - << " deadlines." << std::endl; - } -} - -ReturnValue_t FixedTimeslotTask::startTask() { - started = true; - - // We must not call resume if scheduler is not started yet - if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { - vTaskResume(handle); - } - - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, - uint32_t slotTimeMs, int8_t executionStep) { - if (objectManager->get(componentId) != nullptr) { - pst.addSlot(componentId, slotTimeMs, executionStep, this); - return HasReturnvaluesIF::RETURN_OK; - } - - sif::error << "Component " << std::hex << componentId << - " not found, not adding it to pst" << std::endl; - 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. - auto slotListIter = pst.current; - - //The start time for the first entry is read. - uint32_t intervalMs = slotListIter->pollingTimeMs; - TickType_t interval = pdMS_TO_TICKS(intervalMs); - - TickType_t xLastWakeTime; - /* The xLastWakeTime variable needs to be initialized with the current tick - count. Note that this is the only time the variable is written to - explicitly. After this assignment, xLastWakeTime is updated automatically - internally within vTaskDelayUntil(). */ - xLastWakeTime = xTaskGetTickCount(); - - // wait for first entry's start time - if(interval > 0) { - vTaskDelayUntil(&xLastWakeTime, interval); - } - - /* Enter the loop that defines the task behavior. */ - for (;;) { - //The component for this slot is executed and the next one is chosen. - this->pst.executeAndAdvance(); - if (not pst.slotFollowsImmediately()) { - // Get the interval till execution of the next slot. - intervalMs = this->pst.getIntervalToPreviousSlotMs(); - interval = pdMS_TO_TICKS(intervalMs); - - checkMissedDeadline(xLastWakeTime, interval); - - // Wait for the interval. This exits immediately if a deadline was - // missed while also updating the last wake time. - vTaskDelayUntil(&xLastWakeTime, interval); - } - } -} - -void FixedTimeslotTask::checkMissedDeadline(const TickType_t xLastWakeTime, - const TickType_t interval) { - /* Check whether deadline was missed while also taking overflows - * into account. Drawing this on paper with a timeline helps to understand - * it. */ - TickType_t currentTickCount = xTaskGetTickCount(); - TickType_t timeToWake = xLastWakeTime + interval; - // Time to wake has not overflown. - if(timeToWake > xLastWakeTime) { - /* If the current time has overflown exclusively or the current - * tick count is simply larger than the time to wake, a deadline was - * missed */ - if((currentTickCount < xLastWakeTime) or (currentTickCount > timeToWake)) { - handleMissedDeadline(); - } - } - /* Time to wake has overflown. A deadline was missed if the current time - * is larger than the time to wake */ - else if((timeToWake < xLastWakeTime) and (currentTickCount > timeToWake)) { - handleMissedDeadline(); - } -} - -void FixedTimeslotTask::handleMissedDeadline() { -#ifdef DEBUG - sif::warning << "FixedTimeslotTask: " << pcTaskGetName(NULL) << - " missed deadline!\n" << std::flush; -#endif - if(deadlineMissedFunc != nullptr) { - this->deadlineMissedFunc(); - } -} - -ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) { - vTaskDelay(pdMS_TO_TICKS(ms)); - return HasReturnvaluesIF::RETURN_OK; -} - -TaskHandle_t FixedTimeslotTask::getTaskHandle() { - return handle; -} +#include "FixedTimeslotTask.h" + +#include "../../serviceinterface/ServiceInterfaceStream.h" + +uint32_t FixedTimeslotTask::deadlineMissedCount = 0; +const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = configMINIMAL_STACK_SIZE; + +FixedTimeslotTask::FixedTimeslotTask(TaskName name, TaskPriority setPriority, + TaskStackSize setStack, TaskPeriod overallPeriod, + void (*setDeadlineMissedFunc)()) : + started(false), handle(NULL), pst(overallPeriod * 1000) { + configSTACK_DEPTH_TYPE stackSize = setStack / sizeof(configSTACK_DEPTH_TYPE); + xTaskCreate(taskEntryPoint, name, stackSize, this, setPriority, &handle); + // All additional attributes are applied to the object. + this->deadlineMissedFunc = setDeadlineMissedFunc; +} + +FixedTimeslotTask::~FixedTimeslotTask() { +} + +void FixedTimeslotTask::taskEntryPoint(void* argument) { + + // The argument is re-interpreted as FixedTimeslotTask. The Task object is + // global, so it is found from any place. + FixedTimeslotTask *originalTask(reinterpret_cast(argument)); + /* Task should not start until explicitly requested, + * but in FreeRTOS, tasks start as soon as they are created if the scheduler + * is running but not if the scheduler is not running. + * To be able to accommodate both cases we check a member which is set in + * #startTask(). If it is not set and we get here, the scheduler was started + * before #startTask() was called and we need to suspend if it is set, + * the scheduler was not running before #startTask() was called and we + * can continue */ + + if (not originalTask->started) { + vTaskSuspend(NULL); + } + + originalTask->taskFunctionality(); + sif::debug << "Polling task " << originalTask->handle + << " returned from taskFunctionality." << std::endl; +} + +void FixedTimeslotTask::missedDeadlineCounter() { + FixedTimeslotTask::deadlineMissedCount++; + if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) { + sif::error << "PST missed " << FixedTimeslotTask::deadlineMissedCount + << " deadlines." << std::endl; + } +} + +ReturnValue_t FixedTimeslotTask::startTask() { + started = true; + + // We must not call resume if scheduler is not started yet + if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { + vTaskResume(handle); + } + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, + uint32_t slotTimeMs, int8_t executionStep) { + if (objectManager->get(componentId) != nullptr) { + pst.addSlot(componentId, slotTimeMs, executionStep, this); + return HasReturnvaluesIF::RETURN_OK; + } + + sif::error << "Component " << std::hex << componentId << + " not found, not adding it to pst" << std::endl; + 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. + auto slotListIter = pst.current; + + //The start time for the first entry is read. + uint32_t intervalMs = slotListIter->pollingTimeMs; + TickType_t interval = pdMS_TO_TICKS(intervalMs); + + TickType_t xLastWakeTime; + /* The xLastWakeTime variable needs to be initialized with the current tick + count. Note that this is the only time the variable is written to + explicitly. After this assignment, xLastWakeTime is updated automatically + internally within vTaskDelayUntil(). */ + xLastWakeTime = xTaskGetTickCount(); + + // wait for first entry's start time + if(interval > 0) { + vTaskDelayUntil(&xLastWakeTime, interval); + } + + /* Enter the loop that defines the task behavior. */ + for (;;) { + //The component for this slot is executed and the next one is chosen. + this->pst.executeAndAdvance(); + if (not pst.slotFollowsImmediately()) { + // Get the interval till execution of the next slot. + intervalMs = this->pst.getIntervalToPreviousSlotMs(); + interval = pdMS_TO_TICKS(intervalMs); + + checkMissedDeadline(xLastWakeTime, interval); + + // Wait for the interval. This exits immediately if a deadline was + // missed while also updating the last wake time. + vTaskDelayUntil(&xLastWakeTime, interval); + } + } +} + +void FixedTimeslotTask::checkMissedDeadline(const TickType_t xLastWakeTime, + const TickType_t interval) { + /* Check whether deadline was missed while also taking overflows + * into account. Drawing this on paper with a timeline helps to understand + * it. */ + TickType_t currentTickCount = xTaskGetTickCount(); + TickType_t timeToWake = xLastWakeTime + interval; + // Time to wake has not overflown. + if(timeToWake > xLastWakeTime) { + /* If the current time has overflown exclusively or the current + * tick count is simply larger than the time to wake, a deadline was + * missed */ + if((currentTickCount < xLastWakeTime) or (currentTickCount > timeToWake)) { + handleMissedDeadline(); + } + } + /* Time to wake has overflown. A deadline was missed if the current time + * is larger than the time to wake */ + else if((timeToWake < xLastWakeTime) and (currentTickCount > timeToWake)) { + handleMissedDeadline(); + } +} + +void FixedTimeslotTask::handleMissedDeadline() { +#ifdef DEBUG + sif::warning << "FixedTimeslotTask: " << pcTaskGetName(NULL) << + " missed deadline!\n" << std::flush; +#endif + if(deadlineMissedFunc != nullptr) { + this->deadlineMissedFunc(); + } +} + +ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) { + vTaskDelay(pdMS_TO_TICKS(ms)); + return HasReturnvaluesIF::RETURN_OK; +} + +TaskHandle_t FixedTimeslotTask::getTaskHandle() { + return handle; +} diff --git a/osal/FreeRTOS/FixedTimeslotTask.h b/osal/FreeRTOS/FixedTimeslotTask.h index 36950773..42af14b8 100644 --- a/osal/FreeRTOS/FixedTimeslotTask.h +++ b/osal/FreeRTOS/FixedTimeslotTask.h @@ -1,101 +1,101 @@ -#ifndef FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_ -#define FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_ - -#include -#include -#include -#include - -#include -#include - -class FixedTimeslotTask: public FixedTimeslotTaskIF, public FreeRTOSTaskIF { -public: - - /** - * Keep in mind that you need to call before vTaskStartScheduler()! - * A lot of task parameters are set in "FreeRTOSConfig.h". - * @param name Name of the task, lenght limited by configMAX_TASK_NAME_LEN - * @param setPriority Number of priorities specified by - * configMAX_PRIORITIES. High taskPriority_ number means high priority. - * @param setStack Stack size in words (not bytes!). - * Lower limit specified by configMINIMAL_STACK_SIZE - * @param overallPeriod Period in seconds. - * @param setDeadlineMissedFunc Callback if a deadline was missed. - * @return Pointer to the newly created task. - */ - FixedTimeslotTask(TaskName name, TaskPriority setPriority, - TaskStackSize setStack, TaskPeriod 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 ~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) override; - - uint32_t getPeriodMs() const override; - - ReturnValue_t checkSequence() const override; - - ReturnValue_t sleepFor(uint32_t ms) override; - - TaskHandle_t getTaskHandle() override; - -protected: - bool started; - TaskHandle_t handle; - - 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 for a new task. - * @details - * This method starts the task by calling taskFunctionality(), as soon as - * all requirements (task scheduler has started and startTask() - * has been called) are met. - */ - static void taskEntryPoint(void* argument); - - /** - * @brief This function holds the main functionality of the thread. - * @details - * Core function holding the main functionality of the task - * It links the functionalities provided by FixedSlotSequence with the - * OS's System Calls to keep the timing of the periods. - */ - void taskFunctionality(void); - - void checkMissedDeadline(const TickType_t xLastWakeTime, - const TickType_t interval); - void handleMissedDeadline(); -}; - -#endif /* POLLINGTASK_H_ */ +#ifndef FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_ +#define FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_ + +#include "../../osal/FreeRTOS/FreeRTOSTaskIF.h" +#include "../../tasks/FixedSlotSequence.h" +#include "../../tasks/FixedTimeslotTaskIF.h" +#include "../../tasks/Typedef.h" + +#include +#include + +class FixedTimeslotTask: public FixedTimeslotTaskIF, public FreeRTOSTaskIF { +public: + + /** + * Keep in mind that you need to call before vTaskStartScheduler()! + * A lot of task parameters are set in "FreeRTOSConfig.h". + * @param name Name of the task, lenght limited by configMAX_TASK_NAME_LEN + * @param setPriority Number of priorities specified by + * configMAX_PRIORITIES. High taskPriority_ number means high priority. + * @param setStack Stack size in words (not bytes!). + * Lower limit specified by configMINIMAL_STACK_SIZE + * @param overallPeriod Period in seconds. + * @param setDeadlineMissedFunc Callback if a deadline was missed. + * @return Pointer to the newly created task. + */ + FixedTimeslotTask(TaskName name, TaskPriority setPriority, + TaskStackSize setStack, TaskPeriod 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 ~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) override; + + uint32_t getPeriodMs() const override; + + ReturnValue_t checkSequence() const override; + + ReturnValue_t sleepFor(uint32_t ms) override; + + TaskHandle_t getTaskHandle() override; + +protected: + bool started; + TaskHandle_t handle; + + 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 for a new task. + * @details + * This method starts the task by calling taskFunctionality(), as soon as + * all requirements (task scheduler has started and startTask() + * has been called) are met. + */ + static void taskEntryPoint(void* argument); + + /** + * @brief This function holds the main functionality of the thread. + * @details + * Core function holding the main functionality of the task + * It links the functionalities provided by FixedSlotSequence with the + * OS's System Calls to keep the timing of the periods. + */ + void taskFunctionality(void); + + void checkMissedDeadline(const TickType_t xLastWakeTime, + const TickType_t interval); + void handleMissedDeadline(); +}; + +#endif /* POLLINGTASK_H_ */ diff --git a/osal/FreeRTOS/MessageQueue.cpp b/osal/FreeRTOS/MessageQueue.cpp index e9f3871e..3b335ffc 100644 --- a/osal/FreeRTOS/MessageQueue.cpp +++ b/osal/FreeRTOS/MessageQueue.cpp @@ -1,155 +1,155 @@ -#include - -#include - -// TODO I guess we should have a way of checking if we are in an ISR and then -// use the "fromISR" versions of all calls -// As a first step towards this, introduces system context variable which needs -// to be switched manually -// Haven't found function to find system context. -MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize): - maxMessageSize(maxMessageSize) { - handle = xQueueCreate(messageDepth, maxMessageSize); - if (handle == NULL) { - sif::error << "MessageQueue: Creation failed" << std::endl; - } -} - -MessageQueue::~MessageQueue() { - if (handle != NULL) { - vQueueDelete(handle); - } -} - -void MessageQueue::switchSystemContext(CallContext callContext) { - this->callContext = callContext; -} - -ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, - MessageQueueMessageIF* message, bool ignoreFault) { - return sendMessageFrom(sendTo, message, this->getId(), ignoreFault); -} - -ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessageIF* message) { - return sendToDefaultFrom(message, this->getId()); -} - -ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message, - MessageQueueId_t sentFrom, bool ignoreFault) { - return sendMessageFrom(defaultDestination,message,sentFrom,ignoreFault); -} - -ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) { - if (this->lastPartner != MessageQueueMessageIF::NO_QUEUE) { - return sendMessageFrom(this->lastPartner, message, this->getId()); - } else { - return NO_REPLY_PARTNER; - } -} - -ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, - MessageQueueMessageIF* message, MessageQueueId_t sentFrom, - bool ignoreFault) { - return sendMessageFromMessageQueue(sendTo, message, sentFrom, ignoreFault, - callContext); -} - - -ReturnValue_t MessageQueue::handleSendResult(BaseType_t result, bool ignoreFault) { - if (result != pdPASS) { - if (not ignoreFault) { - InternalErrorReporterIF* internalErrorReporter = - objectManager->get( - objects::INTERNAL_ERROR_REPORTER); - if (internalErrorReporter != nullptr) { - internalErrorReporter->queueMessageNotSent(); - } - } - return MessageQueueIF::FULL; - } - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message, - MessageQueueId_t* receivedFrom) { - ReturnValue_t status = this->receiveMessage(message); - if(status == HasReturnvaluesIF::RETURN_OK) { - *receivedFrom = this->lastPartner; - } - return status; -} - -ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) { - BaseType_t result = xQueueReceive(handle,reinterpret_cast( - message->getBuffer()), 0); - if (result == pdPASS){ - this->lastPartner = message->getSender(); - return HasReturnvaluesIF::RETURN_OK; - } else { - return MessageQueueIF::EMPTY; - } -} - -MessageQueueId_t MessageQueue::getLastPartner() const { - return lastPartner; -} - -ReturnValue_t MessageQueue::flush(uint32_t* count) { - //TODO FreeRTOS does not support flushing partially - //Is always successful - xQueueReset(handle); - return HasReturnvaluesIF::RETURN_OK; -} - -MessageQueueId_t MessageQueue::getId() const { - return reinterpret_cast(handle); -} - -void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) { - defaultDestinationSet = true; - this->defaultDestination = defaultDestination; -} - -MessageQueueId_t MessageQueue::getDefaultDestination() const { - return defaultDestination; -} - -bool MessageQueue::isDefaultDestinationSet() const { - return defaultDestinationSet; -} - - -// static core function to send messages. -ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, - MessageQueueMessageIF* message, MessageQueueId_t sentFrom, - bool ignoreFault, CallContext callContext) { - BaseType_t result = pdFALSE; - QueueHandle_t destination = nullptr; - - if(sendTo == MessageQueueIF::NO_QUEUE) { - return MessageQueueIF::DESTINVATION_INVALID; - } - else { - destination = reinterpret_cast(sendTo); - } - message->setSender(sentFrom); - - - if(callContext == CallContext::TASK) { - result = xQueueSendToBack(destination, - static_cast(message->getBuffer()), 0); - } - else { - /* If the call context is from an interrupt, - * request a context switch if a higher priority task - * was blocked by the interrupt. */ - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - result = xQueueSendFromISR(reinterpret_cast(sendTo), - static_cast(message->getBuffer()), - &xHigherPriorityTaskWoken); - if(xHigherPriorityTaskWoken == pdTRUE) { - TaskManagement::requestContextSwitch(callContext); - } - } - return handleSendResult(result, ignoreFault); -} +#include "../../osal/FreeRTOS/MessageQueue.h" + +#include "../../serviceinterface/ServiceInterfaceStream.h" + +// TODO I guess we should have a way of checking if we are in an ISR and then +// use the "fromISR" versions of all calls +// As a first step towards this, introduces system context variable which needs +// to be switched manually +// Haven't found function to find system context. +MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize): + maxMessageSize(maxMessageSize) { + handle = xQueueCreate(messageDepth, maxMessageSize); + if (handle == NULL) { + sif::error << "MessageQueue: Creation failed" << std::endl; + } +} + +MessageQueue::~MessageQueue() { + if (handle != NULL) { + vQueueDelete(handle); + } +} + +void MessageQueue::switchSystemContext(CallContext callContext) { + this->callContext = callContext; +} + +ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, + MessageQueueMessageIF* message, bool ignoreFault) { + return sendMessageFrom(sendTo, message, this->getId(), ignoreFault); +} + +ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessageIF* message) { + return sendToDefaultFrom(message, this->getId()); +} + +ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message, + MessageQueueId_t sentFrom, bool ignoreFault) { + return sendMessageFrom(defaultDestination,message,sentFrom,ignoreFault); +} + +ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) { + if (this->lastPartner != MessageQueueMessageIF::NO_QUEUE) { + return sendMessageFrom(this->lastPartner, message, this->getId()); + } else { + return NO_REPLY_PARTNER; + } +} + +ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, + MessageQueueMessageIF* message, MessageQueueId_t sentFrom, + bool ignoreFault) { + return sendMessageFromMessageQueue(sendTo, message, sentFrom, ignoreFault, + callContext); +} + + +ReturnValue_t MessageQueue::handleSendResult(BaseType_t result, bool ignoreFault) { + if (result != pdPASS) { + if (not ignoreFault) { + InternalErrorReporterIF* internalErrorReporter = + objectManager->get( + objects::INTERNAL_ERROR_REPORTER); + if (internalErrorReporter != nullptr) { + internalErrorReporter->queueMessageNotSent(); + } + } + return MessageQueueIF::FULL; + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message, + MessageQueueId_t* receivedFrom) { + ReturnValue_t status = this->receiveMessage(message); + if(status == HasReturnvaluesIF::RETURN_OK) { + *receivedFrom = this->lastPartner; + } + return status; +} + +ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) { + BaseType_t result = xQueueReceive(handle,reinterpret_cast( + message->getBuffer()), 0); + if (result == pdPASS){ + this->lastPartner = message->getSender(); + return HasReturnvaluesIF::RETURN_OK; + } else { + return MessageQueueIF::EMPTY; + } +} + +MessageQueueId_t MessageQueue::getLastPartner() const { + return lastPartner; +} + +ReturnValue_t MessageQueue::flush(uint32_t* count) { + //TODO FreeRTOS does not support flushing partially + //Is always successful + xQueueReset(handle); + return HasReturnvaluesIF::RETURN_OK; +} + +MessageQueueId_t MessageQueue::getId() const { + return reinterpret_cast(handle); +} + +void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) { + defaultDestinationSet = true; + this->defaultDestination = defaultDestination; +} + +MessageQueueId_t MessageQueue::getDefaultDestination() const { + return defaultDestination; +} + +bool MessageQueue::isDefaultDestinationSet() const { + return defaultDestinationSet; +} + + +// static core function to send messages. +ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, + MessageQueueMessageIF* message, MessageQueueId_t sentFrom, + bool ignoreFault, CallContext callContext) { + BaseType_t result = pdFALSE; + QueueHandle_t destination = nullptr; + + if(sendTo == MessageQueueIF::NO_QUEUE) { + return MessageQueueIF::DESTINVATION_INVALID; + } + else { + destination = reinterpret_cast(sendTo); + } + message->setSender(sentFrom); + + + if(callContext == CallContext::TASK) { + result = xQueueSendToBack(destination, + static_cast(message->getBuffer()), 0); + } + else { + /* If the call context is from an interrupt, + * request a context switch if a higher priority task + * was blocked by the interrupt. */ + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + result = xQueueSendFromISR(reinterpret_cast(sendTo), + static_cast(message->getBuffer()), + &xHigherPriorityTaskWoken); + if(xHigherPriorityTaskWoken == pdTRUE) { + TaskManagement::requestContextSwitch(callContext); + } + } + return handleSendResult(result, ignoreFault); +} diff --git a/osal/FreeRTOS/MessageQueue.h b/osal/FreeRTOS/MessageQueue.h index b7e52bb3..48a5ab6a 100644 --- a/osal/FreeRTOS/MessageQueue.h +++ b/osal/FreeRTOS/MessageQueue.h @@ -1,212 +1,212 @@ -#ifndef MESSAGEQUEUE_H_ -#define MESSAGEQUEUE_H_ - -#include -#include -#include -#include - -#include -#include - -// TODO: this class assumes that MessageQueueId_t is the same size as void* -// (the FreeRTOS handle type), compiler will catch this but it might be nice -// to have something checking or even an always working solution -// https://scaryreasoner.wordpress.com/2009/02/28/checking-sizeof-at-compile-time/ - -/** - * @brief This class manages sending and receiving of - * message queue messages. - * @details - * Message queues are used to pass asynchronous messages between processes. - * They work like post boxes, where all incoming messages are stored in FIFO - * order. This class creates a new receiving queue and provides methods to fetch - * received messages. Being a child of MessageQueueSender, this class also - * provides methods to send a message to a user-defined or a default destination. - * In addition it also provides a reply method to answer to the queue it - * received its last message from. - * - * The MessageQueue should be used as "post box" for a single owning object. - * So all message queue communication is "n-to-one". - * For creating the queue, as well as sending and receiving messages, the class - * makes use of the operating system calls provided. - * - * Please keep in mind that FreeRTOS offers different calls for message queue - * operations if called from an ISR. - * For now, the system context needs to be switched manually. - * @ingroup osal - * @ingroup message_queue - */ -class MessageQueue : public MessageQueueIF { - friend class MessageQueueSenderIF; -public: - /** - * @brief The constructor initializes and configures the message queue. - * @details - * By making use of the according operating system call, a message queue is created - * and initialized. The message depth - the maximum number of messages to be - * buffered - may be set with the help of a parameter, whereas the message size is - * automatically set to the maximum message queue message size. The operating system - * sets the message queue id, or i case of failure, it is set to zero. - * @param message_depth - * The number of messages to be buffered before passing an error to the - * sender. Default is three. - * @param max_message_size - * With this parameter, the maximum message size can be adjusted. - * This should be left default. - */ - MessageQueue( size_t messageDepth = 3, - size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE ); - - /** Copying message queues forbidden */ - MessageQueue(const MessageQueue&) = delete; - MessageQueue& operator=(const MessageQueue&) = delete; - - /** - * @brief The destructor deletes the formerly created message queue. - * @details This is accomplished by using the delete call provided - * by the operating system. - */ - virtual ~MessageQueue(); - - /** - * This function is used to switch the call context. This has to be called - * if a message is sent or received from an ISR! - * @param callContext - */ - void switchSystemContext(CallContext callContext); - - /** - * @brief This operation sends a message to the given destination. - * @details It directly uses the sendMessage call of the MessageQueueSender parent, but passes its - * queue id as "sentFrom" parameter. - * @param sendTo This parameter specifies the message queue id of the destination message queue. - * @param message A pointer to a previously created message, which is sent. - * @param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. - */ - ReturnValue_t sendMessage(MessageQueueId_t sendTo, - MessageQueueMessageIF* message, bool ignoreFault = false) override; - /** - * @brief This operation sends a message to the default destination. - * @details As in the sendMessage method, this function uses the sendToDefault call of the - * MessageQueueSender parent class and adds its queue id as "sentFrom" information. - * @param message A pointer to a previously created message, which is sent. - */ - ReturnValue_t sendToDefault(MessageQueueMessageIF* message) override; - /** - * @brief This operation sends a message to the last communication partner. - * @details This operation simplifies answering an incoming message by using the stored - * lastParnter information as destination. If there was no message received yet - * (i.e. lastPartner is zero), an error code is returned. - * @param message A pointer to a previously created message, which is sent. - */ - ReturnValue_t reply(MessageQueueMessageIF* message) override; - - /** - * @brief With the sendMessage call, a queue message is sent to a receiving queue. - * @details This method takes the message provided, adds the sentFrom information and passes - * it on to the destination provided with an operating system call. The OS's return - * value is returned. - * @param sendTo This parameter specifies the message queue id to send the message to. - * @param message This is a pointer to a previously created message, which is sent. - * @param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. - * This variable is set to zero by default. - * @param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. - */ - virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, - MessageQueueMessageIF* message, - MessageQueueId_t sentFrom = NO_QUEUE, - bool ignoreFault = false) override; - - /** - * @brief The sendToDefault method sends a queue message to the default destination. - * @details In all other aspects, it works identical to the sendMessage method. - * @param message This is a pointer to a previously created message, which is sent. - * @param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. - * This variable is set to zero by default. - */ - virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessageIF* message, - MessageQueueId_t sentFrom = NO_QUEUE, - bool ignoreFault = false) override; - - /** - * @brief This function reads available messages from the message queue and returns the sender. - * @details It works identically to the other receiveMessage call, but in addition returns the - * sender's queue id. - * @param message A pointer to a message in which the received data is stored. - * @param receivedFrom A pointer to a queue id in which the sender's id is stored. - */ - ReturnValue_t receiveMessage(MessageQueueMessageIF* message, - MessageQueueId_t *receivedFrom) override; - - /** - * @brief This function reads available messages from the message queue. - * @details If data is available it is stored in the passed message pointer. The message's - * original content is overwritten and the sendFrom information is stored in the - * lastPartner attribute. Else, the lastPartner information remains untouched, the - * message's content is cleared and the function returns immediately. - * @param message A pointer to a message in which the received data is stored. - */ - ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override; - /** - * Deletes all pending messages in the queue. - * @param count The number of flushed messages. - * @return RETURN_OK on success. - */ - ReturnValue_t flush(uint32_t* count); - /** - * @brief This method returns the message queue id of the last communication partner. - */ - MessageQueueId_t getLastPartner() const; - /** - * @brief This method returns the message queue id of this class's message queue. - */ - MessageQueueId_t getId() const; - - /** - * @brief This method is a simple setter for the default destination. - */ - void setDefaultDestination(MessageQueueId_t defaultDestination); - /** - * @brief This method is a simple getter for the default destination. - */ - MessageQueueId_t getDefaultDestination() const; - - bool isDefaultDestinationSet() const; -protected: - /** - * @brief Implementation to be called from any send Call within - * MessageQueue and MessageQueueSenderIF. - * @details - * This method takes the message provided, adds the sentFrom information and - * passes it on to the destination provided with an operating system call. - * The OS's return value is returned. - * @param sendTo - * This parameter specifies the message queue id to send the message to. - * @param message - * This is a pointer to a previously created message, which is sent. - * @param sentFrom - * The sentFrom information can be set to inject the sender's queue id into - * the message. This variable is set to zero by default. - * @param ignoreFault - * If set to true, the internal software fault counter is not incremented - * if queue is full. - * @param context Specify whether call is made from task or from an ISR. - */ - static ReturnValue_t sendMessageFromMessageQueue(MessageQueueId_t sendTo, - MessageQueueMessageIF* message, MessageQueueId_t sentFrom = NO_QUEUE, - bool ignoreFault=false, CallContext callContext = CallContext::TASK); - - static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault); - -private: - bool defaultDestinationSet = false; - QueueHandle_t handle; - MessageQueueId_t defaultDestination = 0; - MessageQueueId_t lastPartner = 0; - const size_t maxMessageSize; - //!< Stores the current system context - CallContext callContext = CallContext::TASK; -}; - -#endif /* MESSAGEQUEUE_H_ */ +#ifndef MESSAGEQUEUE_H_ +#define MESSAGEQUEUE_H_ + +#include "../../internalError/InternalErrorReporterIF.h" +#include "../../ipc/MessageQueueIF.h" +#include "../../ipc/MessageQueueMessageIF.h" +#include "../../osal/FreeRTOS/TaskManagement.h" + +#include +#include + +// TODO: this class assumes that MessageQueueId_t is the same size as void* +// (the FreeRTOS handle type), compiler will catch this but it might be nice +// to have something checking or even an always working solution +// https://scaryreasoner.wordpress.com/2009/02/28/checking-sizeof-at-compile-time/ + +/** + * @brief This class manages sending and receiving of + * message queue messages. + * @details + * Message queues are used to pass asynchronous messages between processes. + * They work like post boxes, where all incoming messages are stored in FIFO + * order. This class creates a new receiving queue and provides methods to fetch + * received messages. Being a child of MessageQueueSender, this class also + * provides methods to send a message to a user-defined or a default destination. + * In addition it also provides a reply method to answer to the queue it + * received its last message from. + * + * The MessageQueue should be used as "post box" for a single owning object. + * So all message queue communication is "n-to-one". + * For creating the queue, as well as sending and receiving messages, the class + * makes use of the operating system calls provided. + * + * Please keep in mind that FreeRTOS offers different calls for message queue + * operations if called from an ISR. + * For now, the system context needs to be switched manually. + * @ingroup osal + * @ingroup message_queue + */ +class MessageQueue : public MessageQueueIF { + friend class MessageQueueSenderIF; +public: + /** + * @brief The constructor initializes and configures the message queue. + * @details + * By making use of the according operating system call, a message queue is created + * and initialized. The message depth - the maximum number of messages to be + * buffered - may be set with the help of a parameter, whereas the message size is + * automatically set to the maximum message queue message size. The operating system + * sets the message queue id, or i case of failure, it is set to zero. + * @param message_depth + * The number of messages to be buffered before passing an error to the + * sender. Default is three. + * @param max_message_size + * With this parameter, the maximum message size can be adjusted. + * This should be left default. + */ + MessageQueue( size_t messageDepth = 3, + size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE ); + + /** Copying message queues forbidden */ + MessageQueue(const MessageQueue&) = delete; + MessageQueue& operator=(const MessageQueue&) = delete; + + /** + * @brief The destructor deletes the formerly created message queue. + * @details This is accomplished by using the delete call provided + * by the operating system. + */ + virtual ~MessageQueue(); + + /** + * This function is used to switch the call context. This has to be called + * if a message is sent or received from an ISR! + * @param callContext + */ + void switchSystemContext(CallContext callContext); + + /** + * @brief This operation sends a message to the given destination. + * @details It directly uses the sendMessage call of the MessageQueueSender parent, but passes its + * queue id as "sentFrom" parameter. + * @param sendTo This parameter specifies the message queue id of the destination message queue. + * @param message A pointer to a previously created message, which is sent. + * @param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. + */ + ReturnValue_t sendMessage(MessageQueueId_t sendTo, + MessageQueueMessageIF* message, bool ignoreFault = false) override; + /** + * @brief This operation sends a message to the default destination. + * @details As in the sendMessage method, this function uses the sendToDefault call of the + * MessageQueueSender parent class and adds its queue id as "sentFrom" information. + * @param message A pointer to a previously created message, which is sent. + */ + ReturnValue_t sendToDefault(MessageQueueMessageIF* message) override; + /** + * @brief This operation sends a message to the last communication partner. + * @details This operation simplifies answering an incoming message by using the stored + * lastParnter information as destination. If there was no message received yet + * (i.e. lastPartner is zero), an error code is returned. + * @param message A pointer to a previously created message, which is sent. + */ + ReturnValue_t reply(MessageQueueMessageIF* message) override; + + /** + * @brief With the sendMessage call, a queue message is sent to a receiving queue. + * @details This method takes the message provided, adds the sentFrom information and passes + * it on to the destination provided with an operating system call. The OS's return + * value is returned. + * @param sendTo This parameter specifies the message queue id to send the message to. + * @param message This is a pointer to a previously created message, which is sent. + * @param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. + * This variable is set to zero by default. + * @param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. + */ + virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, + MessageQueueMessageIF* message, + MessageQueueId_t sentFrom = NO_QUEUE, + bool ignoreFault = false) override; + + /** + * @brief The sendToDefault method sends a queue message to the default destination. + * @details In all other aspects, it works identical to the sendMessage method. + * @param message This is a pointer to a previously created message, which is sent. + * @param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. + * This variable is set to zero by default. + */ + virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessageIF* message, + MessageQueueId_t sentFrom = NO_QUEUE, + bool ignoreFault = false) override; + + /** + * @brief This function reads available messages from the message queue and returns the sender. + * @details It works identically to the other receiveMessage call, but in addition returns the + * sender's queue id. + * @param message A pointer to a message in which the received data is stored. + * @param receivedFrom A pointer to a queue id in which the sender's id is stored. + */ + ReturnValue_t receiveMessage(MessageQueueMessageIF* message, + MessageQueueId_t *receivedFrom) override; + + /** + * @brief This function reads available messages from the message queue. + * @details If data is available it is stored in the passed message pointer. The message's + * original content is overwritten and the sendFrom information is stored in the + * lastPartner attribute. Else, the lastPartner information remains untouched, the + * message's content is cleared and the function returns immediately. + * @param message A pointer to a message in which the received data is stored. + */ + ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override; + /** + * Deletes all pending messages in the queue. + * @param count The number of flushed messages. + * @return RETURN_OK on success. + */ + ReturnValue_t flush(uint32_t* count); + /** + * @brief This method returns the message queue id of the last communication partner. + */ + MessageQueueId_t getLastPartner() const; + /** + * @brief This method returns the message queue id of this class's message queue. + */ + MessageQueueId_t getId() const; + + /** + * @brief This method is a simple setter for the default destination. + */ + void setDefaultDestination(MessageQueueId_t defaultDestination); + /** + * @brief This method is a simple getter for the default destination. + */ + MessageQueueId_t getDefaultDestination() const; + + bool isDefaultDestinationSet() const; +protected: + /** + * @brief Implementation to be called from any send Call within + * MessageQueue and MessageQueueSenderIF. + * @details + * This method takes the message provided, adds the sentFrom information and + * passes it on to the destination provided with an operating system call. + * The OS's return value is returned. + * @param sendTo + * This parameter specifies the message queue id to send the message to. + * @param message + * This is a pointer to a previously created message, which is sent. + * @param sentFrom + * The sentFrom information can be set to inject the sender's queue id into + * the message. This variable is set to zero by default. + * @param ignoreFault + * If set to true, the internal software fault counter is not incremented + * if queue is full. + * @param context Specify whether call is made from task or from an ISR. + */ + static ReturnValue_t sendMessageFromMessageQueue(MessageQueueId_t sendTo, + MessageQueueMessageIF* message, MessageQueueId_t sentFrom = NO_QUEUE, + bool ignoreFault=false, CallContext callContext = CallContext::TASK); + + static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault); + +private: + bool defaultDestinationSet = false; + QueueHandle_t handle; + MessageQueueId_t defaultDestination = 0; + MessageQueueId_t lastPartner = 0; + const size_t maxMessageSize; + //!< Stores the current system context + CallContext callContext = CallContext::TASK; +}; + +#endif /* MESSAGEQUEUE_H_ */ diff --git a/osal/FreeRTOS/Mutex.cpp b/osal/FreeRTOS/Mutex.cpp index 764b0ae0..8d2e43b8 100644 --- a/osal/FreeRTOS/Mutex.cpp +++ b/osal/FreeRTOS/Mutex.cpp @@ -1,51 +1,51 @@ -#include - -#include - -Mutex::Mutex() { - handle = xSemaphoreCreateMutex(); - if(handle == nullptr) { - sif::error << "Mutex::Mutex(FreeRTOS): Creation failure" << std::endl; - } -} - -Mutex::~Mutex() { - if (handle != nullptr) { - vSemaphoreDelete(handle); - } - -} - -ReturnValue_t Mutex::lockMutex(TimeoutType timeoutType, - uint32_t timeoutMs) { - if (handle == nullptr) { - return MutexIF::MUTEX_NOT_FOUND; - } - // If the timeout type is BLOCKING, this will be the correct value. - uint32_t timeout = portMAX_DELAY; - if(timeoutType == TimeoutType::POLLING) { - timeout = 0; - } - else if(timeoutType == TimeoutType::WAITING){ - timeout = pdMS_TO_TICKS(timeoutMs); - } - - BaseType_t returncode = xSemaphoreTake(handle, timeout); - if (returncode == pdPASS) { - return HasReturnvaluesIF::RETURN_OK; - } else { - return MutexIF::MUTEX_TIMEOUT; - } -} - -ReturnValue_t Mutex::unlockMutex() { - if (handle == nullptr) { - return MutexIF::MUTEX_NOT_FOUND; - } - BaseType_t returncode = xSemaphoreGive(handle); - if (returncode == pdPASS) { - return HasReturnvaluesIF::RETURN_OK; - } else { - return MutexIF::CURR_THREAD_DOES_NOT_OWN_MUTEX; - } -} +#include "../../osal/FreeRTOS/Mutex.h" + +#include "../../serviceinterface/ServiceInterfaceStream.h" + +Mutex::Mutex() { + handle = xSemaphoreCreateMutex(); + if(handle == nullptr) { + sif::error << "Mutex::Mutex(FreeRTOS): Creation failure" << std::endl; + } +} + +Mutex::~Mutex() { + if (handle != nullptr) { + vSemaphoreDelete(handle); + } + +} + +ReturnValue_t Mutex::lockMutex(TimeoutType timeoutType, + uint32_t timeoutMs) { + if (handle == nullptr) { + return MutexIF::MUTEX_NOT_FOUND; + } + // If the timeout type is BLOCKING, this will be the correct value. + uint32_t timeout = portMAX_DELAY; + if(timeoutType == TimeoutType::POLLING) { + timeout = 0; + } + else if(timeoutType == TimeoutType::WAITING){ + timeout = pdMS_TO_TICKS(timeoutMs); + } + + BaseType_t returncode = xSemaphoreTake(handle, timeout); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } else { + return MutexIF::MUTEX_TIMEOUT; + } +} + +ReturnValue_t Mutex::unlockMutex() { + if (handle == nullptr) { + return MutexIF::MUTEX_NOT_FOUND; + } + BaseType_t returncode = xSemaphoreGive(handle); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } else { + return MutexIF::CURR_THREAD_DOES_NOT_OWN_MUTEX; + } +} diff --git a/osal/FreeRTOS/Mutex.h b/osal/FreeRTOS/Mutex.h index 2a4fae26..5cbc6a72 100644 --- a/osal/FreeRTOS/Mutex.h +++ b/osal/FreeRTOS/Mutex.h @@ -1,29 +1,29 @@ -#ifndef FRAMEWORK_FREERTOS_MUTEX_H_ -#define FRAMEWORK_FREERTOS_MUTEX_H_ - -#include - -#include -#include - -/** - * @brief OS component to implement MUTual EXclusion - * - * @details - * Mutexes are binary semaphores which include a priority inheritance mechanism. - * Documentation: https://www.freertos.org/Real-time-embedded-RTOS-mutexes.html - * @ingroup osal - */ -class Mutex : public MutexIF { -public: - Mutex(); - ~Mutex(); - ReturnValue_t lockMutex(TimeoutType timeoutType, - uint32_t timeoutMs) override; - ReturnValue_t unlockMutex() override; - -private: - SemaphoreHandle_t handle; -}; - -#endif /* FRAMEWORK_FREERTOS_MUTEX_H_ */ +#ifndef FRAMEWORK_FREERTOS_MUTEX_H_ +#define FRAMEWORK_FREERTOS_MUTEX_H_ + +#include "../../ipc/MutexIF.h" + +#include +#include + +/** + * @brief OS component to implement MUTual EXclusion + * + * @details + * Mutexes are binary semaphores which include a priority inheritance mechanism. + * Documentation: https://www.freertos.org/Real-time-embedded-RTOS-mutexes.html + * @ingroup osal + */ +class Mutex : public MutexIF { +public: + Mutex(); + ~Mutex(); + ReturnValue_t lockMutex(TimeoutType timeoutType, + uint32_t timeoutMs) override; + ReturnValue_t unlockMutex() override; + +private: + SemaphoreHandle_t handle; +}; + +#endif /* FRAMEWORK_FREERTOS_MUTEX_H_ */ diff --git a/osal/FreeRTOS/MutexFactory.cpp b/osal/FreeRTOS/MutexFactory.cpp index a1cca54b..9dcd8536 100644 --- a/osal/FreeRTOS/MutexFactory.cpp +++ b/osal/FreeRTOS/MutexFactory.cpp @@ -1,28 +1,28 @@ -#include -#include - -//TODO: Different variant than the lazy loading in QueueFactory. -//What's better and why? -> one is on heap the other on bss/data -//MutexFactory* MutexFactory::factoryInstance = new MutexFactory(); -MutexFactory* MutexFactory::factoryInstance = nullptr; - -MutexFactory::MutexFactory() { -} - -MutexFactory::~MutexFactory() { -} - -MutexFactory* MutexFactory::instance() { - if (factoryInstance == nullptr){ - factoryInstance = new MutexFactory(); - } - return MutexFactory::factoryInstance; -} - -MutexIF* MutexFactory::createMutex() { - return new Mutex(); -} - -void MutexFactory::deleteMutex(MutexIF* mutex) { - delete mutex; -} +#include "../../ipc/MutexFactory.h" +#include "../../osal/FreeRTOS/Mutex.h" + +//TODO: Different variant than the lazy loading in QueueFactory. +//What's better and why? -> one is on heap the other on bss/data +//MutexFactory* MutexFactory::factoryInstance = new MutexFactory(); +MutexFactory* MutexFactory::factoryInstance = nullptr; + +MutexFactory::MutexFactory() { +} + +MutexFactory::~MutexFactory() { +} + +MutexFactory* MutexFactory::instance() { + if (factoryInstance == nullptr){ + factoryInstance = new MutexFactory(); + } + return MutexFactory::factoryInstance; +} + +MutexIF* MutexFactory::createMutex() { + return new Mutex(); +} + +void MutexFactory::deleteMutex(MutexIF* mutex) { + delete mutex; +} diff --git a/osal/FreeRTOS/PeriodicTask.cpp b/osal/FreeRTOS/PeriodicTask.cpp index c316d4fc..662ece3b 100644 --- a/osal/FreeRTOS/PeriodicTask.cpp +++ b/osal/FreeRTOS/PeriodicTask.cpp @@ -1,138 +1,138 @@ -#include "PeriodicTask.h" - -#include -#include - -PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority, - TaskStackSize setStack, TaskPeriod setPeriod, - TaskDeadlineMissedFunction deadlineMissedFunc) : - started(false), handle(NULL), period(setPeriod), deadlineMissedFunc( - deadlineMissedFunc) -{ - configSTACK_DEPTH_TYPE stackSize = setStack / sizeof(configSTACK_DEPTH_TYPE); - BaseType_t status = xTaskCreate(taskEntryPoint, name, - stackSize, this, setPriority, &handle); - if(status != pdPASS){ - sif::debug << "PeriodicTask Insufficient heap memory remaining. " - "Status: " << status << std::endl; - } - -} - -PeriodicTask::~PeriodicTask(void) { - //Do not delete objects, we were responsible for ptrs only. -} - -void PeriodicTask::taskEntryPoint(void* argument) { - // The argument is re-interpreted as PeriodicTask. The Task object is - // global, so it is found from any place. - PeriodicTask *originalTask(reinterpret_cast(argument)); - /* Task should not start until explicitly requested, - * but in FreeRTOS, tasks start as soon as they are created if the scheduler - * is running but not if the scheduler is not running. - * To be able to accommodate both cases we check a member which is set in - * #startTask(). If it is not set and we get here, the scheduler was started - * before #startTask() was called and we need to suspend if it is set, - * the scheduler was not running before #startTask() was called and we - * can continue */ - - if (not originalTask->started) { - vTaskSuspend(NULL); - } - - originalTask->taskFunctionality(); - sif::debug << "Polling task " << originalTask->handle - << " returned from taskFunctionality." << std::endl; -} - -ReturnValue_t PeriodicTask::startTask() { - started = true; - - // We must not call resume if scheduler is not started yet - if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { - vTaskResume(handle); - } - - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t PeriodicTask::sleepFor(uint32_t ms) { - vTaskDelay(pdMS_TO_TICKS(ms)); - return HasReturnvaluesIF::RETURN_OK; -} - -void PeriodicTask::taskFunctionality() { - TickType_t xLastWakeTime; - const TickType_t xPeriod = pdMS_TO_TICKS(this->period * 1000.); - /* The xLastWakeTime variable needs to be initialized with the current tick - count. Note that this is the only time the variable is written to - explicitly. After this assignment, xLastWakeTime is updated automatically - internally within vTaskDelayUntil(). */ - xLastWakeTime = xTaskGetTickCount(); - /* Enter the loop that defines the task behavior. */ - for (;;) { - for (auto const& object: objectList) { - object->performOperation(); - } - - checkMissedDeadline(xLastWakeTime, xPeriod); - - vTaskDelayUntil(&xLastWakeTime, xPeriod); - - } -} - -ReturnValue_t PeriodicTask::addComponent(object_id_t object) { - ExecutableObjectIF* newObject = objectManager->get( - object); - if (newObject == nullptr) { - sif::error << "PeriodicTask::addComponent: Invalid object. Make sure" - "it implement ExecutableObjectIF" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - objectList.push_back(newObject); - newObject->setTaskIF(this); - - return newObject->initializeAfterTaskCreation(); -} - -uint32_t PeriodicTask::getPeriodMs() const { - return period * 1000; -} - -void PeriodicTask::checkMissedDeadline(const TickType_t xLastWakeTime, - const TickType_t interval) { - /* Check whether deadline was missed while also taking overflows - * into account. Drawing this on paper with a timeline helps to understand - * it. */ - TickType_t currentTickCount = xTaskGetTickCount(); - TickType_t timeToWake = xLastWakeTime + interval; - // Time to wake has not overflown. - if(timeToWake > xLastWakeTime) { - /* If the current time has overflown exclusively or the current - * tick count is simply larger than the time to wake, a deadline was - * missed */ - if((currentTickCount < xLastWakeTime) or (currentTickCount > timeToWake)) { - handleMissedDeadline(); - } - } - /* Time to wake has overflown. A deadline was missed if the current time - * is larger than the time to wake */ - else if((timeToWake < xLastWakeTime) and (currentTickCount > timeToWake)) { - handleMissedDeadline(); - } -} - -TaskHandle_t PeriodicTask::getTaskHandle() { - return handle; -} - -void PeriodicTask::handleMissedDeadline() { -#ifdef DEBUG - sif::warning << "PeriodicTask: " << pcTaskGetName(NULL) << - " missed deadline!\n" << std::flush; -#endif - if(deadlineMissedFunc != nullptr) { - this->deadlineMissedFunc(); - } -} +#include "PeriodicTask.h" + +#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "../../tasks/ExecutableObjectIF.h" + +PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority, + TaskStackSize setStack, TaskPeriod setPeriod, + TaskDeadlineMissedFunction deadlineMissedFunc) : + started(false), handle(NULL), period(setPeriod), deadlineMissedFunc( + deadlineMissedFunc) +{ + configSTACK_DEPTH_TYPE stackSize = setStack / sizeof(configSTACK_DEPTH_TYPE); + BaseType_t status = xTaskCreate(taskEntryPoint, name, + stackSize, this, setPriority, &handle); + if(status != pdPASS){ + sif::debug << "PeriodicTask Insufficient heap memory remaining. " + "Status: " << status << std::endl; + } + +} + +PeriodicTask::~PeriodicTask(void) { + //Do not delete objects, we were responsible for ptrs only. +} + +void PeriodicTask::taskEntryPoint(void* argument) { + // The argument is re-interpreted as PeriodicTask. The Task object is + // global, so it is found from any place. + PeriodicTask *originalTask(reinterpret_cast(argument)); + /* Task should not start until explicitly requested, + * but in FreeRTOS, tasks start as soon as they are created if the scheduler + * is running but not if the scheduler is not running. + * To be able to accommodate both cases we check a member which is set in + * #startTask(). If it is not set and we get here, the scheduler was started + * before #startTask() was called and we need to suspend if it is set, + * the scheduler was not running before #startTask() was called and we + * can continue */ + + if (not originalTask->started) { + vTaskSuspend(NULL); + } + + originalTask->taskFunctionality(); + sif::debug << "Polling task " << originalTask->handle + << " returned from taskFunctionality." << std::endl; +} + +ReturnValue_t PeriodicTask::startTask() { + started = true; + + // We must not call resume if scheduler is not started yet + if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { + vTaskResume(handle); + } + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t PeriodicTask::sleepFor(uint32_t ms) { + vTaskDelay(pdMS_TO_TICKS(ms)); + return HasReturnvaluesIF::RETURN_OK; +} + +void PeriodicTask::taskFunctionality() { + TickType_t xLastWakeTime; + const TickType_t xPeriod = pdMS_TO_TICKS(this->period * 1000.); + /* The xLastWakeTime variable needs to be initialized with the current tick + count. Note that this is the only time the variable is written to + explicitly. After this assignment, xLastWakeTime is updated automatically + internally within vTaskDelayUntil(). */ + xLastWakeTime = xTaskGetTickCount(); + /* Enter the loop that defines the task behavior. */ + for (;;) { + for (auto const& object: objectList) { + object->performOperation(); + } + + checkMissedDeadline(xLastWakeTime, xPeriod); + + vTaskDelayUntil(&xLastWakeTime, xPeriod); + + } +} + +ReturnValue_t PeriodicTask::addComponent(object_id_t object) { + ExecutableObjectIF* newObject = objectManager->get( + object); + if (newObject == nullptr) { + sif::error << "PeriodicTask::addComponent: Invalid object. Make sure" + "it implement ExecutableObjectIF" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + objectList.push_back(newObject); + newObject->setTaskIF(this); + + return newObject->initializeAfterTaskCreation(); +} + +uint32_t PeriodicTask::getPeriodMs() const { + return period * 1000; +} + +void PeriodicTask::checkMissedDeadline(const TickType_t xLastWakeTime, + const TickType_t interval) { + /* Check whether deadline was missed while also taking overflows + * into account. Drawing this on paper with a timeline helps to understand + * it. */ + TickType_t currentTickCount = xTaskGetTickCount(); + TickType_t timeToWake = xLastWakeTime + interval; + // Time to wake has not overflown. + if(timeToWake > xLastWakeTime) { + /* If the current time has overflown exclusively or the current + * tick count is simply larger than the time to wake, a deadline was + * missed */ + if((currentTickCount < xLastWakeTime) or (currentTickCount > timeToWake)) { + handleMissedDeadline(); + } + } + /* Time to wake has overflown. A deadline was missed if the current time + * is larger than the time to wake */ + else if((timeToWake < xLastWakeTime) and (currentTickCount > timeToWake)) { + handleMissedDeadline(); + } +} + +TaskHandle_t PeriodicTask::getTaskHandle() { + return handle; +} + +void PeriodicTask::handleMissedDeadline() { +#ifdef DEBUG + sif::warning << "PeriodicTask: " << pcTaskGetName(NULL) << + " missed deadline!\n" << std::flush; +#endif + if(deadlineMissedFunc != nullptr) { + this->deadlineMissedFunc(); + } +} diff --git a/osal/FreeRTOS/PeriodicTask.h b/osal/FreeRTOS/PeriodicTask.h index 8030baad..1cdc3df7 100644 --- a/osal/FreeRTOS/PeriodicTask.h +++ b/osal/FreeRTOS/PeriodicTask.h @@ -1,128 +1,128 @@ -#ifndef FRAMEWORK_OSAL_FREERTOS_PERIODICTASK_H_ -#define FRAMEWORK_OSAL_FREERTOS_PERIODICTASK_H_ - -#include -#include -#include -#include - - -#include -#include - -#include - -class ExecutableObjectIF; - -/** - * @brief This class represents a specialized task for - * periodic activities of multiple objects. - * @ingroup task_handling - */ -class PeriodicTask: public PeriodicTaskIF, public FreeRTOSTaskIF { -public: - /** - * Keep in Mind that you need to call before this vTaskStartScheduler()! - * A lot of task parameters are set in "FreeRTOSConfig.h". - * TODO: why does this need to be called before vTaskStartScheduler? - * @details - * The class is initialized without allocated objects. - * These need to be added with #addComponent. - * @param priority - * Sets the priority of a task. Values depend on freeRTOS configuration, - * high number means high priority. - * @param stack_size - * The stack size reserved by the operating system for the task. - * @param setPeriod - * The length of the period with which the task's - * functionality will be executed. It is expressed in clock ticks. - * @param setDeadlineMissedFunc - * The function pointer to the deadline missed function that shall - * be assigned. - */ - PeriodicTask(TaskName name, TaskPriority setPriority, - TaskStackSize setStack, TaskPeriod setPeriod, - TaskDeadlineMissedFunction deadlineMissedFunc); - /** - * @brief Currently, the executed object's lifetime is not coupled with - * the task object's lifetime, so the destructor is empty. - */ - virtual ~PeriodicTask(void); - - /** - * @brief The method to start the task. - * @details The method starts the task with the respective system call. - * Entry point is the taskEntryPoint method described below. - * The address of the task object is passed as an argument - * to the system call. - */ - ReturnValue_t startTask() override; - /** - * Adds an object to the list of objects to be executed. - * The objects are executed in the order added. - * @param object Id of the object to add. - * @return - * -@c RETURN_OK on success - * -@c RETURN_FAILED if the object could not be added. - */ - ReturnValue_t addComponent(object_id_t object) override; - - uint32_t getPeriodMs() const override; - - ReturnValue_t sleepFor(uint32_t ms) override; - - TaskHandle_t getTaskHandle() override; -protected: - bool started; - TaskHandle_t handle; - - //! Typedef for the List of objects. - typedef std::vector ObjectList; - /** - * @brief This attribute holds a list of objects to be executed. - */ - ObjectList objectList; - /** - * @brief The period of the task. - * @details - * The period determines the frequency of the task's execution. - * It is expressed in clock ticks. - */ - TaskPeriod period; - /** - * @brief The pointer to the deadline-missed function. - * @details - * This pointer stores the function that is executed if the task's deadline - * is missed so each may react individually on a timing failure. - * The pointer may be NULL, then nothing happens on missing the deadline. - * The deadline is equal to the next execution of the periodic task. - */ - void (*deadlineMissedFunc)(void); - /** - * @brief This is the function executed in the new task's context. - * @details - * It converts the argument back to the thread object type and copies the - * class instance to the task context. The taskFunctionality method is - * called afterwards. - * @param A pointer to the task object itself is passed as argument. - */ - - static void taskEntryPoint(void* argument); - /** - * @brief The function containing the actual functionality of the task. - * @details - * The method sets and starts the task's period, then enters a loop that is - * repeated as long as the isRunning attribute is true. Within the loop, - * all performOperation methods of the added objects are called. - * Afterwards the checkAndRestartPeriod system call blocks the task until - * the next period. - * On missing the deadline, the deadlineMissedFunction is executed. - */ - void taskFunctionality(void); - - void checkMissedDeadline(const TickType_t xLastWakeTime, - const TickType_t interval); - void handleMissedDeadline(); -}; - -#endif /* PERIODICTASK_H_ */ +#ifndef FRAMEWORK_OSAL_FREERTOS_PERIODICTASK_H_ +#define FRAMEWORK_OSAL_FREERTOS_PERIODICTASK_H_ + +#include "../../osal/FreeRTOS/FreeRTOSTaskIF.h" +#include "../../objectmanager/ObjectManagerIF.h" +#include "../../tasks/PeriodicTaskIF.h" +#include "../../tasks/Typedef.h" + + +#include +#include + +#include + +class ExecutableObjectIF; + +/** + * @brief This class represents a specialized task for + * periodic activities of multiple objects. + * @ingroup task_handling + */ +class PeriodicTask: public PeriodicTaskIF, public FreeRTOSTaskIF { +public: + /** + * Keep in Mind that you need to call before this vTaskStartScheduler()! + * A lot of task parameters are set in "FreeRTOSConfig.h". + * TODO: why does this need to be called before vTaskStartScheduler? + * @details + * The class is initialized without allocated objects. + * These need to be added with #addComponent. + * @param priority + * Sets the priority of a task. Values depend on freeRTOS configuration, + * high number means high priority. + * @param stack_size + * The stack size reserved by the operating system for the task. + * @param setPeriod + * The length of the period with which the task's + * functionality will be executed. It is expressed in clock ticks. + * @param setDeadlineMissedFunc + * The function pointer to the deadline missed function that shall + * be assigned. + */ + PeriodicTask(TaskName name, TaskPriority setPriority, + TaskStackSize setStack, TaskPeriod setPeriod, + TaskDeadlineMissedFunction deadlineMissedFunc); + /** + * @brief Currently, the executed object's lifetime is not coupled with + * the task object's lifetime, so the destructor is empty. + */ + virtual ~PeriodicTask(void); + + /** + * @brief The method to start the task. + * @details The method starts the task with the respective system call. + * Entry point is the taskEntryPoint method described below. + * The address of the task object is passed as an argument + * to the system call. + */ + ReturnValue_t startTask() override; + /** + * Adds an object to the list of objects to be executed. + * The objects are executed in the order added. + * @param object Id of the object to add. + * @return + * -@c RETURN_OK on success + * -@c RETURN_FAILED if the object could not be added. + */ + ReturnValue_t addComponent(object_id_t object) override; + + uint32_t getPeriodMs() const override; + + ReturnValue_t sleepFor(uint32_t ms) override; + + TaskHandle_t getTaskHandle() override; +protected: + bool started; + TaskHandle_t handle; + + //! Typedef for the List of objects. + typedef std::vector ObjectList; + /** + * @brief This attribute holds a list of objects to be executed. + */ + ObjectList objectList; + /** + * @brief The period of the task. + * @details + * The period determines the frequency of the task's execution. + * It is expressed in clock ticks. + */ + TaskPeriod period; + /** + * @brief The pointer to the deadline-missed function. + * @details + * This pointer stores the function that is executed if the task's deadline + * is missed so each may react individually on a timing failure. + * The pointer may be NULL, then nothing happens on missing the deadline. + * The deadline is equal to the next execution of the periodic task. + */ + void (*deadlineMissedFunc)(void); + /** + * @brief This is the function executed in the new task's context. + * @details + * It converts the argument back to the thread object type and copies the + * class instance to the task context. The taskFunctionality method is + * called afterwards. + * @param A pointer to the task object itself is passed as argument. + */ + + static void taskEntryPoint(void* argument); + /** + * @brief The function containing the actual functionality of the task. + * @details + * The method sets and starts the task's period, then enters a loop that is + * repeated as long as the isRunning attribute is true. Within the loop, + * all performOperation methods of the added objects are called. + * Afterwards the checkAndRestartPeriod system call blocks the task until + * the next period. + * On missing the deadline, the deadlineMissedFunction is executed. + */ + void taskFunctionality(void); + + void checkMissedDeadline(const TickType_t xLastWakeTime, + const TickType_t interval); + void handleMissedDeadline(); +}; + +#endif /* PERIODICTASK_H_ */ diff --git a/osal/FreeRTOS/QueueFactory.cpp b/osal/FreeRTOS/QueueFactory.cpp index beb4969b..05091733 100644 --- a/osal/FreeRTOS/QueueFactory.cpp +++ b/osal/FreeRTOS/QueueFactory.cpp @@ -1,36 +1,36 @@ -#include - -#include - - -QueueFactory* QueueFactory::factoryInstance = nullptr; - - -ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo, - MessageQueueMessageIF* message, MessageQueueId_t sentFrom, - bool ignoreFault) { - return MessageQueue::sendMessageFromMessageQueue(sendTo,message, - sentFrom,ignoreFault); -} - -QueueFactory* QueueFactory::instance() { - if (factoryInstance == nullptr) { - factoryInstance = new QueueFactory; - } - return factoryInstance; -} - -QueueFactory::QueueFactory() { -} - -QueueFactory::~QueueFactory() { -} - -MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, - size_t maxMessageSize) { - return new MessageQueue(messageDepth, maxMessageSize); -} - -void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { - delete queue; -} +#include "../../ipc/QueueFactory.h" + +#include "../../osal/FreeRTOS/MessageQueue.h" + + +QueueFactory* QueueFactory::factoryInstance = nullptr; + + +ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo, + MessageQueueMessageIF* message, MessageQueueId_t sentFrom, + bool ignoreFault) { + return MessageQueue::sendMessageFromMessageQueue(sendTo,message, + sentFrom,ignoreFault); +} + +QueueFactory* QueueFactory::instance() { + if (factoryInstance == nullptr) { + factoryInstance = new QueueFactory; + } + return factoryInstance; +} + +QueueFactory::QueueFactory() { +} + +QueueFactory::~QueueFactory() { +} + +MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, + size_t maxMessageSize) { + return new MessageQueue(messageDepth, maxMessageSize); +} + +void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { + delete queue; +} diff --git a/osal/FreeRTOS/SemaphoreFactory.cpp b/osal/FreeRTOS/SemaphoreFactory.cpp index 78427f6c..453f2226 100644 --- a/osal/FreeRTOS/SemaphoreFactory.cpp +++ b/osal/FreeRTOS/SemaphoreFactory.cpp @@ -1,61 +1,61 @@ -#include -#include -#include -#include -#include -#include - -SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr; -const uint32_t SemaphoreIF::POLLING = 0; -const uint32_t SemaphoreIF::BLOCKING = portMAX_DELAY; - -static const uint32_t USE_REGULAR_SEMAPHORES = 0; -static const uint32_t USE_TASK_NOTIFICATIONS = 1; - -SemaphoreFactory::SemaphoreFactory() { -} - -SemaphoreFactory::~SemaphoreFactory() { - delete factoryInstance; -} - -SemaphoreFactory* SemaphoreFactory::instance() { - if (factoryInstance == nullptr){ - factoryInstance = new SemaphoreFactory(); - } - return SemaphoreFactory::factoryInstance; -} - -SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t argument) { - if(argument == USE_REGULAR_SEMAPHORES) { - return new BinarySemaphore(); - } - else if(argument == USE_TASK_NOTIFICATIONS) { - return new BinarySemaphoreUsingTask(); - } - else { - sif::warning << "SemaphoreFactory: Invalid argument, return regular" - "binary semaphore" << std::endl; - return new BinarySemaphore(); - } -} - -SemaphoreIF* SemaphoreFactory::createCountingSemaphore(uint8_t maxCount, - uint8_t initCount, uint32_t argument) { - if(argument == USE_REGULAR_SEMAPHORES) { - return new CountingSemaphore(maxCount, initCount); - } - else if(argument == USE_TASK_NOTIFICATIONS) { - return new CountingSemaphoreUsingTask(maxCount, initCount); - } - else { - sif::warning << "SemaphoreFactory: Invalid argument, return regular" - "binary semaphore" << std::endl; - return new CountingSemaphore(maxCount, initCount); - } - -} - -void SemaphoreFactory::deleteSemaphore(SemaphoreIF* semaphore) { - delete semaphore; -} +#include "../../osal/FreeRTOS/BinarySemaphore.h" +#include "../../osal/FreeRTOS/BinSemaphUsingTask.h" +#include "../../osal/FreeRTOS/CountingSemaphore.h" +#include "../../osal/FreeRTOS/CountingSemaphUsingTask.h" +#include "../../tasks/SemaphoreFactory.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" + +SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr; +const uint32_t SemaphoreIF::POLLING = 0; +const uint32_t SemaphoreIF::BLOCKING = portMAX_DELAY; + +static const uint32_t USE_REGULAR_SEMAPHORES = 0; +static const uint32_t USE_TASK_NOTIFICATIONS = 1; + +SemaphoreFactory::SemaphoreFactory() { +} + +SemaphoreFactory::~SemaphoreFactory() { + delete factoryInstance; +} + +SemaphoreFactory* SemaphoreFactory::instance() { + if (factoryInstance == nullptr){ + factoryInstance = new SemaphoreFactory(); + } + return SemaphoreFactory::factoryInstance; +} + +SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t argument) { + if(argument == USE_REGULAR_SEMAPHORES) { + return new BinarySemaphore(); + } + else if(argument == USE_TASK_NOTIFICATIONS) { + return new BinarySemaphoreUsingTask(); + } + else { + sif::warning << "SemaphoreFactory: Invalid argument, return regular" + "binary semaphore" << std::endl; + return new BinarySemaphore(); + } +} + +SemaphoreIF* SemaphoreFactory::createCountingSemaphore(uint8_t maxCount, + uint8_t initCount, uint32_t argument) { + if(argument == USE_REGULAR_SEMAPHORES) { + return new CountingSemaphore(maxCount, initCount); + } + else if(argument == USE_TASK_NOTIFICATIONS) { + return new CountingSemaphoreUsingTask(maxCount, initCount); + } + else { + sif::warning << "SemaphoreFactory: Invalid argument, return regular" + "binary semaphore" << std::endl; + return new CountingSemaphore(maxCount, initCount); + } + +} + +void SemaphoreFactory::deleteSemaphore(SemaphoreIF* semaphore) { + delete semaphore; +} diff --git a/osal/FreeRTOS/TaskFactory.cpp b/osal/FreeRTOS/TaskFactory.cpp index 68866f39..b68b05b3 100644 --- a/osal/FreeRTOS/TaskFactory.cpp +++ b/osal/FreeRTOS/TaskFactory.cpp @@ -1,53 +1,53 @@ -#include -#include - -#include "PeriodicTask.h" -#include "FixedTimeslotTask.h" - - -TaskFactory* TaskFactory::factoryInstance = new TaskFactory(); - -TaskFactory::~TaskFactory() { -} - -TaskFactory* TaskFactory::instance() { - return TaskFactory::factoryInstance; -} - -PeriodicTaskIF* TaskFactory::createPeriodicTask(TaskName name_, - TaskPriority taskPriority_, TaskStackSize stackSize_, - TaskPeriod period_, - TaskDeadlineMissedFunction deadLineMissedFunction_) { - return dynamic_cast(new PeriodicTask(name_, taskPriority_, - stackSize_, period_, deadLineMissedFunction_)); -} - -/** - * Keep in Mind that you need to call before this vTaskStartScheduler()! - */ -FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(TaskName name_, - TaskPriority taskPriority_, TaskStackSize stackSize_, - TaskPeriod period_, - TaskDeadlineMissedFunction deadLineMissedFunction_) { - return dynamic_cast(new FixedTimeslotTask(name_, - taskPriority_,stackSize_, period_, deadLineMissedFunction_)); -} - -ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) { - if (task == nullptr) { - //delete self - vTaskDelete(nullptr); - return HasReturnvaluesIF::RETURN_OK; - } else { - //TODO not implemented - return HasReturnvaluesIF::RETURN_FAILED; - } -} - -ReturnValue_t TaskFactory::delayTask(uint32_t delayMs) { - vTaskDelay(pdMS_TO_TICKS(delayMs)); - return HasReturnvaluesIF::RETURN_OK; -} - -TaskFactory::TaskFactory() { -} +#include "../../tasks/TaskFactory.h" +#include "../../returnvalues/HasReturnvaluesIF.h" + +#include "PeriodicTask.h" +#include "FixedTimeslotTask.h" + + +TaskFactory* TaskFactory::factoryInstance = new TaskFactory(); + +TaskFactory::~TaskFactory() { +} + +TaskFactory* TaskFactory::instance() { + return TaskFactory::factoryInstance; +} + +PeriodicTaskIF* TaskFactory::createPeriodicTask(TaskName name_, + TaskPriority taskPriority_, TaskStackSize stackSize_, + TaskPeriod period_, + TaskDeadlineMissedFunction deadLineMissedFunction_) { + return dynamic_cast(new PeriodicTask(name_, taskPriority_, + stackSize_, period_, deadLineMissedFunction_)); +} + +/** + * Keep in Mind that you need to call before this vTaskStartScheduler()! + */ +FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(TaskName name_, + TaskPriority taskPriority_, TaskStackSize stackSize_, + TaskPeriod period_, + TaskDeadlineMissedFunction deadLineMissedFunction_) { + return dynamic_cast(new FixedTimeslotTask(name_, + taskPriority_,stackSize_, period_, deadLineMissedFunction_)); +} + +ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) { + if (task == nullptr) { + //delete self + vTaskDelete(nullptr); + return HasReturnvaluesIF::RETURN_OK; + } else { + //TODO not implemented + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +ReturnValue_t TaskFactory::delayTask(uint32_t delayMs) { + vTaskDelay(pdMS_TO_TICKS(delayMs)); + return HasReturnvaluesIF::RETURN_OK; +} + +TaskFactory::TaskFactory() { +} diff --git a/osal/FreeRTOS/TaskManagement.cpp b/osal/FreeRTOS/TaskManagement.cpp index ff552adb..16682d36 100644 --- a/osal/FreeRTOS/TaskManagement.cpp +++ b/osal/FreeRTOS/TaskManagement.cpp @@ -1,11 +1,11 @@ -#include - +#include "../../osal/FreeRTOS/TaskManagement.h" + void TaskManagement::vRequestContextSwitchFromTask() { vTaskDelay(0); } - + void TaskManagement::requestContextSwitch( - CallContext callContext = CallContext::TASK) { + CallContext callContext = CallContext::TASK) { if(callContext == CallContext::ISR) { // This function depends on the partmacro.h definition for the specific device vRequestContextSwitchFromISR(); @@ -13,7 +13,7 @@ void TaskManagement::requestContextSwitch( vRequestContextSwitchFromTask(); } } - + TaskHandle_t TaskManagement::getCurrentTaskHandle() { return xTaskGetCurrentTaskHandle(); } @@ -21,4 +21,4 @@ TaskHandle_t TaskManagement::getCurrentTaskHandle() { size_t TaskManagement::getTaskStackHighWatermark( TaskHandle_t task) { return uxTaskGetStackHighWaterMark(task) * sizeof(StackType_t); -} +} diff --git a/osal/FreeRTOS/TaskManagement.h b/osal/FreeRTOS/TaskManagement.h index 62c68331..43003d76 100644 --- a/osal/FreeRTOS/TaskManagement.h +++ b/osal/FreeRTOS/TaskManagement.h @@ -1,14 +1,14 @@ #ifndef FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ #define FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ -#include +#include "../../returnvalues/HasReturnvaluesIF.h" extern "C" { #include #include } #include - + /** * Architecture dependant portmacro.h function call. * Should be implemented in bsp. @@ -17,9 +17,9 @@ extern void vRequestContextSwitchFromISR(); /*! * Used by functions to tell if they are being called from - * within an ISR or from a regular task. This is required because FreeRTOS + * within an ISR or from a regular task. This is required because FreeRTOS * has different functions for handling semaphores and messages from within - * an ISR and task. + * an ISR and task. */ enum class CallContext { TASK = 0x00,//!< task_context @@ -29,19 +29,19 @@ enum class CallContext { class TaskManagement { public: - /** + /** * @brief In this function, a function dependant on the portmacro.h header * function calls to request a context switch can be specified. * This can be used if sending to the queue from an ISR caused a task - * to unblock and a context switch is required. + * to unblock and a context switch is required. */ static void requestContextSwitch(CallContext callContext); /** * If task preemption in FreeRTOS is disabled, a context switch * can be requested manually by calling this function. - */ - static void vRequestContextSwitchFromTask(void); + */ + static void vRequestContextSwitchFromTask(void); /** * @return The current task handle @@ -56,9 +56,9 @@ public: * E.g. on a 32 bit machine, a value of 200 means 800 bytes. * @return Smallest value of stack remaining since the task was started in * words. - */ + */ static size_t getTaskStackHighWatermark( - TaskHandle_t task = nullptr); + TaskHandle_t task = nullptr); }; #endif /* FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ */ diff --git a/osal/FreeRTOS/Timekeeper.cpp b/osal/FreeRTOS/Timekeeper.cpp index 643b2747..f7a3c8f8 100644 --- a/osal/FreeRTOS/Timekeeper.cpp +++ b/osal/FreeRTOS/Timekeeper.cpp @@ -1,41 +1,41 @@ -#include - -#include "FreeRTOSConfig.h" - -Timekeeper * Timekeeper::myinstance = nullptr; - -Timekeeper::Timekeeper() : offset( { 0, 0 } ) {} - -Timekeeper::~Timekeeper() {} - -const timeval& Timekeeper::getOffset() const { - return offset; -} - -Timekeeper* Timekeeper::instance() { - if (myinstance == nullptr) { - myinstance = new Timekeeper(); - } - return myinstance; -} - -void Timekeeper::setOffset(const timeval& offset) { - this->offset = offset; -} - -timeval Timekeeper::ticksToTimeval(TickType_t ticks) { - timeval uptime; - uptime.tv_sec = ticks / configTICK_RATE_HZ; - - //TODO explain, think about overflow - uint32_t subsecondTicks = ticks % configTICK_RATE_HZ; - uint64_t usecondTicks = subsecondTicks * 1000000; - - uptime.tv_usec = usecondTicks / configTICK_RATE_HZ; - - return uptime; -} - -TickType_t Timekeeper::getTicks() { - return xTaskGetTickCount(); -} +#include "../../osal/FreeRTOS/Timekeeper.h" + +#include "FreeRTOSConfig.h" + +Timekeeper * Timekeeper::myinstance = nullptr; + +Timekeeper::Timekeeper() : offset( { 0, 0 } ) {} + +Timekeeper::~Timekeeper() {} + +const timeval& Timekeeper::getOffset() const { + return offset; +} + +Timekeeper* Timekeeper::instance() { + if (myinstance == nullptr) { + myinstance = new Timekeeper(); + } + return myinstance; +} + +void Timekeeper::setOffset(const timeval& offset) { + this->offset = offset; +} + +timeval Timekeeper::ticksToTimeval(TickType_t ticks) { + timeval uptime; + uptime.tv_sec = ticks / configTICK_RATE_HZ; + + //TODO explain, think about overflow + uint32_t subsecondTicks = ticks % configTICK_RATE_HZ; + uint64_t usecondTicks = subsecondTicks * 1000000; + + uptime.tv_usec = usecondTicks / configTICK_RATE_HZ; + + return uptime; +} + +TickType_t Timekeeper::getTicks() { + return xTaskGetTickCount(); +} diff --git a/osal/FreeRTOS/Timekeeper.h b/osal/FreeRTOS/Timekeeper.h index 7d3ca22b..fc1664e2 100644 --- a/osal/FreeRTOS/Timekeeper.h +++ b/osal/FreeRTOS/Timekeeper.h @@ -1,40 +1,40 @@ -#ifndef FRAMEWORK_OSAL_FREERTOS_TIMEKEEPER_H_ -#define FRAMEWORK_OSAL_FREERTOS_TIMEKEEPER_H_ - -#include - -#include -#include - - -/** - * A Class to basically store the time difference between uptime and UTC - * so the "time-agnostic" FreeRTOS can keep an UTC Time - * - * Implemented as Singleton, so the FSFW Clock Implementation (see Clock.cpp) - * can use it without having a member. - */ - -class Timekeeper { -private: - Timekeeper(); - - timeval offset; - - static Timekeeper * myinstance; -public: - static Timekeeper * instance(); - virtual ~Timekeeper(); - - static timeval ticksToTimeval(TickType_t ticks); - /** - * Get elapsed time in system ticks. - * @return - */ - static TickType_t getTicks(); - - const timeval& getOffset() const; - void setOffset(const timeval& offset); -}; - -#endif /* FRAMEWORK_OSAL_FREERTOS_TIMEKEEPER_H_ */ +#ifndef FRAMEWORK_OSAL_FREERTOS_TIMEKEEPER_H_ +#define FRAMEWORK_OSAL_FREERTOS_TIMEKEEPER_H_ + +#include "../../timemanager/Clock.h" + +#include +#include + + +/** + * A Class to basically store the time difference between uptime and UTC + * so the "time-agnostic" FreeRTOS can keep an UTC Time + * + * Implemented as Singleton, so the FSFW Clock Implementation (see Clock.cpp) + * can use it without having a member. + */ + +class Timekeeper { +private: + Timekeeper(); + + timeval offset; + + static Timekeeper * myinstance; +public: + static Timekeeper * instance(); + virtual ~Timekeeper(); + + static timeval ticksToTimeval(TickType_t ticks); + /** + * Get elapsed time in system ticks. + * @return + */ + static TickType_t getTicks(); + + const timeval& getOffset() const; + void setOffset(const timeval& offset); +}; + +#endif /* FRAMEWORK_OSAL_FREERTOS_TIMEKEEPER_H_ */ diff --git a/osal/InternalErrorCodes.h b/osal/InternalErrorCodes.h index 5419fd94..d89eb230 100644 --- a/osal/InternalErrorCodes.h +++ b/osal/InternalErrorCodes.h @@ -1,39 +1,39 @@ -#ifndef INTERNALERRORCODES_H_ -#define INTERNALERRORCODES_H_ - -#include - -class InternalErrorCodes { -public: - static const uint8_t INTERFACE_ID = CLASS_ID::INTERNAL_ERROR_CODES; - -static const ReturnValue_t NO_CONFIGURATION_TABLE = MAKE_RETURN_CODE(0x01 ); -static const ReturnValue_t NO_CPU_TABLE = MAKE_RETURN_CODE(0x02 ); -static const ReturnValue_t INVALID_WORKSPACE_ADDRESS = MAKE_RETURN_CODE(0x03 ); -static const ReturnValue_t TOO_LITTLE_WORKSPACE = MAKE_RETURN_CODE(0x04 ); -static const ReturnValue_t WORKSPACE_ALLOCATION = MAKE_RETURN_CODE(0x05 ); -static const ReturnValue_t INTERRUPT_STACK_TOO_SMALL = MAKE_RETURN_CODE(0x06 ); -static const ReturnValue_t THREAD_EXITTED = MAKE_RETURN_CODE(0x07 ); -static const ReturnValue_t INCONSISTENT_MP_INFORMATION = MAKE_RETURN_CODE(0x08 ); -static const ReturnValue_t INVALID_NODE = MAKE_RETURN_CODE(0x09 ); -static const ReturnValue_t NO_MPCI = MAKE_RETURN_CODE(0x0a ); -static const ReturnValue_t BAD_PACKET = MAKE_RETURN_CODE(0x0b ); -static const ReturnValue_t OUT_OF_PACKETS = MAKE_RETURN_CODE(0x0c ); -static const ReturnValue_t OUT_OF_GLOBAL_OBJECTS = MAKE_RETURN_CODE(0x0d ); -static const ReturnValue_t OUT_OF_PROXIES = MAKE_RETURN_CODE(0x0e ); -static const ReturnValue_t INVALID_GLOBAL_ID = MAKE_RETURN_CODE(0x0f ); -static const ReturnValue_t BAD_STACK_HOOK = MAKE_RETURN_CODE(0x10 ); -static const ReturnValue_t BAD_ATTRIBUTES = MAKE_RETURN_CODE(0x11 ); -static const ReturnValue_t IMPLEMENTATION_KEY_CREATE_INCONSISTENCY = MAKE_RETURN_CODE(0x12 ); -static const ReturnValue_t IMPLEMENTATION_BLOCKING_OPERATION_CANCEL = MAKE_RETURN_CODE(0x13 ); -static const ReturnValue_t MUTEX_OBTAIN_FROM_BAD_STATE = MAKE_RETURN_CODE(0x14 ); -static const ReturnValue_t UNLIMITED_AND_MAXIMUM_IS_0 = MAKE_RETURN_CODE(0x15 ); - - virtual ~InternalErrorCodes(); - - static ReturnValue_t translate(uint8_t code); -private: - InternalErrorCodes(); -}; - -#endif /* INTERNALERRORCODES_H_ */ +#ifndef INTERNALERRORCODES_H_ +#define INTERNALERRORCODES_H_ + +#include "../returnvalues/HasReturnvaluesIF.h" + +class InternalErrorCodes { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::INTERNAL_ERROR_CODES; + +static const ReturnValue_t NO_CONFIGURATION_TABLE = MAKE_RETURN_CODE(0x01 ); +static const ReturnValue_t NO_CPU_TABLE = MAKE_RETURN_CODE(0x02 ); +static const ReturnValue_t INVALID_WORKSPACE_ADDRESS = MAKE_RETURN_CODE(0x03 ); +static const ReturnValue_t TOO_LITTLE_WORKSPACE = MAKE_RETURN_CODE(0x04 ); +static const ReturnValue_t WORKSPACE_ALLOCATION = MAKE_RETURN_CODE(0x05 ); +static const ReturnValue_t INTERRUPT_STACK_TOO_SMALL = MAKE_RETURN_CODE(0x06 ); +static const ReturnValue_t THREAD_EXITTED = MAKE_RETURN_CODE(0x07 ); +static const ReturnValue_t INCONSISTENT_MP_INFORMATION = MAKE_RETURN_CODE(0x08 ); +static const ReturnValue_t INVALID_NODE = MAKE_RETURN_CODE(0x09 ); +static const ReturnValue_t NO_MPCI = MAKE_RETURN_CODE(0x0a ); +static const ReturnValue_t BAD_PACKET = MAKE_RETURN_CODE(0x0b ); +static const ReturnValue_t OUT_OF_PACKETS = MAKE_RETURN_CODE(0x0c ); +static const ReturnValue_t OUT_OF_GLOBAL_OBJECTS = MAKE_RETURN_CODE(0x0d ); +static const ReturnValue_t OUT_OF_PROXIES = MAKE_RETURN_CODE(0x0e ); +static const ReturnValue_t INVALID_GLOBAL_ID = MAKE_RETURN_CODE(0x0f ); +static const ReturnValue_t BAD_STACK_HOOK = MAKE_RETURN_CODE(0x10 ); +static const ReturnValue_t BAD_ATTRIBUTES = MAKE_RETURN_CODE(0x11 ); +static const ReturnValue_t IMPLEMENTATION_KEY_CREATE_INCONSISTENCY = MAKE_RETURN_CODE(0x12 ); +static const ReturnValue_t IMPLEMENTATION_BLOCKING_OPERATION_CANCEL = MAKE_RETURN_CODE(0x13 ); +static const ReturnValue_t MUTEX_OBTAIN_FROM_BAD_STATE = MAKE_RETURN_CODE(0x14 ); +static const ReturnValue_t UNLIMITED_AND_MAXIMUM_IS_0 = MAKE_RETURN_CODE(0x15 ); + + virtual ~InternalErrorCodes(); + + static ReturnValue_t translate(uint8_t code); +private: + InternalErrorCodes(); +}; + +#endif /* INTERNALERRORCODES_H_ */ diff --git a/osal/host/Clock.cpp b/osal/host/Clock.cpp index 57f2572b..52d0d5f0 100644 --- a/osal/host/Clock.cpp +++ b/osal/host/Clock.cpp @@ -1,227 +1,227 @@ -#include -#include - -#include -#if defined(WIN32) -#include -#elif defined(LINUX) -#include -#endif - -uint16_t Clock::leapSeconds = 0; -MutexIF* Clock::timeMutex = NULL; - -using SystemClock = std::chrono::system_clock; - -uint32_t Clock::getTicksPerSecond(void){ - sif::warning << "Clock::getTicksPerSecond: not implemented yet" << std::endl; - return 0; - //return CLOCKS_PER_SEC; - //uint32_t ticks = sysconf(_SC_CLK_TCK); - //return ticks; -} - -ReturnValue_t Clock::setClock(const TimeOfDay_t* time) { - // do some magic with chrono - sif::warning << "Clock::setClock: not implemented yet" << std::endl; - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t Clock::setClock(const timeval* time) { - // do some magic with chrono -#if defined(WIN32) - return HasReturnvaluesIF::RETURN_OK; -#elif defined(LINUX) - return HasReturnvaluesIF::RETURN_OK; -#else - -#endif - sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; -} - -ReturnValue_t Clock::getClock_timeval(timeval* time) { -#if defined(WIN32) - auto now = std::chrono::system_clock::now(); - auto secondsChrono = std::chrono::time_point_cast(now); - auto epoch = now.time_since_epoch(); - time->tv_sec = std::chrono::duration_cast(epoch).count(); - auto fraction = now - secondsChrono; - time->tv_usec = std::chrono::duration_cast( - fraction).count(); - return HasReturnvaluesIF::RETURN_OK; -#elif defined(LINUX) - timespec timeUnix; - int status = clock_gettime(CLOCK_REALTIME,&timeUnix); - if(status!=0){ - return HasReturnvaluesIF::RETURN_FAILED; - } - time->tv_sec = timeUnix.tv_sec; - time->tv_usec = timeUnix.tv_nsec / 1000.0; - return HasReturnvaluesIF::RETURN_OK; -#else - sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; -#endif - -} - -ReturnValue_t Clock::getClock_usecs(uint64_t* time) { - // do some magic with chrono - sif::warning << "Clock::gerClock_usecs: not implemented yet" << std::endl; - return HasReturnvaluesIF::RETURN_OK; -} - -timeval Clock::getUptime() { - timeval timeval; -#if defined(WIN32) - auto uptime = std::chrono::milliseconds(GetTickCount64()); - auto secondsChrono = std::chrono::duration_cast(uptime); - timeval.tv_sec = secondsChrono.count(); - auto fraction = uptime - secondsChrono; - timeval.tv_usec = std::chrono::duration_cast( - fraction).count(); -#elif defined(LINUX) - double uptimeSeconds; - if (std::ifstream("/proc/uptime", std::ios::in) >> uptimeSeconds) - { - // value is rounded down automatically - timeval.tv_sec = uptimeSeconds; - timeval.tv_usec = uptimeSeconds *(double) 1e6 - (timeval.tv_sec *1e6); - } -#else - sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl; -#endif - return timeval; -} - -ReturnValue_t Clock::getUptime(timeval* uptime) { - *uptime = getUptime(); - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) { - timeval uptime = getUptime(); - *uptimeMs = uptime.tv_sec * 1000 + uptime.tv_usec / 1000; - return HasReturnvaluesIF::RETURN_OK; -} - - -ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) { - // do some magic with chrono (C++20!) - // Right now, the library doesn't have the new features yet. - // so we work around that for now. - auto now = SystemClock::now(); - auto seconds = std::chrono::time_point_cast(now); - auto fraction = now - seconds; - time_t tt = SystemClock::to_time_t(now); - struct tm* timeInfo; - timeInfo = gmtime(&tt); - time->year = timeInfo->tm_year + 1900; - time->month = timeInfo->tm_mon+1; - time->day = timeInfo->tm_mday; - time->hour = timeInfo->tm_hour; - time->minute = timeInfo->tm_min; - time->second = timeInfo->tm_sec; - auto usecond = std::chrono::duration_cast(fraction); - time->usecond = usecond.count(); - - //sif::warning << "Clock::getDateAndTime: not implemented yet" << std::endl; - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from, - timeval* to) { - struct tm time_tm; - - time_tm.tm_year = from->year - 1900; - time_tm.tm_mon = from->month - 1; - time_tm.tm_mday = from->day; - - time_tm.tm_hour = from->hour; - time_tm.tm_min = from->minute; - time_tm.tm_sec = from->second; - - time_t seconds = mktime(&time_tm); - - to->tv_sec = seconds; - to->tv_usec = from->usecond; - //Fails in 2038.. - return HasReturnvaluesIF::RETURN_OK; - sif::warning << "Clock::convertTimeBla: not implemented yet" << std::endl; - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) { - *JD2000 = (time.tv_sec - 946728000. + time.tv_usec / 1000000.) / 24. - / 3600.; - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) { - //SHOULDDO: works not for dates in the past (might have less leap seconds) - if (timeMutex == NULL) { - return HasReturnvaluesIF::RETURN_FAILED; - } - - uint16_t leapSeconds; - ReturnValue_t result = getLeapSeconds(&leapSeconds); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - timeval leapSeconds_timeval = { 0, 0 }; - leapSeconds_timeval.tv_sec = leapSeconds; - - //initial offset between UTC and TAI - timeval UTCtoTAI1972 = { 10, 0 }; - - timeval TAItoTT = { 32, 184000 }; - - *tt = utc + leapSeconds_timeval + UTCtoTAI1972 + TAItoTT; - - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) { - if(checkOrCreateClockMutex()!=HasReturnvaluesIF::RETURN_OK){ - return HasReturnvaluesIF::RETURN_FAILED; - } - ReturnValue_t result = timeMutex->lockMutex(MutexIF::BLOCKING); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - leapSeconds = leapSeconds_; - - result = timeMutex->unlockMutex(); - return result; -} - -ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) { - if(timeMutex == nullptr){ - return HasReturnvaluesIF::RETURN_FAILED; - } - ReturnValue_t result = timeMutex->lockMutex(MutexIF::BLOCKING); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - *leapSeconds_ = leapSeconds; - - result = timeMutex->unlockMutex(); - return result; -} - -ReturnValue_t Clock::checkOrCreateClockMutex(){ - if(timeMutex == nullptr){ - MutexFactory* mutexFactory = MutexFactory::instance(); - if (mutexFactory == nullptr) { - return HasReturnvaluesIF::RETURN_FAILED; - } - timeMutex = mutexFactory->createMutex(); - if (timeMutex == nullptr) { - return HasReturnvaluesIF::RETURN_FAILED; - } - } - return HasReturnvaluesIF::RETURN_OK; -} +#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "../../timemanager/Clock.h" + +#include +#if defined(WIN32) +#include +#elif defined(LINUX) +#include +#endif + +uint16_t Clock::leapSeconds = 0; +MutexIF* Clock::timeMutex = NULL; + +using SystemClock = std::chrono::system_clock; + +uint32_t Clock::getTicksPerSecond(void){ + sif::warning << "Clock::getTicksPerSecond: not implemented yet" << std::endl; + return 0; + //return CLOCKS_PER_SEC; + //uint32_t ticks = sysconf(_SC_CLK_TCK); + //return ticks; +} + +ReturnValue_t Clock::setClock(const TimeOfDay_t* time) { + // do some magic with chrono + sif::warning << "Clock::setClock: not implemented yet" << std::endl; + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Clock::setClock(const timeval* time) { + // do some magic with chrono +#if defined(WIN32) + return HasReturnvaluesIF::RETURN_OK; +#elif defined(LINUX) + return HasReturnvaluesIF::RETURN_OK; +#else + +#endif + sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; +} + +ReturnValue_t Clock::getClock_timeval(timeval* time) { +#if defined(WIN32) + auto now = std::chrono::system_clock::now(); + auto secondsChrono = std::chrono::time_point_cast(now); + auto epoch = now.time_since_epoch(); + time->tv_sec = std::chrono::duration_cast(epoch).count(); + auto fraction = now - secondsChrono; + time->tv_usec = std::chrono::duration_cast( + fraction).count(); + return HasReturnvaluesIF::RETURN_OK; +#elif defined(LINUX) + timespec timeUnix; + int status = clock_gettime(CLOCK_REALTIME,&timeUnix); + if(status!=0){ + return HasReturnvaluesIF::RETURN_FAILED; + } + time->tv_sec = timeUnix.tv_sec; + time->tv_usec = timeUnix.tv_nsec / 1000.0; + return HasReturnvaluesIF::RETURN_OK; +#else + sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; +#endif + +} + +ReturnValue_t Clock::getClock_usecs(uint64_t* time) { + // do some magic with chrono + sif::warning << "Clock::gerClock_usecs: not implemented yet" << std::endl; + return HasReturnvaluesIF::RETURN_OK; +} + +timeval Clock::getUptime() { + timeval timeval; +#if defined(WIN32) + auto uptime = std::chrono::milliseconds(GetTickCount64()); + auto secondsChrono = std::chrono::duration_cast(uptime); + timeval.tv_sec = secondsChrono.count(); + auto fraction = uptime - secondsChrono; + timeval.tv_usec = std::chrono::duration_cast( + fraction).count(); +#elif defined(LINUX) + double uptimeSeconds; + if (std::ifstream("/proc/uptime", std::ios::in) >> uptimeSeconds) + { + // value is rounded down automatically + timeval.tv_sec = uptimeSeconds; + timeval.tv_usec = uptimeSeconds *(double) 1e6 - (timeval.tv_sec *1e6); + } +#else + sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl; +#endif + return timeval; +} + +ReturnValue_t Clock::getUptime(timeval* uptime) { + *uptime = getUptime(); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) { + timeval uptime = getUptime(); + *uptimeMs = uptime.tv_sec * 1000 + uptime.tv_usec / 1000; + return HasReturnvaluesIF::RETURN_OK; +} + + +ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) { + // do some magic with chrono (C++20!) + // Right now, the library doesn't have the new features yet. + // so we work around that for now. + auto now = SystemClock::now(); + auto seconds = std::chrono::time_point_cast(now); + auto fraction = now - seconds; + time_t tt = SystemClock::to_time_t(now); + struct tm* timeInfo; + timeInfo = gmtime(&tt); + time->year = timeInfo->tm_year + 1900; + time->month = timeInfo->tm_mon+1; + time->day = timeInfo->tm_mday; + time->hour = timeInfo->tm_hour; + time->minute = timeInfo->tm_min; + time->second = timeInfo->tm_sec; + auto usecond = std::chrono::duration_cast(fraction); + time->usecond = usecond.count(); + + //sif::warning << "Clock::getDateAndTime: not implemented yet" << std::endl; + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from, + timeval* to) { + struct tm time_tm; + + time_tm.tm_year = from->year - 1900; + time_tm.tm_mon = from->month - 1; + time_tm.tm_mday = from->day; + + time_tm.tm_hour = from->hour; + time_tm.tm_min = from->minute; + time_tm.tm_sec = from->second; + + time_t seconds = mktime(&time_tm); + + to->tv_sec = seconds; + to->tv_usec = from->usecond; + //Fails in 2038.. + return HasReturnvaluesIF::RETURN_OK; + sif::warning << "Clock::convertTimeBla: not implemented yet" << std::endl; + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) { + *JD2000 = (time.tv_sec - 946728000. + time.tv_usec / 1000000.) / 24. + / 3600.; + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) { + //SHOULDDO: works not for dates in the past (might have less leap seconds) + if (timeMutex == NULL) { + return HasReturnvaluesIF::RETURN_FAILED; + } + + uint16_t leapSeconds; + ReturnValue_t result = getLeapSeconds(&leapSeconds); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + timeval leapSeconds_timeval = { 0, 0 }; + leapSeconds_timeval.tv_sec = leapSeconds; + + //initial offset between UTC and TAI + timeval UTCtoTAI1972 = { 10, 0 }; + + timeval TAItoTT = { 32, 184000 }; + + *tt = utc + leapSeconds_timeval + UTCtoTAI1972 + TAItoTT; + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) { + if(checkOrCreateClockMutex()!=HasReturnvaluesIF::RETURN_OK){ + return HasReturnvaluesIF::RETURN_FAILED; + } + ReturnValue_t result = timeMutex->lockMutex(MutexIF::BLOCKING); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + leapSeconds = leapSeconds_; + + result = timeMutex->unlockMutex(); + return result; +} + +ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) { + if(timeMutex == nullptr){ + return HasReturnvaluesIF::RETURN_FAILED; + } + ReturnValue_t result = timeMutex->lockMutex(MutexIF::BLOCKING); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + *leapSeconds_ = leapSeconds; + + result = timeMutex->unlockMutex(); + return result; +} + +ReturnValue_t Clock::checkOrCreateClockMutex(){ + if(timeMutex == nullptr){ + MutexFactory* mutexFactory = MutexFactory::instance(); + if (mutexFactory == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + timeMutex = mutexFactory->createMutex(); + if (timeMutex == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + } + return HasReturnvaluesIF::RETURN_OK; +} diff --git a/osal/host/FixedTimeslotTask.cpp b/osal/host/FixedTimeslotTask.cpp index dac399f6..1999c9e6 100644 --- a/osal/host/FixedTimeslotTask.cpp +++ b/osal/host/FixedTimeslotTask.cpp @@ -1,191 +1,191 @@ -#include - -#include -#include -#include - -#include -#include - -#include -#include - -#if defined(WIN32) -#include -#elif defined(LINUX) -#include -#endif - -FixedTimeslotTask::FixedTimeslotTask(const char *name, TaskPriority setPriority, - TaskStackSize setStack, TaskPeriod setPeriod, - void (*setDeadlineMissedFunc)()) : - started(false), pollingSeqTable(setPeriod*1000), taskName(name), - period(setPeriod), deadlineMissedFunc(setDeadlineMissedFunc) { - // It is propably possible to set task priorities by using the native - // task handles for Windows / Linux - mainThread = std::thread(&FixedTimeslotTask::taskEntryPoint, this, this); -#if defined(WIN32) - /* List of possible priority classes: - * https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ - * nf-processthreadsapi-setpriorityclass - * And respective thread priority numbers: - * https://docs.microsoft.com/en-us/windows/ - * win32/procthread/scheduling-priorities */ - int result = SetPriorityClass( - reinterpret_cast(mainThread.native_handle()), - ABOVE_NORMAL_PRIORITY_CLASS); - if(result != 0) { - sif::error << "FixedTimeslotTask: Windows SetPriorityClass failed with code " - << GetLastError() << std::endl; - } - result = SetThreadPriority( - reinterpret_cast(mainThread.native_handle()), - THREAD_PRIORITY_NORMAL); - if(result != 0) { - sif::error << "FixedTimeslotTask: Windows SetPriorityClass failed with code " - << GetLastError() << std::endl; - } -#elif defined(LINUX) - // we can just copy and paste the code from linux here. -#endif -} - -FixedTimeslotTask::~FixedTimeslotTask(void) { - //Do not delete objects, we were responsible for ptrs only. - terminateThread = true; - if(mainThread.joinable()) { - mainThread.join(); - } - delete this; -} - -void FixedTimeslotTask::taskEntryPoint(void* argument) { - FixedTimeslotTask *originalTask(reinterpret_cast(argument)); - - if (not originalTask->started) { - // we have to suspend/block here until the task is started. - // if semaphores are implemented, use them here. - std::unique_lock lock(initMutex); - initCondition.wait(lock); - } - - this->taskFunctionality(); - sif::debug << "FixedTimeslotTask::taskEntryPoint: " - "Returned from taskFunctionality." << std::endl; -} - -ReturnValue_t FixedTimeslotTask::startTask() { - started = true; - - // Notify task to start. - std::lock_guard lock(initMutex); - initCondition.notify_one(); - - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) { - std::this_thread::sleep_for(std::chrono::milliseconds(ms)); - return HasReturnvaluesIF::RETURN_OK; -} - -void FixedTimeslotTask::taskFunctionality() { - // A local iterator for the Polling Sequence Table is created to - // find the start time for the first entry. - FixedSlotSequence::SlotListIter slotListIter = pollingSeqTable.current; - // Get start time for first entry. - chron_ms interval(slotListIter->pollingTimeMs); - auto currentStartTime { - std::chrono::duration_cast( - std::chrono::system_clock::now().time_since_epoch()) - }; - if(interval.count() > 0) { - delayForInterval(¤tStartTime, interval); - } - - /* Enter the loop that defines the task behavior. */ - for (;;) { - if(terminateThread.load()) { - break; - } - //The component for this slot is executed and the next one is chosen. - this->pollingSeqTable.executeAndAdvance(); - if (not pollingSeqTable.slotFollowsImmediately()) { - // we need to wait before executing the current slot - //this gives us the time to wait: - interval = chron_ms(this->pollingSeqTable.getIntervalToPreviousSlotMs()); - delayForInterval(¤tStartTime, interval); - //TODO deadline missed check - } - } -} - -ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, - uint32_t slotTimeMs, int8_t executionStep) { - if (objectManager->get(componentId) != nullptr) { - pollingSeqTable.addSlot(componentId, slotTimeMs, executionStep, this); - return HasReturnvaluesIF::RETURN_OK; - } - - sif::error << "Component " << std::hex << componentId << - " not found, not adding it to pst" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; -} - -ReturnValue_t FixedTimeslotTask::checkSequence() const { - return pollingSeqTable.checkSequence(); -} - -uint32_t FixedTimeslotTask::getPeriodMs() const { - return period * 1000; -} - -bool FixedTimeslotTask::delayForInterval(chron_ms * previousWakeTimeMs, - const chron_ms interval) { - bool shouldDelay = false; - //Get current wakeup time - auto currentStartTime = - std::chrono::duration_cast( - std::chrono::system_clock::now().time_since_epoch()); - /* Generate the tick time at which the task wants to wake. */ - auto nextTimeToWake_ms = (*previousWakeTimeMs) + interval; - - if (currentStartTime < *previousWakeTimeMs) { - /* The tick count has overflowed since this function was - lasted called. In this case the only time we should ever - actually delay is if the wake time has also overflowed, - and the wake time is greater than the tick time. When this - is the case it is as if neither time had overflowed. */ - if ((nextTimeToWake_ms < *previousWakeTimeMs) - && (nextTimeToWake_ms > currentStartTime)) { - shouldDelay = true; - } - } else { - /* The tick time has not overflowed. In this case we will - delay if either the wake time has overflowed, and/or the - tick time is less than the wake time. */ - if ((nextTimeToWake_ms < *previousWakeTimeMs) - || (nextTimeToWake_ms > currentStartTime)) { - shouldDelay = true; - } - } - - /* Update the wake time ready for the next call. */ - - (*previousWakeTimeMs) = nextTimeToWake_ms; - - if (shouldDelay) { - auto sleepTime = std::chrono::duration_cast( - nextTimeToWake_ms - currentStartTime); - std::this_thread::sleep_for(sleepTime); - return true; - } - //We are shifting the time in case the deadline was missed like rtems - (*previousWakeTimeMs) = currentStartTime; - return false; - -} - - - - +#include "../../osal/host/FixedTimeslotTask.h" + +#include "../../ipc/MutexFactory.h" +#include "../../osal/host/Mutex.h" +#include "../../osal/host/FixedTimeslotTask.h" + +#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "../../tasks/ExecutableObjectIF.h" + +#include +#include + +#if defined(WIN32) +#include +#elif defined(LINUX) +#include +#endif + +FixedTimeslotTask::FixedTimeslotTask(const char *name, TaskPriority setPriority, + TaskStackSize setStack, TaskPeriod setPeriod, + void (*setDeadlineMissedFunc)()) : + started(false), pollingSeqTable(setPeriod*1000), taskName(name), + period(setPeriod), deadlineMissedFunc(setDeadlineMissedFunc) { + // It is propably possible to set task priorities by using the native + // task handles for Windows / Linux + mainThread = std::thread(&FixedTimeslotTask::taskEntryPoint, this, this); +#if defined(WIN32) + /* List of possible priority classes: + * https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ + * nf-processthreadsapi-setpriorityclass + * And respective thread priority numbers: + * https://docs.microsoft.com/en-us/windows/ + * win32/procthread/scheduling-priorities */ + int result = SetPriorityClass( + reinterpret_cast(mainThread.native_handle()), + ABOVE_NORMAL_PRIORITY_CLASS); + if(result != 0) { + sif::error << "FixedTimeslotTask: Windows SetPriorityClass failed with code " + << GetLastError() << std::endl; + } + result = SetThreadPriority( + reinterpret_cast(mainThread.native_handle()), + THREAD_PRIORITY_NORMAL); + if(result != 0) { + sif::error << "FixedTimeslotTask: Windows SetPriorityClass failed with code " + << GetLastError() << std::endl; + } +#elif defined(LINUX) + // we can just copy and paste the code from linux here. +#endif +} + +FixedTimeslotTask::~FixedTimeslotTask(void) { + //Do not delete objects, we were responsible for ptrs only. + terminateThread = true; + if(mainThread.joinable()) { + mainThread.join(); + } + delete this; +} + +void FixedTimeslotTask::taskEntryPoint(void* argument) { + FixedTimeslotTask *originalTask(reinterpret_cast(argument)); + + if (not originalTask->started) { + // we have to suspend/block here until the task is started. + // if semaphores are implemented, use them here. + std::unique_lock lock(initMutex); + initCondition.wait(lock); + } + + this->taskFunctionality(); + sif::debug << "FixedTimeslotTask::taskEntryPoint: " + "Returned from taskFunctionality." << std::endl; +} + +ReturnValue_t FixedTimeslotTask::startTask() { + started = true; + + // Notify task to start. + std::lock_guard lock(initMutex); + initCondition.notify_one(); + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) { + std::this_thread::sleep_for(std::chrono::milliseconds(ms)); + return HasReturnvaluesIF::RETURN_OK; +} + +void FixedTimeslotTask::taskFunctionality() { + // A local iterator for the Polling Sequence Table is created to + // find the start time for the first entry. + FixedSlotSequence::SlotListIter slotListIter = pollingSeqTable.current; + // Get start time for first entry. + chron_ms interval(slotListIter->pollingTimeMs); + auto currentStartTime { + std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()) + }; + if(interval.count() > 0) { + delayForInterval(¤tStartTime, interval); + } + + /* Enter the loop that defines the task behavior. */ + for (;;) { + if(terminateThread.load()) { + break; + } + //The component for this slot is executed and the next one is chosen. + this->pollingSeqTable.executeAndAdvance(); + if (not pollingSeqTable.slotFollowsImmediately()) { + // we need to wait before executing the current slot + //this gives us the time to wait: + interval = chron_ms(this->pollingSeqTable.getIntervalToPreviousSlotMs()); + delayForInterval(¤tStartTime, interval); + //TODO deadline missed check + } + } +} + +ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, + uint32_t slotTimeMs, int8_t executionStep) { + if (objectManager->get(componentId) != nullptr) { + pollingSeqTable.addSlot(componentId, slotTimeMs, executionStep, this); + return HasReturnvaluesIF::RETURN_OK; + } + + sif::error << "Component " << std::hex << componentId << + " not found, not adding it to pst" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; +} + +ReturnValue_t FixedTimeslotTask::checkSequence() const { + return pollingSeqTable.checkSequence(); +} + +uint32_t FixedTimeslotTask::getPeriodMs() const { + return period * 1000; +} + +bool FixedTimeslotTask::delayForInterval(chron_ms * previousWakeTimeMs, + const chron_ms interval) { + bool shouldDelay = false; + //Get current wakeup time + auto currentStartTime = + std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()); + /* Generate the tick time at which the task wants to wake. */ + auto nextTimeToWake_ms = (*previousWakeTimeMs) + interval; + + if (currentStartTime < *previousWakeTimeMs) { + /* The tick count has overflowed since this function was + lasted called. In this case the only time we should ever + actually delay is if the wake time has also overflowed, + and the wake time is greater than the tick time. When this + is the case it is as if neither time had overflowed. */ + if ((nextTimeToWake_ms < *previousWakeTimeMs) + && (nextTimeToWake_ms > currentStartTime)) { + shouldDelay = true; + } + } else { + /* The tick time has not overflowed. In this case we will + delay if either the wake time has overflowed, and/or the + tick time is less than the wake time. */ + if ((nextTimeToWake_ms < *previousWakeTimeMs) + || (nextTimeToWake_ms > currentStartTime)) { + shouldDelay = true; + } + } + + /* Update the wake time ready for the next call. */ + + (*previousWakeTimeMs) = nextTimeToWake_ms; + + if (shouldDelay) { + auto sleepTime = std::chrono::duration_cast( + nextTimeToWake_ms - currentStartTime); + std::this_thread::sleep_for(sleepTime); + return true; + } + //We are shifting the time in case the deadline was missed like rtems + (*previousWakeTimeMs) = currentStartTime; + return false; + +} + + + + diff --git a/osal/host/FixedTimeslotTask.h b/osal/host/FixedTimeslotTask.h index b12cc6d3..bbee94a6 100644 --- a/osal/host/FixedTimeslotTask.h +++ b/osal/host/FixedTimeslotTask.h @@ -1,130 +1,130 @@ -#ifndef FRAMEWORK_OSAL_HOST_FIXEDTIMESLOTTASK_H_ -#define FRAMEWORK_OSAL_HOST_FIXEDTIMESLOTTASK_H_ - -#include -#include -#include -#include - -#include -#include -#include -#include - -class ExecutableObjectIF; - -/** - * @brief This class represents a task for periodic activities with multiple - * steps and strict timeslot requirements for these steps. - * @details - * @ingroup task_handling - */ -class FixedTimeslotTask: public FixedTimeslotTaskIF { -public: - /** - * @brief Standard constructor of the class. - * @details - * The class is initialized without allocated objects. These need to be - * added with #addComponent. - * @param priority - * @param stack_size - * @param setPeriod - * @param setDeadlineMissedFunc - * The function pointer to the deadline missed function that shall be - * assigned. - */ - FixedTimeslotTask(const char *name, TaskPriority setPriority, - TaskStackSize setStack, TaskPeriod setPeriod, - void (*setDeadlineMissedFunc)()); - /** - * @brief Currently, the executed object's lifetime is not coupled with - * the task object's lifetime, so the destructor is empty. - */ - virtual ~FixedTimeslotTask(void); - - /** - * @brief The method to start the task. - * @details The method starts the task with the respective system call. - * Entry point is the taskEntryPoint method described below. - * The address of the task object is passed as an argument - * to the system call. - */ - ReturnValue_t startTask(void); - - /** - * Add timeslot to the polling sequence table. - * @param componentId - * @param slotTimeMs - * @param executionStep - * @return - */ - ReturnValue_t addSlot(object_id_t componentId, - uint32_t slotTimeMs, int8_t executionStep); - - ReturnValue_t checkSequence() const; - - uint32_t getPeriodMs() const; - - ReturnValue_t sleepFor(uint32_t ms); - -protected: - using chron_ms = std::chrono::milliseconds; - - bool started; - //!< Typedef for the List of objects. - typedef std::vector ObjectList; - std::thread mainThread; - std::atomic terminateThread = false; - - //! Polling sequence table which contains the object to execute - //! and information like the timeslots and the passed execution step. - FixedSlotSequence pollingSeqTable; - - std::condition_variable initCondition; - std::mutex initMutex; - std::string taskName; - /** - * @brief The period of the task. - * @details - * The period determines the frequency of the task's execution. - * It is expressed in clock ticks. - */ - TaskPeriod period; - - /** - * @brief The pointer to the deadline-missed function. - * @details - * This pointer stores the function that is executed if the task's deadline - * is missed. So, each may react individually on a timing failure. - * The pointer may be NULL, then nothing happens on missing the deadline. - * The deadline is equal to the next execution of the periodic task. - */ - void (*deadlineMissedFunc)(void); - /** - * @brief This is the function executed in the new task's context. - * @details - * It converts the argument back to the thread object type and copies the - * class instance to the task context. - * The taskFunctionality method is called afterwards. - * @param A pointer to the task object itself is passed as argument. - */ - - void taskEntryPoint(void* argument); - /** - * @brief The function containing the actual functionality of the task. - * @details - * The method sets and starts the task's period, then enters a loop that is - * repeated as long as the isRunning attribute is true. Within the loop, - * all performOperation methods of the added objects are called. Afterwards - * the checkAndRestartPeriod system call blocks the task until the next - * period. On missing the deadline, the deadlineMissedFunction is executed. - */ - void taskFunctionality(void); - - bool delayForInterval(chron_ms * previousWakeTimeMs, - const chron_ms interval); -}; - - - -#endif /* FRAMEWORK_OSAL_HOST_FIXEDTIMESLOTTASK_H_ */ +#ifndef FRAMEWORK_OSAL_HOST_FIXEDTIMESLOTTASK_H_ +#define FRAMEWORK_OSAL_HOST_FIXEDTIMESLOTTASK_H_ + +#include "../../objectmanager/ObjectManagerIF.h" +#include "../../tasks/FixedSlotSequence.h" +#include "../../tasks/FixedTimeslotTaskIF.h" +#include "../../tasks/Typedef.h" + +#include +#include +#include +#include + +class ExecutableObjectIF; + +/** + * @brief This class represents a task for periodic activities with multiple + * steps and strict timeslot requirements for these steps. + * @details + * @ingroup task_handling + */ +class FixedTimeslotTask: public FixedTimeslotTaskIF { +public: + /** + * @brief Standard constructor of the class. + * @details + * The class is initialized without allocated objects. These need to be + * added with #addComponent. + * @param priority + * @param stack_size + * @param setPeriod + * @param setDeadlineMissedFunc + * The function pointer to the deadline missed function that shall be + * assigned. + */ + FixedTimeslotTask(const char *name, TaskPriority setPriority, + TaskStackSize setStack, TaskPeriod setPeriod, + void (*setDeadlineMissedFunc)()); + /** + * @brief Currently, the executed object's lifetime is not coupled with + * the task object's lifetime, so the destructor is empty. + */ + virtual ~FixedTimeslotTask(void); + + /** + * @brief The method to start the task. + * @details The method starts the task with the respective system call. + * Entry point is the taskEntryPoint method described below. + * The address of the task object is passed as an argument + * to the system call. + */ + ReturnValue_t startTask(void); + + /** + * Add timeslot to the polling sequence table. + * @param componentId + * @param slotTimeMs + * @param executionStep + * @return + */ + ReturnValue_t addSlot(object_id_t componentId, + uint32_t slotTimeMs, int8_t executionStep); + + ReturnValue_t checkSequence() const; + + uint32_t getPeriodMs() const; + + ReturnValue_t sleepFor(uint32_t ms); + +protected: + using chron_ms = std::chrono::milliseconds; + + bool started; + //!< Typedef for the List of objects. + typedef std::vector ObjectList; + std::thread mainThread; + std::atomic terminateThread = false; + + //! Polling sequence table which contains the object to execute + //! and information like the timeslots and the passed execution step. + FixedSlotSequence pollingSeqTable; + + std::condition_variable initCondition; + std::mutex initMutex; + std::string taskName; + /** + * @brief The period of the task. + * @details + * The period determines the frequency of the task's execution. + * It is expressed in clock ticks. + */ + TaskPeriod period; + + /** + * @brief The pointer to the deadline-missed function. + * @details + * This pointer stores the function that is executed if the task's deadline + * is missed. So, each may react individually on a timing failure. + * The pointer may be NULL, then nothing happens on missing the deadline. + * The deadline is equal to the next execution of the periodic task. + */ + void (*deadlineMissedFunc)(void); + /** + * @brief This is the function executed in the new task's context. + * @details + * It converts the argument back to the thread object type and copies the + * class instance to the task context. + * The taskFunctionality method is called afterwards. + * @param A pointer to the task object itself is passed as argument. + */ + + void taskEntryPoint(void* argument); + /** + * @brief The function containing the actual functionality of the task. + * @details + * The method sets and starts the task's period, then enters a loop that is + * repeated as long as the isRunning attribute is true. Within the loop, + * all performOperation methods of the added objects are called. Afterwards + * the checkAndRestartPeriod system call blocks the task until the next + * period. On missing the deadline, the deadlineMissedFunction is executed. + */ + void taskFunctionality(void); + + bool delayForInterval(chron_ms * previousWakeTimeMs, + const chron_ms interval); +}; + + + +#endif /* FRAMEWORK_OSAL_HOST_FIXEDTIMESLOTTASK_H_ */ diff --git a/osal/host/MessageQueue.cpp b/osal/host/MessageQueue.cpp index 7af5fbd9..6fd42849 100644 --- a/osal/host/MessageQueue.cpp +++ b/osal/host/MessageQueue.cpp @@ -1,155 +1,155 @@ -#include -#include -#include -#include -#include - -MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize): - messageSize(maxMessageSize), messageDepth(messageDepth) { - queueLock = MutexFactory::instance()->createMutex(); - auto result = QueueMapManager::instance()->addMessageQueue(this, &mqId); - if(result != HasReturnvaluesIF::RETURN_OK) { - sif::error << "MessageQueue: Could not be created" << std::endl; - } -} - -MessageQueue::~MessageQueue() { - MutexFactory::instance()->deleteMutex(queueLock); -} - -ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, - MessageQueueMessageIF* message, bool ignoreFault) { - return sendMessageFrom(sendTo, message, this->getId(), ignoreFault); -} - -ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessageIF* message) { - return sendToDefaultFrom(message, this->getId()); -} - -ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message, - MessageQueueId_t sentFrom, bool ignoreFault) { - return sendMessageFrom(defaultDestination,message,sentFrom,ignoreFault); -} - -ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) { - if (this->lastPartner != 0) { - return sendMessageFrom(this->lastPartner, message, this->getId()); - } else { - return MessageQueueIF::NO_REPLY_PARTNER; - } -} - -ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, - MessageQueueMessageIF* message, MessageQueueId_t sentFrom, - bool ignoreFault) { - return sendMessageFromMessageQueue(sendTo, message, sentFrom, - ignoreFault); -} - -ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message, - MessageQueueId_t* receivedFrom) { - ReturnValue_t status = this->receiveMessage(message); - if(status == HasReturnvaluesIF::RETURN_OK) { - *receivedFrom = this->lastPartner; - } - return status; -} - -ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) { - if(messageQueue.empty()) { - return MessageQueueIF::EMPTY; - } - // not sure this will work.. - //*message = std::move(messageQueue.front()); - MutexHelper mutexLock(queueLock, 20); - MessageQueueMessage* currentMessage = &messageQueue.front(); - std::copy(currentMessage->getBuffer(), - currentMessage->getBuffer() + messageSize, message->getBuffer()); - messageQueue.pop(); - // The last partner is the first uint32_t field in the message - this->lastPartner = message->getSender(); - return HasReturnvaluesIF::RETURN_OK; -} - -MessageQueueId_t MessageQueue::getLastPartner() const { - return lastPartner; -} - -ReturnValue_t MessageQueue::flush(uint32_t* count) { - *count = messageQueue.size(); - // Clears the queue. - messageQueue = std::queue(); - return HasReturnvaluesIF::RETURN_OK; -} - -MessageQueueId_t MessageQueue::getId() const { - return mqId; -} - -void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) { - defaultDestinationSet = true; - this->defaultDestination = defaultDestination; -} - -MessageQueueId_t MessageQueue::getDefaultDestination() const { - return defaultDestination; -} - -bool MessageQueue::isDefaultDestinationSet() const { - return defaultDestinationSet; -} - - -// static core function to send messages. -ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, - MessageQueueMessageIF* message, MessageQueueId_t sentFrom, - bool ignoreFault) { - if(message->getMessageSize() > message->getMaximumMessageSize()) { - // Actually, this should never happen or an error will be emitted - // in MessageQueueMessage. - // But I will still return a failure here. - return HasReturnvaluesIF::RETURN_FAILED; - } - MessageQueue* targetQueue = dynamic_cast( - QueueMapManager::instance()->getMessageQueue(sendTo)); - if(targetQueue == nullptr) { - if(not ignoreFault) { - InternalErrorReporterIF* internalErrorReporter = - objectManager->get( - objects::INTERNAL_ERROR_REPORTER); - if (internalErrorReporter != nullptr) { - internalErrorReporter->queueMessageNotSent(); - } - } - // TODO: Better returnvalue - return HasReturnvaluesIF::RETURN_FAILED; - } - - if(targetQueue->messageQueue.size() < targetQueue->messageDepth) { - MutexHelper mutexLock(targetQueue->queueLock, 20); - // not ideal, works for now though. - MessageQueueMessage* mqmMessage = - dynamic_cast(message); - if(message != nullptr) { - targetQueue->messageQueue.push(*mqmMessage); - } - else { - sif::error << "MessageQueue::sendMessageFromMessageQueue: Message" - "is not MessageQueueMessage!" << std::endl; - } - - } - else { - return MessageQueueIF::FULL; - } - message->setSender(sentFrom); - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t MessageQueue::lockQueue(dur_millis_t lockTimeout) { - return queueLock->lockMutex(lockTimeout); -} - -ReturnValue_t MessageQueue::unlockQueue() { - return queueLock->unlockMutex(); -} +#include "../../osal/host/MessageQueue.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "../../osal/host/QueueMapManager.h" +#include "../../ipc/MutexFactory.h" +#include "../../ipc/MutexHelper.h" + +MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize): + messageSize(maxMessageSize), messageDepth(messageDepth) { + queueLock = MutexFactory::instance()->createMutex(); + auto result = QueueMapManager::instance()->addMessageQueue(this, &mqId); + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::error << "MessageQueue: Could not be created" << std::endl; + } +} + +MessageQueue::~MessageQueue() { + MutexFactory::instance()->deleteMutex(queueLock); +} + +ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, + MessageQueueMessageIF* message, bool ignoreFault) { + return sendMessageFrom(sendTo, message, this->getId(), ignoreFault); +} + +ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessageIF* message) { + return sendToDefaultFrom(message, this->getId()); +} + +ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message, + MessageQueueId_t sentFrom, bool ignoreFault) { + return sendMessageFrom(defaultDestination,message,sentFrom,ignoreFault); +} + +ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) { + if (this->lastPartner != 0) { + return sendMessageFrom(this->lastPartner, message, this->getId()); + } else { + return MessageQueueIF::NO_REPLY_PARTNER; + } +} + +ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, + MessageQueueMessageIF* message, MessageQueueId_t sentFrom, + bool ignoreFault) { + return sendMessageFromMessageQueue(sendTo, message, sentFrom, + ignoreFault); +} + +ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message, + MessageQueueId_t* receivedFrom) { + ReturnValue_t status = this->receiveMessage(message); + if(status == HasReturnvaluesIF::RETURN_OK) { + *receivedFrom = this->lastPartner; + } + return status; +} + +ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) { + if(messageQueue.empty()) { + return MessageQueueIF::EMPTY; + } + // not sure this will work.. + //*message = std::move(messageQueue.front()); + MutexHelper mutexLock(queueLock, 20); + MessageQueueMessage* currentMessage = &messageQueue.front(); + std::copy(currentMessage->getBuffer(), + currentMessage->getBuffer() + messageSize, message->getBuffer()); + messageQueue.pop(); + // The last partner is the first uint32_t field in the message + this->lastPartner = message->getSender(); + return HasReturnvaluesIF::RETURN_OK; +} + +MessageQueueId_t MessageQueue::getLastPartner() const { + return lastPartner; +} + +ReturnValue_t MessageQueue::flush(uint32_t* count) { + *count = messageQueue.size(); + // Clears the queue. + messageQueue = std::queue(); + return HasReturnvaluesIF::RETURN_OK; +} + +MessageQueueId_t MessageQueue::getId() const { + return mqId; +} + +void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) { + defaultDestinationSet = true; + this->defaultDestination = defaultDestination; +} + +MessageQueueId_t MessageQueue::getDefaultDestination() const { + return defaultDestination; +} + +bool MessageQueue::isDefaultDestinationSet() const { + return defaultDestinationSet; +} + + +// static core function to send messages. +ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, + MessageQueueMessageIF* message, MessageQueueId_t sentFrom, + bool ignoreFault) { + if(message->getMessageSize() > message->getMaximumMessageSize()) { + // Actually, this should never happen or an error will be emitted + // in MessageQueueMessage. + // But I will still return a failure here. + return HasReturnvaluesIF::RETURN_FAILED; + } + MessageQueue* targetQueue = dynamic_cast( + QueueMapManager::instance()->getMessageQueue(sendTo)); + if(targetQueue == nullptr) { + if(not ignoreFault) { + InternalErrorReporterIF* internalErrorReporter = + objectManager->get( + objects::INTERNAL_ERROR_REPORTER); + if (internalErrorReporter != nullptr) { + internalErrorReporter->queueMessageNotSent(); + } + } + // TODO: Better returnvalue + return HasReturnvaluesIF::RETURN_FAILED; + } + + if(targetQueue->messageQueue.size() < targetQueue->messageDepth) { + MutexHelper mutexLock(targetQueue->queueLock, 20); + // not ideal, works for now though. + MessageQueueMessage* mqmMessage = + dynamic_cast(message); + if(message != nullptr) { + targetQueue->messageQueue.push(*mqmMessage); + } + else { + sif::error << "MessageQueue::sendMessageFromMessageQueue: Message" + "is not MessageQueueMessage!" << std::endl; + } + + } + else { + return MessageQueueIF::FULL; + } + message->setSender(sentFrom); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t MessageQueue::lockQueue(dur_millis_t lockTimeout) { + return queueLock->lockMutex(lockTimeout); +} + +ReturnValue_t MessageQueue::unlockQueue() { + return queueLock->unlockMutex(); +} diff --git a/osal/host/MessageQueue.h b/osal/host/MessageQueue.h index 7fc77f7a..d2da2402 100644 --- a/osal/host/MessageQueue.h +++ b/osal/host/MessageQueue.h @@ -1,230 +1,230 @@ -#ifndef FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_ -#define FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_ - -#include -#include -#include -#include -#include - -#include -#include - -/** - * @brief This class manages sending and receiving of - * message queue messages. - * @details - * Message queues are used to pass asynchronous messages between processes. - * They work like post boxes, where all incoming messages are stored in FIFO - * order. This class creates a new receiving queue and provides methods to fetch - * received messages. Being a child of MessageQueueSender, this class also - * provides methods to send a message to a user-defined or a default destination. - * In addition it also provides a reply method to answer to the queue it - * received its last message from. - * - * The MessageQueue should be used as "post box" for a single owning object. - * So all message queue communication is "n-to-one". - * For creating the queue, as well as sending and receiving messages, the class - * makes use of the operating system calls provided. - * - * Please keep in mind that FreeRTOS offers different calls for message queue - * operations if called from an ISR. - * For now, the system context needs to be switched manually. - * @ingroup osal - * @ingroup message_queue - */ -class MessageQueue : public MessageQueueIF { - friend class MessageQueueSenderIF; -public: - /** - * @brief The constructor initializes and configures the message queue. - * @details - * By making use of the according operating system call, a message queue is - * created and initialized. The message depth - the maximum number of - * messages to be buffered - may be set with the help of a parameter, - * whereas the message size is automatically set to the maximum message - * queue message size. The operating system sets the message queue id, or - * in case of failure, it is set to zero. - * @param message_depth - * The number of messages to be buffered before passing an error to the - * sender. Default is three. - * @param max_message_size - * With this parameter, the maximum message size can be adjusted. - * This should be left default. - */ - MessageQueue(size_t messageDepth = 3, - size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE); - - /** Copying message queues forbidden */ - MessageQueue(const MessageQueue&) = delete; - MessageQueue& operator=(const MessageQueue&) = delete; - - /** - * @brief The destructor deletes the formerly created message queue. - * @details This is accomplished by using the delete call provided - * by the operating system. - */ - virtual ~MessageQueue(); - - /** - * @brief This operation sends a message to the given destination. - * @details It directly uses the sendMessage call of the MessageQueueSender - * parent, but passes its queue id as "sentFrom" parameter. - * @param sendTo This parameter specifies the message queue id of the - * destination message queue. - * @param message A pointer to a previously created message, which is sent. - * @param ignoreFault If set to true, the internal software fault counter - * is not incremented if queue is full. - */ - ReturnValue_t sendMessage(MessageQueueId_t sendTo, - MessageQueueMessageIF* message, bool ignoreFault = false) override; - /** - * @brief This operation sends a message to the default destination. - * @details As in the sendMessage method, this function uses the - * sendToDefault call of the MessageQueueSender parent class and adds its - * queue id as "sentFrom" information. - * @param message A pointer to a previously created message, which is sent. - */ - ReturnValue_t sendToDefault(MessageQueueMessageIF* message) override; - /** - * @brief This operation sends a message to the last communication partner. - * @details This operation simplifies answering an incoming message by using - * the stored lastPartner information as destination. If there was no - * message received yet (i.e. lastPartner is zero), an error code is returned. - * @param message A pointer to a previously created message, which is sent. - */ - ReturnValue_t reply(MessageQueueMessageIF* message) override; - - /** - * @brief With the sendMessage call, a queue message is sent to a - * receiving queue. - * @details - * This method takes the message provided, adds the sentFrom information and - * passes it on to the destination provided with an operating system call. - * The OS's return value is returned. - * @param sendTo This parameter specifies the message queue id to send - * the message to. - * @param message This is a pointer to a previously created message, - * which is sent. - * @param sentFrom The sentFrom information can be set to inject the - * sender's queue id into the message. This variable is set to zero by - * default. - * @param ignoreFault If set to true, the internal software fault counter - * is not incremented if queue is full. - */ - virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo, - MessageQueueMessageIF* message, MessageQueueId_t sentFrom = NO_QUEUE, - bool ignoreFault = false) override; - - /** - * @brief The sendToDefault method sends a queue message to the default - * destination. - * @details - * In all other aspects, it works identical to the sendMessage method. - * @param message This is a pointer to a previously created message, - * which is sent. - * @param sentFrom The sentFrom information can be set to inject the - * sender's queue id into the message. This variable is set to zero by - * default. - */ - virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessageIF* message, - MessageQueueId_t sentFrom = NO_QUEUE, - bool ignoreFault = false) override; - - /** - * @brief This function reads available messages from the message queue - * and returns the sender. - * @details - * It works identically to the other receiveMessage call, but in addition - * returns the sender's queue id. - * @param message A pointer to a message in which the received data is stored. - * @param receivedFrom A pointer to a queue id in which the sender's id is stored. - */ - ReturnValue_t receiveMessage(MessageQueueMessageIF* message, - MessageQueueId_t *receivedFrom) override; - - /** - * @brief This function reads available messages from the message queue. - * @details - * If data is available it is stored in the passed message pointer. - * The message's original content is overwritten and the sendFrom - * information is stored in the lastPartner attribute. Else, the lastPartner - * information remains untouched, the message's content is cleared and the - * function returns immediately. - * @param message A pointer to a message in which the received data is stored. - */ - ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override; - /** - * Deletes all pending messages in the queue. - * @param count The number of flushed messages. - * @return RETURN_OK on success. - */ - ReturnValue_t flush(uint32_t* count) override; - /** - * @brief This method returns the message queue id of the last - * communication partner. - */ - MessageQueueId_t getLastPartner() const override; - /** - * @brief This method returns the message queue id of this class's - * message queue. - */ - MessageQueueId_t getId() const override; - - /** - * @brief This method is a simple setter for the default destination. - */ - void setDefaultDestination(MessageQueueId_t defaultDestination) override; - /** - * @brief This method is a simple getter for the default destination. - */ - MessageQueueId_t getDefaultDestination() const override; - - bool isDefaultDestinationSet() const override; - - ReturnValue_t lockQueue(dur_millis_t lockTimeout); - ReturnValue_t unlockQueue(); -protected: - /** - * @brief Implementation to be called from any send Call within - * MessageQueue and MessageQueueSenderIF. - * @details - * This method takes the message provided, adds the sentFrom information and - * passes it on to the destination provided with an operating system call. - * The OS's return value is returned. - * @param sendTo - * This parameter specifies the message queue id to send the message to. - * @param message - * This is a pointer to a previously created message, which is sent. - * @param sentFrom - * The sentFrom information can be set to inject the sender's queue id into - * the message. This variable is set to zero by default. - * @param ignoreFault - * If set to true, the internal software fault counter is not incremented - * if queue is full. - * @param context Specify whether call is made from task or from an ISR. - */ - static ReturnValue_t sendMessageFromMessageQueue(MessageQueueId_t sendTo, - MessageQueueMessageIF* message, MessageQueueId_t sentFrom = NO_QUEUE, - bool ignoreFault=false); - - //static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault); - -private: - std::queue messageQueue; - /** - * @brief The class stores the queue id it got assigned. - * If initialization fails, the queue id is set to zero. - */ - MessageQueueId_t mqId = 0; - size_t messageSize = 0; - size_t messageDepth = 0; - - MutexIF* queueLock; - - bool defaultDestinationSet = false; - MessageQueueId_t defaultDestination = 0; - MessageQueueId_t lastPartner = 0; -}; - -#endif /* FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_ */ +#ifndef FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_ +#define FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_ + +#include "../../internalError/InternalErrorReporterIF.h" +#include "../../ipc/MessageQueueIF.h" +#include "../../ipc/MessageQueueMessage.h" +#include "../../ipc/MutexIF.h" +#include "../../timemanager/Clock.h" + +#include +#include + +/** + * @brief This class manages sending and receiving of + * message queue messages. + * @details + * Message queues are used to pass asynchronous messages between processes. + * They work like post boxes, where all incoming messages are stored in FIFO + * order. This class creates a new receiving queue and provides methods to fetch + * received messages. Being a child of MessageQueueSender, this class also + * provides methods to send a message to a user-defined or a default destination. + * In addition it also provides a reply method to answer to the queue it + * received its last message from. + * + * The MessageQueue should be used as "post box" for a single owning object. + * So all message queue communication is "n-to-one". + * For creating the queue, as well as sending and receiving messages, the class + * makes use of the operating system calls provided. + * + * Please keep in mind that FreeRTOS offers different calls for message queue + * operations if called from an ISR. + * For now, the system context needs to be switched manually. + * @ingroup osal + * @ingroup message_queue + */ +class MessageQueue : public MessageQueueIF { + friend class MessageQueueSenderIF; +public: + /** + * @brief The constructor initializes and configures the message queue. + * @details + * By making use of the according operating system call, a message queue is + * created and initialized. The message depth - the maximum number of + * messages to be buffered - may be set with the help of a parameter, + * whereas the message size is automatically set to the maximum message + * queue message size. The operating system sets the message queue id, or + * in case of failure, it is set to zero. + * @param message_depth + * The number of messages to be buffered before passing an error to the + * sender. Default is three. + * @param max_message_size + * With this parameter, the maximum message size can be adjusted. + * This should be left default. + */ + MessageQueue(size_t messageDepth = 3, + size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE); + + /** Copying message queues forbidden */ + MessageQueue(const MessageQueue&) = delete; + MessageQueue& operator=(const MessageQueue&) = delete; + + /** + * @brief The destructor deletes the formerly created message queue. + * @details This is accomplished by using the delete call provided + * by the operating system. + */ + virtual ~MessageQueue(); + + /** + * @brief This operation sends a message to the given destination. + * @details It directly uses the sendMessage call of the MessageQueueSender + * parent, but passes its queue id as "sentFrom" parameter. + * @param sendTo This parameter specifies the message queue id of the + * destination message queue. + * @param message A pointer to a previously created message, which is sent. + * @param ignoreFault If set to true, the internal software fault counter + * is not incremented if queue is full. + */ + ReturnValue_t sendMessage(MessageQueueId_t sendTo, + MessageQueueMessageIF* message, bool ignoreFault = false) override; + /** + * @brief This operation sends a message to the default destination. + * @details As in the sendMessage method, this function uses the + * sendToDefault call of the MessageQueueSender parent class and adds its + * queue id as "sentFrom" information. + * @param message A pointer to a previously created message, which is sent. + */ + ReturnValue_t sendToDefault(MessageQueueMessageIF* message) override; + /** + * @brief This operation sends a message to the last communication partner. + * @details This operation simplifies answering an incoming message by using + * the stored lastPartner information as destination. If there was no + * message received yet (i.e. lastPartner is zero), an error code is returned. + * @param message A pointer to a previously created message, which is sent. + */ + ReturnValue_t reply(MessageQueueMessageIF* message) override; + + /** + * @brief With the sendMessage call, a queue message is sent to a + * receiving queue. + * @details + * This method takes the message provided, adds the sentFrom information and + * passes it on to the destination provided with an operating system call. + * The OS's return value is returned. + * @param sendTo This parameter specifies the message queue id to send + * the message to. + * @param message This is a pointer to a previously created message, + * which is sent. + * @param sentFrom The sentFrom information can be set to inject the + * sender's queue id into the message. This variable is set to zero by + * default. + * @param ignoreFault If set to true, the internal software fault counter + * is not incremented if queue is full. + */ + virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo, + MessageQueueMessageIF* message, MessageQueueId_t sentFrom = NO_QUEUE, + bool ignoreFault = false) override; + + /** + * @brief The sendToDefault method sends a queue message to the default + * destination. + * @details + * In all other aspects, it works identical to the sendMessage method. + * @param message This is a pointer to a previously created message, + * which is sent. + * @param sentFrom The sentFrom information can be set to inject the + * sender's queue id into the message. This variable is set to zero by + * default. + */ + virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessageIF* message, + MessageQueueId_t sentFrom = NO_QUEUE, + bool ignoreFault = false) override; + + /** + * @brief This function reads available messages from the message queue + * and returns the sender. + * @details + * It works identically to the other receiveMessage call, but in addition + * returns the sender's queue id. + * @param message A pointer to a message in which the received data is stored. + * @param receivedFrom A pointer to a queue id in which the sender's id is stored. + */ + ReturnValue_t receiveMessage(MessageQueueMessageIF* message, + MessageQueueId_t *receivedFrom) override; + + /** + * @brief This function reads available messages from the message queue. + * @details + * If data is available it is stored in the passed message pointer. + * The message's original content is overwritten and the sendFrom + * information is stored in the lastPartner attribute. Else, the lastPartner + * information remains untouched, the message's content is cleared and the + * function returns immediately. + * @param message A pointer to a message in which the received data is stored. + */ + ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override; + /** + * Deletes all pending messages in the queue. + * @param count The number of flushed messages. + * @return RETURN_OK on success. + */ + ReturnValue_t flush(uint32_t* count) override; + /** + * @brief This method returns the message queue id of the last + * communication partner. + */ + MessageQueueId_t getLastPartner() const override; + /** + * @brief This method returns the message queue id of this class's + * message queue. + */ + MessageQueueId_t getId() const override; + + /** + * @brief This method is a simple setter for the default destination. + */ + void setDefaultDestination(MessageQueueId_t defaultDestination) override; + /** + * @brief This method is a simple getter for the default destination. + */ + MessageQueueId_t getDefaultDestination() const override; + + bool isDefaultDestinationSet() const override; + + ReturnValue_t lockQueue(dur_millis_t lockTimeout); + ReturnValue_t unlockQueue(); +protected: + /** + * @brief Implementation to be called from any send Call within + * MessageQueue and MessageQueueSenderIF. + * @details + * This method takes the message provided, adds the sentFrom information and + * passes it on to the destination provided with an operating system call. + * The OS's return value is returned. + * @param sendTo + * This parameter specifies the message queue id to send the message to. + * @param message + * This is a pointer to a previously created message, which is sent. + * @param sentFrom + * The sentFrom information can be set to inject the sender's queue id into + * the message. This variable is set to zero by default. + * @param ignoreFault + * If set to true, the internal software fault counter is not incremented + * if queue is full. + * @param context Specify whether call is made from task or from an ISR. + */ + static ReturnValue_t sendMessageFromMessageQueue(MessageQueueId_t sendTo, + MessageQueueMessageIF* message, MessageQueueId_t sentFrom = NO_QUEUE, + bool ignoreFault=false); + + //static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault); + +private: + std::queue messageQueue; + /** + * @brief The class stores the queue id it got assigned. + * If initialization fails, the queue id is set to zero. + */ + MessageQueueId_t mqId = 0; + size_t messageSize = 0; + size_t messageDepth = 0; + + MutexIF* queueLock; + + bool defaultDestinationSet = false; + MessageQueueId_t defaultDestination = 0; + MessageQueueId_t lastPartner = 0; +}; + +#endif /* FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_ */ diff --git a/osal/host/Mutex.cpp b/osal/host/Mutex.cpp index 03948c4c..28768507 100644 --- a/osal/host/Mutex.cpp +++ b/osal/host/Mutex.cpp @@ -1,40 +1,40 @@ -#include -#include - -const uint32_t MutexIF::POLLING = 0; -const uint32_t MutexIF::BLOCKING = 0xffffffff; - -ReturnValue_t Mutex::lockMutex(uint32_t timeoutMs) { - if(timeoutMs == MutexIF::BLOCKING) { - mutex.lock(); - locked = true; - return HasReturnvaluesIF::RETURN_OK; - } - else if(timeoutMs == MutexIF::POLLING) { - if(mutex.try_lock()) { - locked = true; - return HasReturnvaluesIF::RETURN_OK; - } - } - else if(timeoutMs > MutexIF::POLLING){ - auto chronoMs = std::chrono::milliseconds(timeoutMs); - if(mutex.try_lock_for(chronoMs)) { - locked = true; - return HasReturnvaluesIF::RETURN_OK; - } - } - return MutexIF::MUTEX_TIMEOUT; -} - -ReturnValue_t Mutex::unlockMutex() { - if(not locked) { - return MutexIF::CURR_THREAD_DOES_NOT_OWN_MUTEX; - } - mutex.unlock(); - locked = false; - return HasReturnvaluesIF::RETURN_OK; -} - -std::timed_mutex* Mutex::getMutexHandle() { - return &mutex; -} +#include "../../osal/host/Mutex.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" + +const uint32_t MutexIF::POLLING = 0; +const uint32_t MutexIF::BLOCKING = 0xffffffff; + +ReturnValue_t Mutex::lockMutex(uint32_t timeoutMs) { + if(timeoutMs == MutexIF::BLOCKING) { + mutex.lock(); + locked = true; + return HasReturnvaluesIF::RETURN_OK; + } + else if(timeoutMs == MutexIF::POLLING) { + if(mutex.try_lock()) { + locked = true; + return HasReturnvaluesIF::RETURN_OK; + } + } + else if(timeoutMs > MutexIF::POLLING){ + auto chronoMs = std::chrono::milliseconds(timeoutMs); + if(mutex.try_lock_for(chronoMs)) { + locked = true; + return HasReturnvaluesIF::RETURN_OK; + } + } + return MutexIF::MUTEX_TIMEOUT; +} + +ReturnValue_t Mutex::unlockMutex() { + if(not locked) { + return MutexIF::CURR_THREAD_DOES_NOT_OWN_MUTEX; + } + mutex.unlock(); + locked = false; + return HasReturnvaluesIF::RETURN_OK; +} + +std::timed_mutex* Mutex::getMutexHandle() { + return &mutex; +} diff --git a/osal/host/Mutex.h b/osal/host/Mutex.h index d882c457..4d49bac7 100644 --- a/osal/host/Mutex.h +++ b/osal/host/Mutex.h @@ -1,28 +1,28 @@ -#ifndef FRAMEWORK_OSAL_FREERTOS_MUTEX_H_ -#define FRAMEWORK_OSAL_FREERTOS_MUTEX_H_ - -#include - -#include - -/** - * @brief OS component to implement MUTual EXclusion - * - * @details - * Mutexes are binary semaphores which include a priority inheritance mechanism. - * Documentation: https://www.freertos.org/Real-time-embedded-RTOS-mutexes.html - * @ingroup osal - */ -class Mutex : public MutexIF { -public: - Mutex() = default; - ReturnValue_t lockMutex(uint32_t timeoutMs = MutexIF::BLOCKING) override; - ReturnValue_t unlockMutex() override; - - std::timed_mutex* getMutexHandle(); -private: - bool locked = false; - std::timed_mutex mutex; -}; - -#endif /* FRAMEWORK_FREERTOS_MUTEX_H_ */ +#ifndef FRAMEWORK_OSAL_FREERTOS_MUTEX_H_ +#define FRAMEWORK_OSAL_FREERTOS_MUTEX_H_ + +#include "../../ipc/MutexIF.h" + +#include + +/** + * @brief OS component to implement MUTual EXclusion + * + * @details + * Mutexes are binary semaphores which include a priority inheritance mechanism. + * Documentation: https://www.freertos.org/Real-time-embedded-RTOS-mutexes.html + * @ingroup osal + */ +class Mutex : public MutexIF { +public: + Mutex() = default; + ReturnValue_t lockMutex(uint32_t timeoutMs = MutexIF::BLOCKING) override; + ReturnValue_t unlockMutex() override; + + std::timed_mutex* getMutexHandle(); +private: + bool locked = false; + std::timed_mutex mutex; +}; + +#endif /* FRAMEWORK_FREERTOS_MUTEX_H_ */ diff --git a/osal/host/MutexFactory.cpp b/osal/host/MutexFactory.cpp index 25d9fa46..284ce59f 100644 --- a/osal/host/MutexFactory.cpp +++ b/osal/host/MutexFactory.cpp @@ -1,28 +1,28 @@ -#include -#include - -//TODO: Different variant than the lazy loading in QueueFactory. -//What's better and why? -> one is on heap the other on bss/data -//MutexFactory* MutexFactory::factoryInstance = new MutexFactory(); -MutexFactory* MutexFactory::factoryInstance = nullptr; - -MutexFactory::MutexFactory() { -} - -MutexFactory::~MutexFactory() { -} - -MutexFactory* MutexFactory::instance() { - if (factoryInstance == nullptr){ - factoryInstance = new MutexFactory(); - } - return MutexFactory::factoryInstance; -} - -MutexIF* MutexFactory::createMutex() { - return new Mutex(); -} - -void MutexFactory::deleteMutex(MutexIF* mutex) { - delete mutex; -} +#include "../../ipc/MutexFactory.h" +#include "../../osal/host/Mutex.h" + +//TODO: Different variant than the lazy loading in QueueFactory. +//What's better and why? -> one is on heap the other on bss/data +//MutexFactory* MutexFactory::factoryInstance = new MutexFactory(); +MutexFactory* MutexFactory::factoryInstance = nullptr; + +MutexFactory::MutexFactory() { +} + +MutexFactory::~MutexFactory() { +} + +MutexFactory* MutexFactory::instance() { + if (factoryInstance == nullptr){ + factoryInstance = new MutexFactory(); + } + return MutexFactory::factoryInstance; +} + +MutexIF* MutexFactory::createMutex() { + return new Mutex(); +} + +void MutexFactory::deleteMutex(MutexIF* mutex) { + delete mutex; +} diff --git a/osal/host/PeriodicTask.cpp b/osal/host/PeriodicTask.cpp index 1a5024ab..c4cf9f56 100644 --- a/osal/host/PeriodicTask.cpp +++ b/osal/host/PeriodicTask.cpp @@ -1,176 +1,176 @@ -#include -#include -#include - -#include -#include - -#include -#include - -#if defined(WIN32) -#include -#elif defined(LINUX) -#include -#endif - -PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority, - TaskStackSize setStack, TaskPeriod setPeriod, - void (*setDeadlineMissedFunc)()) : - started(false), taskName(name), period(setPeriod), - deadlineMissedFunc(setDeadlineMissedFunc) { - // It is propably possible to set task priorities by using the native - // task handles for Windows / Linux - mainThread = std::thread(&PeriodicTask::taskEntryPoint, this, this); -#if defined(WIN32) - /* List of possible priority classes: - * https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ - * nf-processthreadsapi-setpriorityclass - * And respective thread priority numbers: - * https://docs.microsoft.com/en-us/windows/ - * win32/procthread/scheduling-priorities */ - int result = SetPriorityClass( - reinterpret_cast(mainThread.native_handle()), - ABOVE_NORMAL_PRIORITY_CLASS); - if(result != 0) { - sif::error << "PeriodicTask: Windows SetPriorityClass failed with code " - << GetLastError() << std::endl; - } - result = SetThreadPriority( - reinterpret_cast(mainThread.native_handle()), - THREAD_PRIORITY_NORMAL); - if(result != 0) { - sif::error << "PeriodicTask: Windows SetPriorityClass failed with code " - << GetLastError() << std::endl; - } -#elif defined(LINUX) - // we can just copy and paste the code from linux here. -#endif -} - -PeriodicTask::~PeriodicTask(void) { - //Do not delete objects, we were responsible for ptrs only. - terminateThread = true; - if(mainThread.joinable()) { - mainThread.join(); - } - delete this; -} - -void PeriodicTask::taskEntryPoint(void* argument) { - PeriodicTask *originalTask(reinterpret_cast(argument)); - - - if (not originalTask->started) { - // we have to suspend/block here until the task is started. - // if semaphores are implemented, use them here. - std::unique_lock lock(initMutex); - initCondition.wait(lock); - } - - this->taskFunctionality(); - sif::debug << "PeriodicTask::taskEntryPoint: " - "Returned from taskFunctionality." << std::endl; -} - -ReturnValue_t PeriodicTask::startTask() { - started = true; - - // Notify task to start. - std::lock_guard lock(initMutex); - initCondition.notify_one(); - - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t PeriodicTask::sleepFor(uint32_t ms) { - std::this_thread::sleep_for(std::chrono::milliseconds(ms)); - return HasReturnvaluesIF::RETURN_OK; -} - -void PeriodicTask::taskFunctionality() { - std::chrono::milliseconds periodChrono(static_cast(period*1000)); - auto currentStartTime { - std::chrono::duration_cast( - std::chrono::system_clock::now().time_since_epoch()) - }; - auto nextStartTime{ currentStartTime }; - - /* Enter the loop that defines the task behavior. */ - for (;;) { - if(terminateThread.load()) { - break; - } - for (ObjectList::iterator it = objectList.begin(); - it != objectList.end(); ++it) { - (*it)->performOperation(); - } - if(not delayForInterval(¤tStartTime, periodChrono)) { - sif::warning << "PeriodicTask: " << taskName << - " missed deadline!\n" << std::flush; - if(deadlineMissedFunc != nullptr) { - this->deadlineMissedFunc(); - } - } - } -} - -ReturnValue_t PeriodicTask::addComponent(object_id_t object) { - ExecutableObjectIF* newObject = objectManager->get( - object); - if (newObject == nullptr) { - return HasReturnvaluesIF::RETURN_FAILED; - } - objectList.push_back(newObject); - return HasReturnvaluesIF::RETURN_OK; -} - -uint32_t PeriodicTask::getPeriodMs() const { - return period * 1000; -} - -bool PeriodicTask::delayForInterval(chron_ms* previousWakeTimeMs, - const chron_ms interval) { - bool shouldDelay = false; - //Get current wakeup time - auto currentStartTime = - std::chrono::duration_cast( - std::chrono::system_clock::now().time_since_epoch()); - /* Generate the tick time at which the task wants to wake. */ - auto nextTimeToWake_ms = (*previousWakeTimeMs) + interval; - - if (currentStartTime < *previousWakeTimeMs) { - /* The tick count has overflowed since this function was - lasted called. In this case the only time we should ever - actually delay is if the wake time has also overflowed, - and the wake time is greater than the tick time. When this - is the case it is as if neither time had overflowed. */ - if ((nextTimeToWake_ms < *previousWakeTimeMs) - && (nextTimeToWake_ms > currentStartTime)) { - shouldDelay = true; - } - } else { - /* The tick time has not overflowed. In this case we will - delay if either the wake time has overflowed, and/or the - tick time is less than the wake time. */ - if ((nextTimeToWake_ms < *previousWakeTimeMs) - || (nextTimeToWake_ms > currentStartTime)) { - shouldDelay = true; - } - } - - /* Update the wake time ready for the next call. */ - - (*previousWakeTimeMs) = nextTimeToWake_ms; - - if (shouldDelay) { - auto sleepTime = std::chrono::duration_cast( - nextTimeToWake_ms - currentStartTime); - std::this_thread::sleep_for(sleepTime); - return true; - } - //We are shifting the time in case the deadline was missed like rtems - (*previousWakeTimeMs) = currentStartTime; - return false; - -} +#include "../../ipc/MutexFactory.h" +#include "../../osal/host/Mutex.h" +#include "../../osal/host/PeriodicTask.h" + +#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "../../tasks/ExecutableObjectIF.h" + +#include +#include + +#if defined(WIN32) +#include +#elif defined(LINUX) +#include +#endif + +PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority, + TaskStackSize setStack, TaskPeriod setPeriod, + void (*setDeadlineMissedFunc)()) : + started(false), taskName(name), period(setPeriod), + deadlineMissedFunc(setDeadlineMissedFunc) { + // It is propably possible to set task priorities by using the native + // task handles for Windows / Linux + mainThread = std::thread(&PeriodicTask::taskEntryPoint, this, this); +#if defined(WIN32) + /* List of possible priority classes: + * https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ + * nf-processthreadsapi-setpriorityclass + * And respective thread priority numbers: + * https://docs.microsoft.com/en-us/windows/ + * win32/procthread/scheduling-priorities */ + int result = SetPriorityClass( + reinterpret_cast(mainThread.native_handle()), + ABOVE_NORMAL_PRIORITY_CLASS); + if(result != 0) { + sif::error << "PeriodicTask: Windows SetPriorityClass failed with code " + << GetLastError() << std::endl; + } + result = SetThreadPriority( + reinterpret_cast(mainThread.native_handle()), + THREAD_PRIORITY_NORMAL); + if(result != 0) { + sif::error << "PeriodicTask: Windows SetPriorityClass failed with code " + << GetLastError() << std::endl; + } +#elif defined(LINUX) + // we can just copy and paste the code from linux here. +#endif +} + +PeriodicTask::~PeriodicTask(void) { + //Do not delete objects, we were responsible for ptrs only. + terminateThread = true; + if(mainThread.joinable()) { + mainThread.join(); + } + delete this; +} + +void PeriodicTask::taskEntryPoint(void* argument) { + PeriodicTask *originalTask(reinterpret_cast(argument)); + + + if (not originalTask->started) { + // we have to suspend/block here until the task is started. + // if semaphores are implemented, use them here. + std::unique_lock lock(initMutex); + initCondition.wait(lock); + } + + this->taskFunctionality(); + sif::debug << "PeriodicTask::taskEntryPoint: " + "Returned from taskFunctionality." << std::endl; +} + +ReturnValue_t PeriodicTask::startTask() { + started = true; + + // Notify task to start. + std::lock_guard lock(initMutex); + initCondition.notify_one(); + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t PeriodicTask::sleepFor(uint32_t ms) { + std::this_thread::sleep_for(std::chrono::milliseconds(ms)); + return HasReturnvaluesIF::RETURN_OK; +} + +void PeriodicTask::taskFunctionality() { + std::chrono::milliseconds periodChrono(static_cast(period*1000)); + auto currentStartTime { + std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()) + }; + auto nextStartTime{ currentStartTime }; + + /* Enter the loop that defines the task behavior. */ + for (;;) { + if(terminateThread.load()) { + break; + } + for (ObjectList::iterator it = objectList.begin(); + it != objectList.end(); ++it) { + (*it)->performOperation(); + } + if(not delayForInterval(¤tStartTime, periodChrono)) { + sif::warning << "PeriodicTask: " << taskName << + " missed deadline!\n" << std::flush; + if(deadlineMissedFunc != nullptr) { + this->deadlineMissedFunc(); + } + } + } +} + +ReturnValue_t PeriodicTask::addComponent(object_id_t object) { + ExecutableObjectIF* newObject = objectManager->get( + object); + if (newObject == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + objectList.push_back(newObject); + return HasReturnvaluesIF::RETURN_OK; +} + +uint32_t PeriodicTask::getPeriodMs() const { + return period * 1000; +} + +bool PeriodicTask::delayForInterval(chron_ms* previousWakeTimeMs, + const chron_ms interval) { + bool shouldDelay = false; + //Get current wakeup time + auto currentStartTime = + std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()); + /* Generate the tick time at which the task wants to wake. */ + auto nextTimeToWake_ms = (*previousWakeTimeMs) + interval; + + if (currentStartTime < *previousWakeTimeMs) { + /* The tick count has overflowed since this function was + lasted called. In this case the only time we should ever + actually delay is if the wake time has also overflowed, + and the wake time is greater than the tick time. When this + is the case it is as if neither time had overflowed. */ + if ((nextTimeToWake_ms < *previousWakeTimeMs) + && (nextTimeToWake_ms > currentStartTime)) { + shouldDelay = true; + } + } else { + /* The tick time has not overflowed. In this case we will + delay if either the wake time has overflowed, and/or the + tick time is less than the wake time. */ + if ((nextTimeToWake_ms < *previousWakeTimeMs) + || (nextTimeToWake_ms > currentStartTime)) { + shouldDelay = true; + } + } + + /* Update the wake time ready for the next call. */ + + (*previousWakeTimeMs) = nextTimeToWake_ms; + + if (shouldDelay) { + auto sleepTime = std::chrono::duration_cast( + nextTimeToWake_ms - currentStartTime); + std::this_thread::sleep_for(sleepTime); + return true; + } + //We are shifting the time in case the deadline was missed like rtems + (*previousWakeTimeMs) = currentStartTime; + return false; + +} diff --git a/osal/host/PeriodicTask.h b/osal/host/PeriodicTask.h index d97bf089..7eb768cb 100644 --- a/osal/host/PeriodicTask.h +++ b/osal/host/PeriodicTask.h @@ -1,123 +1,123 @@ -#ifndef FRAMEWORK_OSAL_HOST_PERIODICTASK_H_ -#define FRAMEWORK_OSAL_HOST_PERIODICTASK_H_ - -#include -#include -#include - -#include -#include -#include -#include - -class ExecutableObjectIF; - -/** - * @brief This class represents a specialized task for - * periodic activities of multiple objects. - * @details - * - * @ingroup task_handling - */ -class PeriodicTask: public PeriodicTaskIF { -public: - /** - * @brief Standard constructor of the class. - * @details - * The class is initialized without allocated objects. These need to be - * added with #addComponent. - * @param priority - * @param stack_size - * @param setPeriod - * @param setDeadlineMissedFunc - * The function pointer to the deadline missed function that shall be - * assigned. - */ - PeriodicTask(const char *name, TaskPriority setPriority, TaskStackSize setStack, - TaskPeriod setPeriod,void (*setDeadlineMissedFunc)()); - /** - * @brief Currently, the executed object's lifetime is not coupled with - * the task object's lifetime, so the destructor is empty. - */ - virtual ~PeriodicTask(void); - - /** - * @brief The method to start the task. - * @details The method starts the task with the respective system call. - * Entry point is the taskEntryPoint method described below. - * The address of the task object is passed as an argument - * to the system call. - */ - ReturnValue_t startTask(void); - /** - * Adds an object to the list of objects to be executed. - * The objects are executed in the order added. - * @param object Id of the object to add. - * @return - * -@c RETURN_OK on success - * -@c RETURN_FAILED if the object could not be added. - */ - ReturnValue_t addComponent(object_id_t object); - - uint32_t getPeriodMs() const; - - ReturnValue_t sleepFor(uint32_t ms); - -protected: - using chron_ms = std::chrono::milliseconds; - bool started; - //!< Typedef for the List of objects. - typedef std::vector ObjectList; - std::thread mainThread; - std::atomic terminateThread = false; - - /** - * @brief This attribute holds a list of objects to be executed. - */ - ObjectList objectList; - - std::condition_variable initCondition; - std::mutex initMutex; - std::string taskName; - /** - * @brief The period of the task. - * @details - * The period determines the frequency of the task's execution. - * It is expressed in clock ticks. - */ - TaskPeriod period; - /** - * @brief The pointer to the deadline-missed function. - * @details - * This pointer stores the function that is executed if the task's deadline - * is missed. So, each may react individually on a timing failure. - * The pointer may be NULL, then nothing happens on missing the deadline. - * The deadline is equal to the next execution of the periodic task. - */ - void (*deadlineMissedFunc)(void); - /** - * @brief This is the function executed in the new task's context. - * @details - * It converts the argument back to the thread object type and copies the - * class instance to the task context. - * The taskFunctionality method is called afterwards. - * @param A pointer to the task object itself is passed as argument. - */ - - void taskEntryPoint(void* argument); - /** - * @brief The function containing the actual functionality of the task. - * @details - * The method sets and starts the task's period, then enters a loop that is - * repeated as long as the isRunning attribute is true. Within the loop, - * all performOperation methods of the added objects are called. Afterwards - * the checkAndRestartPeriod system call blocks the task until the next - * period. On missing the deadline, the deadlineMissedFunction is executed. - */ - void taskFunctionality(void); - - bool delayForInterval(chron_ms * previousWakeTimeMs, - const chron_ms interval); -}; - -#endif /* PERIODICTASK_H_ */ +#ifndef FRAMEWORK_OSAL_HOST_PERIODICTASK_H_ +#define FRAMEWORK_OSAL_HOST_PERIODICTASK_H_ + +#include "../../objectmanager/ObjectManagerIF.h" +#include "../../tasks/PeriodicTaskIF.h" +#include "../../tasks/Typedef.h" + +#include +#include +#include +#include + +class ExecutableObjectIF; + +/** + * @brief This class represents a specialized task for + * periodic activities of multiple objects. + * @details + * + * @ingroup task_handling + */ +class PeriodicTask: public PeriodicTaskIF { +public: + /** + * @brief Standard constructor of the class. + * @details + * The class is initialized without allocated objects. These need to be + * added with #addComponent. + * @param priority + * @param stack_size + * @param setPeriod + * @param setDeadlineMissedFunc + * The function pointer to the deadline missed function that shall be + * assigned. + */ + PeriodicTask(const char *name, TaskPriority setPriority, TaskStackSize setStack, + TaskPeriod setPeriod,void (*setDeadlineMissedFunc)()); + /** + * @brief Currently, the executed object's lifetime is not coupled with + * the task object's lifetime, so the destructor is empty. + */ + virtual ~PeriodicTask(void); + + /** + * @brief The method to start the task. + * @details The method starts the task with the respective system call. + * Entry point is the taskEntryPoint method described below. + * The address of the task object is passed as an argument + * to the system call. + */ + ReturnValue_t startTask(void); + /** + * Adds an object to the list of objects to be executed. + * The objects are executed in the order added. + * @param object Id of the object to add. + * @return + * -@c RETURN_OK on success + * -@c RETURN_FAILED if the object could not be added. + */ + ReturnValue_t addComponent(object_id_t object); + + uint32_t getPeriodMs() const; + + ReturnValue_t sleepFor(uint32_t ms); + +protected: + using chron_ms = std::chrono::milliseconds; + bool started; + //!< Typedef for the List of objects. + typedef std::vector ObjectList; + std::thread mainThread; + std::atomic terminateThread = false; + + /** + * @brief This attribute holds a list of objects to be executed. + */ + ObjectList objectList; + + std::condition_variable initCondition; + std::mutex initMutex; + std::string taskName; + /** + * @brief The period of the task. + * @details + * The period determines the frequency of the task's execution. + * It is expressed in clock ticks. + */ + TaskPeriod period; + /** + * @brief The pointer to the deadline-missed function. + * @details + * This pointer stores the function that is executed if the task's deadline + * is missed. So, each may react individually on a timing failure. + * The pointer may be NULL, then nothing happens on missing the deadline. + * The deadline is equal to the next execution of the periodic task. + */ + void (*deadlineMissedFunc)(void); + /** + * @brief This is the function executed in the new task's context. + * @details + * It converts the argument back to the thread object type and copies the + * class instance to the task context. + * The taskFunctionality method is called afterwards. + * @param A pointer to the task object itself is passed as argument. + */ + + void taskEntryPoint(void* argument); + /** + * @brief The function containing the actual functionality of the task. + * @details + * The method sets and starts the task's period, then enters a loop that is + * repeated as long as the isRunning attribute is true. Within the loop, + * all performOperation methods of the added objects are called. Afterwards + * the checkAndRestartPeriod system call blocks the task until the next + * period. On missing the deadline, the deadlineMissedFunction is executed. + */ + void taskFunctionality(void); + + bool delayForInterval(chron_ms * previousWakeTimeMs, + const chron_ms interval); +}; + +#endif /* PERIODICTASK_H_ */ diff --git a/osal/host/QueueFactory.cpp b/osal/host/QueueFactory.cpp index 225bb8c7..052671ca 100644 --- a/osal/host/QueueFactory.cpp +++ b/osal/host/QueueFactory.cpp @@ -1,41 +1,41 @@ -#include -#include -#include -#include - -QueueFactory* QueueFactory::factoryInstance = nullptr; - - -ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo, - MessageQueueMessageIF* message, MessageQueueId_t sentFrom, - bool ignoreFault) { - return MessageQueue::sendMessageFromMessageQueue(sendTo,message, - sentFrom,ignoreFault); - return HasReturnvaluesIF::RETURN_OK; -} - -QueueFactory* QueueFactory::instance() { - if (factoryInstance == nullptr) { - factoryInstance = new QueueFactory; - } - return factoryInstance; -} - -QueueFactory::QueueFactory() { -} - -QueueFactory::~QueueFactory() { -} - -MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, - size_t maxMessageSize) { - // A thread-safe queue can be implemented by using a combination - // of std::queue and std::mutex. This uses dynamic memory allocation - // which could be alleviated by using a custom allocator, external library - // (etl::queue) or simply using std::queue, we're on a host machine anyway. - return new MessageQueue(messageDepth, maxMessageSize); -} - -void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { - delete queue; -} +#include "../../ipc/QueueFactory.h" +#include "../../osal/host/MessageQueue.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" +#include + +QueueFactory* QueueFactory::factoryInstance = nullptr; + + +ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo, + MessageQueueMessageIF* message, MessageQueueId_t sentFrom, + bool ignoreFault) { + return MessageQueue::sendMessageFromMessageQueue(sendTo,message, + sentFrom,ignoreFault); + return HasReturnvaluesIF::RETURN_OK; +} + +QueueFactory* QueueFactory::instance() { + if (factoryInstance == nullptr) { + factoryInstance = new QueueFactory; + } + return factoryInstance; +} + +QueueFactory::QueueFactory() { +} + +QueueFactory::~QueueFactory() { +} + +MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, + size_t maxMessageSize) { + // A thread-safe queue can be implemented by using a combination + // of std::queue and std::mutex. This uses dynamic memory allocation + // which could be alleviated by using a custom allocator, external library + // (etl::queue) or simply using std::queue, we're on a host machine anyway. + return new MessageQueue(messageDepth, maxMessageSize); +} + +void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { + delete queue; +} diff --git a/osal/host/QueueMapManager.cpp b/osal/host/QueueMapManager.cpp index 89b9a948..35db204e 100644 --- a/osal/host/QueueMapManager.cpp +++ b/osal/host/QueueMapManager.cpp @@ -1,51 +1,51 @@ -#include -#include -#include - -QueueMapManager* QueueMapManager::mqManagerInstance = nullptr; - -QueueMapManager::QueueMapManager() { - mapLock = MutexFactory::instance()->createMutex(); -} - -QueueMapManager* QueueMapManager::instance() { - if (mqManagerInstance == nullptr){ - mqManagerInstance = new QueueMapManager(); - } - return QueueMapManager::mqManagerInstance; -} - -ReturnValue_t QueueMapManager::addMessageQueue( - MessageQueueIF* queueToInsert, MessageQueueId_t* id) { - // Not thread-safe, but it is assumed all message queues are created - // at software initialization now. If this is to be made thread-safe in - // the future, it propably would be sufficient to lock the increment - // operation here - uint32_t currentId = queueCounter++; - auto returnPair = queueMap.emplace(currentId, queueToInsert); - if(not returnPair.second) { - // this should never happen for the atomic variable. - sif::error << "QueueMapManager: This ID is already inside the map!" - << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - if (id != nullptr) { - *id = currentId; - } - return HasReturnvaluesIF::RETURN_OK; -} - -MessageQueueIF* QueueMapManager::getMessageQueue( - MessageQueueId_t messageQueueId) const { - MutexHelper(mapLock, 50); - auto queueIter = queueMap.find(messageQueueId); - if(queueIter != queueMap.end()) { - return queueIter->second; - } - else { - sif::warning << "QueueMapManager::getQueueHandle: The ID" << - messageQueueId << " does not exists in the map" << std::endl; - return nullptr; - } -} - +#include "../../ipc/MutexFactory.h" +#include "../../ipc/MutexHelper.h" +#include "../../osal/host/QueueMapManager.h" + +QueueMapManager* QueueMapManager::mqManagerInstance = nullptr; + +QueueMapManager::QueueMapManager() { + mapLock = MutexFactory::instance()->createMutex(); +} + +QueueMapManager* QueueMapManager::instance() { + if (mqManagerInstance == nullptr){ + mqManagerInstance = new QueueMapManager(); + } + return QueueMapManager::mqManagerInstance; +} + +ReturnValue_t QueueMapManager::addMessageQueue( + MessageQueueIF* queueToInsert, MessageQueueId_t* id) { + // Not thread-safe, but it is assumed all message queues are created + // at software initialization now. If this is to be made thread-safe in + // the future, it propably would be sufficient to lock the increment + // operation here + uint32_t currentId = queueCounter++; + auto returnPair = queueMap.emplace(currentId, queueToInsert); + if(not returnPair.second) { + // this should never happen for the atomic variable. + sif::error << "QueueMapManager: This ID is already inside the map!" + << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + if (id != nullptr) { + *id = currentId; + } + return HasReturnvaluesIF::RETURN_OK; +} + +MessageQueueIF* QueueMapManager::getMessageQueue( + MessageQueueId_t messageQueueId) const { + MutexHelper(mapLock, 50); + auto queueIter = queueMap.find(messageQueueId); + if(queueIter != queueMap.end()) { + return queueIter->second; + } + else { + sif::warning << "QueueMapManager::getQueueHandle: The ID" << + messageQueueId << " does not exists in the map" << std::endl; + return nullptr; + } +} + diff --git a/osal/host/QueueMapManager.h b/osal/host/QueueMapManager.h index a2a1b658..acf20389 100644 --- a/osal/host/QueueMapManager.h +++ b/osal/host/QueueMapManager.h @@ -1,47 +1,47 @@ -#ifndef FRAMEWORK_OSAL_HOST_QUEUEMAP_H_ -#define FRAMEWORK_OSAL_HOST_QUEUEMAP_H_ - -#include -#include -#include -#include - -using QueueMap = std::unordered_map; - - -/** - * An internal map to map message queue IDs to message queues. - * This propably should be a singleton.. - */ -class QueueMapManager { -public: - //! Returns the single instance of SemaphoreFactory. - static QueueMapManager* instance(); - - /** - * Insert a message queue into the map and returns a message queue ID - * @param queue The message queue to insert. - * @param id The passed value will be set unless a nullptr is passed - * @return - */ - ReturnValue_t addMessageQueue(MessageQueueIF* queue, MessageQueueId_t* - id = nullptr); - /** - * Get the message queue handle by providing a message queue ID. - * @param messageQueueId - * @return - */ - MessageQueueIF* getMessageQueue(MessageQueueId_t messageQueueId) const; - -private: - //! External instantiation is forbidden. - QueueMapManager(); - uint32_t queueCounter = 1; - MutexIF* mapLock; - QueueMap queueMap; - static QueueMapManager* mqManagerInstance; -}; - - - -#endif /* FRAMEWORK_OSAL_HOST_QUEUEMAP_H_ */ +#ifndef FRAMEWORK_OSAL_HOST_QUEUEMAP_H_ +#define FRAMEWORK_OSAL_HOST_QUEUEMAP_H_ + +#include "../../ipc/MessageQueueSenderIF.h" +#include "../../osal/host/MessageQueue.h" +#include +#include + +using QueueMap = std::unordered_map; + + +/** + * An internal map to map message queue IDs to message queues. + * This propably should be a singleton.. + */ +class QueueMapManager { +public: + //! Returns the single instance of SemaphoreFactory. + static QueueMapManager* instance(); + + /** + * Insert a message queue into the map and returns a message queue ID + * @param queue The message queue to insert. + * @param id The passed value will be set unless a nullptr is passed + * @return + */ + ReturnValue_t addMessageQueue(MessageQueueIF* queue, MessageQueueId_t* + id = nullptr); + /** + * Get the message queue handle by providing a message queue ID. + * @param messageQueueId + * @return + */ + MessageQueueIF* getMessageQueue(MessageQueueId_t messageQueueId) const; + +private: + //! External instantiation is forbidden. + QueueMapManager(); + uint32_t queueCounter = 1; + MutexIF* mapLock; + QueueMap queueMap; + static QueueMapManager* mqManagerInstance; +}; + + + +#endif /* FRAMEWORK_OSAL_HOST_QUEUEMAP_H_ */ diff --git a/osal/host/SemaphoreFactory.cpp b/osal/host/SemaphoreFactory.cpp index 0c077f68..58040428 100644 --- a/osal/host/SemaphoreFactory.cpp +++ b/osal/host/SemaphoreFactory.cpp @@ -1,42 +1,42 @@ -#include -#include -#include -#include - -const uint32_t SemaphoreIF::POLLING = 0; -const uint32_t SemaphoreIF::BLOCKING = 0xFFFFFFFF; - -SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr; - -SemaphoreFactory::SemaphoreFactory() { -} - -SemaphoreFactory::~SemaphoreFactory() { - delete factoryInstance; -} - -SemaphoreFactory* SemaphoreFactory::instance() { - if (factoryInstance == nullptr){ - factoryInstance = new SemaphoreFactory(); - } - return SemaphoreFactory::factoryInstance; -} - -SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t arguments) { - // Just gonna wait for full C++20 for now. - sif::error << "SemaphoreFactory: Binary Semaphore not implemented yet." - " Returning nullptr!\n" << std::flush; - return nullptr; -} - -SemaphoreIF* SemaphoreFactory::createCountingSemaphore(const uint8_t maxCount, - uint8_t initCount, uint32_t arguments) { - // Just gonna wait for full C++20 for now. - sif::error << "SemaphoreFactory: Counting Semaphore not implemented yet." - " Returning nullptr!\n" << std::flush; - return nullptr; -} - -void SemaphoreFactory::deleteSemaphore(SemaphoreIF* semaphore) { - delete semaphore; -} +#include "../../tasks/SemaphoreFactory.h" +#include "../../osal/linux/BinarySemaphore.h" +#include "../../osal/linux/CountingSemaphore.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" + +const uint32_t SemaphoreIF::POLLING = 0; +const uint32_t SemaphoreIF::BLOCKING = 0xFFFFFFFF; + +SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr; + +SemaphoreFactory::SemaphoreFactory() { +} + +SemaphoreFactory::~SemaphoreFactory() { + delete factoryInstance; +} + +SemaphoreFactory* SemaphoreFactory::instance() { + if (factoryInstance == nullptr){ + factoryInstance = new SemaphoreFactory(); + } + return SemaphoreFactory::factoryInstance; +} + +SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t arguments) { + // Just gonna wait for full C++20 for now. + sif::error << "SemaphoreFactory: Binary Semaphore not implemented yet." + " Returning nullptr!\n" << std::flush; + return nullptr; +} + +SemaphoreIF* SemaphoreFactory::createCountingSemaphore(const uint8_t maxCount, + uint8_t initCount, uint32_t arguments) { + // Just gonna wait for full C++20 for now. + sif::error << "SemaphoreFactory: Counting Semaphore not implemented yet." + " Returning nullptr!\n" << std::flush; + return nullptr; +} + +void SemaphoreFactory::deleteSemaphore(SemaphoreIF* semaphore) { + delete semaphore; +} diff --git a/osal/host/TaskFactory.cpp b/osal/host/TaskFactory.cpp index 9db8ac4d..3f527130 100644 --- a/osal/host/TaskFactory.cpp +++ b/osal/host/TaskFactory.cpp @@ -1,55 +1,55 @@ -#include -#include -#include -#include -#include - -#include - -TaskFactory* TaskFactory::factoryInstance = new TaskFactory(); - -// Will propably not be used for hosted implementation -const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = 0; - -TaskFactory::TaskFactory() { -} - -TaskFactory::~TaskFactory() { -} - -TaskFactory* TaskFactory::instance() { - return TaskFactory::factoryInstance; -} - -PeriodicTaskIF* TaskFactory::createPeriodicTask(TaskName name_, - TaskPriority taskPriority_,TaskStackSize stackSize_, - TaskPeriod periodInSeconds_, - TaskDeadlineMissedFunction deadLineMissedFunction_) { - // This is going to be interesting. Time now learn the C++ threading library - // :-) - return new PeriodicTask(name_, taskPriority_, stackSize_, periodInSeconds_, - deadLineMissedFunction_); -} - -FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(TaskName name_, - TaskPriority taskPriority_,TaskStackSize stackSize_, - TaskPeriod periodInSeconds_, - TaskDeadlineMissedFunction deadLineMissedFunction_) { - // This is going to be interesting. Time now learn the C++ threading library - // :-) - return new FixedTimeslotTask(name_, taskPriority_, stackSize_, - periodInSeconds_, deadLineMissedFunction_); -} - -ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) { - // This might block for some time! - delete task; - return HasReturnvaluesIF::RETURN_FAILED; -} - -ReturnValue_t TaskFactory::delayTask(uint32_t delayMs){ - std::this_thread::sleep_for(std::chrono::milliseconds(delayMs)); - return HasReturnvaluesIF::RETURN_OK; -} - - +#include "../../osal/host/FixedTimeslotTask.h" +#include "../../osal/host/PeriodicTask.h" +#include "../../tasks/TaskFactory.h" +#include "../../returnvalues/HasReturnvaluesIF.h" +#include "../../tasks/PeriodicTaskIF.h" + +#include + +TaskFactory* TaskFactory::factoryInstance = new TaskFactory(); + +// Will propably not be used for hosted implementation +const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = 0; + +TaskFactory::TaskFactory() { +} + +TaskFactory::~TaskFactory() { +} + +TaskFactory* TaskFactory::instance() { + return TaskFactory::factoryInstance; +} + +PeriodicTaskIF* TaskFactory::createPeriodicTask(TaskName name_, + TaskPriority taskPriority_,TaskStackSize stackSize_, + TaskPeriod periodInSeconds_, + TaskDeadlineMissedFunction deadLineMissedFunction_) { + // This is going to be interesting. Time now learn the C++ threading library + // :-) + return new PeriodicTask(name_, taskPriority_, stackSize_, periodInSeconds_, + deadLineMissedFunction_); +} + +FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(TaskName name_, + TaskPriority taskPriority_,TaskStackSize stackSize_, + TaskPeriod periodInSeconds_, + TaskDeadlineMissedFunction deadLineMissedFunction_) { + // This is going to be interesting. Time now learn the C++ threading library + // :-) + return new FixedTimeslotTask(name_, taskPriority_, stackSize_, + periodInSeconds_, deadLineMissedFunction_); +} + +ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) { + // This might block for some time! + delete task; + return HasReturnvaluesIF::RETURN_FAILED; +} + +ReturnValue_t TaskFactory::delayTask(uint32_t delayMs){ + std::this_thread::sleep_for(std::chrono::milliseconds(delayMs)); + return HasReturnvaluesIF::RETURN_OK; +} + + diff --git a/osal/linux/BinarySemaphore.cpp b/osal/linux/BinarySemaphore.cpp index e2ad9b58..37947b26 100644 --- a/osal/linux/BinarySemaphore.cpp +++ b/osal/linux/BinarySemaphore.cpp @@ -1,5 +1,5 @@ -#include -#include +#include "../../osal/linux/BinarySemaphore.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" extern "C" { #include diff --git a/osal/linux/BinarySemaphore.h b/osal/linux/BinarySemaphore.h index 9d4ed1cd..9ac9ba7f 100644 --- a/osal/linux/BinarySemaphore.h +++ b/osal/linux/BinarySemaphore.h @@ -1,8 +1,8 @@ #ifndef FRAMEWORK_OSAL_LINUX_BINARYSEMPAHORE_H_ #define FRAMEWORK_OSAL_LINUX_BINARYSEMPAHORE_H_ -#include -#include +#include "../../returnvalues/HasReturnvaluesIF.h" +#include "../../tasks/SemaphoreIF.h" extern "C" { #include diff --git a/osal/linux/Clock.cpp b/osal/linux/Clock.cpp index eda5b7af..370c77f7 100644 --- a/osal/linux/Clock.cpp +++ b/osal/linux/Clock.cpp @@ -1,220 +1,220 @@ -#include -#include - -#include -#include -#include -#include -#include - -//#include -uint16_t Clock::leapSeconds = 0; -MutexIF* Clock::timeMutex = NULL; - -uint32_t Clock::getTicksPerSecond(void){ - uint32_t ticks = sysconf(_SC_CLK_TCK); - return ticks; -} - -ReturnValue_t Clock::setClock(const TimeOfDay_t* time) { - timespec timeUnix; - timeval timeTimeval; - convertTimeOfDayToTimeval(time,&timeTimeval); - timeUnix.tv_sec = timeTimeval.tv_sec; - timeUnix.tv_nsec = (__syscall_slong_t) timeTimeval.tv_usec * 1000; - - int status = clock_settime(CLOCK_REALTIME,&timeUnix); - if(status!=0){ - //TODO errno - return HasReturnvaluesIF::RETURN_FAILED; - } - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t Clock::setClock(const timeval* time) { - timespec timeUnix; - timeUnix.tv_sec = time->tv_sec; - timeUnix.tv_nsec = (__syscall_slong_t) time->tv_usec * 1000; - int status = clock_settime(CLOCK_REALTIME,&timeUnix); - if(status!=0){ - //TODO errno - return HasReturnvaluesIF::RETURN_FAILED; - } - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t Clock::getClock_timeval(timeval* time) { - timespec timeUnix; - int status = clock_gettime(CLOCK_REALTIME,&timeUnix); - if(status!=0){ - return HasReturnvaluesIF::RETURN_FAILED; - } - time->tv_sec = timeUnix.tv_sec; - time->tv_usec = timeUnix.tv_nsec / 1000.0; - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t Clock::getClock_usecs(uint64_t* time) { - timeval timeVal; - ReturnValue_t result = getClock_timeval(&timeVal); - if(result != HasReturnvaluesIF::RETURN_OK){ - return result; - } - *time = (uint64_t)timeVal.tv_sec*1e6 + timeVal.tv_usec; - - return HasReturnvaluesIF::RETURN_OK; -} - -timeval Clock::getUptime() { - timeval uptime; - auto result = getUptime(&uptime); - if(result != HasReturnvaluesIF::RETURN_OK) { - sif::error << "Clock::getUptime: Error getting uptime" << std::endl; - } - return uptime; -} - -ReturnValue_t Clock::getUptime(timeval* uptime) { - //TODO This is not posix compatible and delivers only seconds precision - struct sysinfo sysInfo; - int result = sysinfo(&sysInfo); - if(result != 0){ - return HasReturnvaluesIF::RETURN_FAILED; - } - uptime->tv_sec = sysInfo.uptime; - uptime->tv_usec = 0; - - - //Linux specific file read but more precise -// double uptimeSeconds; -// if(std::ifstream("/proc/uptime",std::ios::in) >> uptimeSeconds){ -// uptime->tv_sec = uptimeSeconds; -// uptime->tv_usec = uptimeSeconds *(double) 1e6 - (uptime->tv_sec *1e6); -// } - - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) { - timeval uptime; - ReturnValue_t result = getUptime(&uptime); - if(result != HasReturnvaluesIF::RETURN_OK){ - return result; - } - *uptimeMs = uptime.tv_sec * 1e3 + uptime.tv_usec / 1e3; - return HasReturnvaluesIF::RETURN_OK; -} - - - -ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) { - timespec timeUnix; - int status = clock_gettime(CLOCK_REALTIME,&timeUnix); - if(status != 0){ - //TODO errno - return HasReturnvaluesIF::RETURN_FAILED; - } - - struct tm* timeInfo; - timeInfo = gmtime(&timeUnix.tv_sec); - time->year = timeInfo->tm_year + 1900; - time->month = timeInfo->tm_mon+1; - time->day = timeInfo->tm_mday; - time->hour = timeInfo->tm_hour; - time->minute = timeInfo->tm_min; - time->second = timeInfo->tm_sec; - time->usecond = timeUnix.tv_nsec / 1000.0; - - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from, - timeval* to) { - - tm fromTm; - //Note: Fails for years before AD - fromTm.tm_year = from->year - 1900; - fromTm.tm_mon = from->month - 1; - fromTm.tm_mday = from->day; - fromTm.tm_hour = from->hour; - fromTm.tm_min = from->minute; - fromTm.tm_sec = from->second; - - to->tv_sec = mktime(&fromTm); - to->tv_usec = from->usecond; - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) { - *JD2000 = (time.tv_sec - 946728000. + time.tv_usec / 1000000.) / 24. - / 3600.; - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) { - //SHOULDDO: works not for dates in the past (might have less leap seconds) - if (timeMutex == NULL) { - return HasReturnvaluesIF::RETURN_FAILED; - } - - uint16_t leapSeconds; - ReturnValue_t result = getLeapSeconds(&leapSeconds); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - timeval leapSeconds_timeval = { 0, 0 }; - leapSeconds_timeval.tv_sec = leapSeconds; - - //initial offset between UTC and TAI - timeval UTCtoTAI1972 = { 10, 0 }; - - timeval TAItoTT = { 32, 184000 }; - - *tt = utc + leapSeconds_timeval + UTCtoTAI1972 + TAItoTT; - - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) { - if(checkOrCreateClockMutex()!=HasReturnvaluesIF::RETURN_OK){ - return HasReturnvaluesIF::RETURN_FAILED; - } - ReturnValue_t result = timeMutex->lockMutex(MutexIF::BLOCKING); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - leapSeconds = leapSeconds_; - - result = timeMutex->unlockMutex(); - return result; -} - -ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) { - if(timeMutex==NULL){ - return HasReturnvaluesIF::RETURN_FAILED; - } - ReturnValue_t result = timeMutex->lockMutex(MutexIF::BLOCKING); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - *leapSeconds_ = leapSeconds; - - result = timeMutex->unlockMutex(); - return result; -} - -ReturnValue_t Clock::checkOrCreateClockMutex(){ - if(timeMutex==NULL){ - MutexFactory* mutexFactory = MutexFactory::instance(); - if (mutexFactory == NULL) { - return HasReturnvaluesIF::RETURN_FAILED; - } - timeMutex = mutexFactory->createMutex(); - if (timeMutex == NULL) { - return HasReturnvaluesIF::RETURN_FAILED; - } - } - return HasReturnvaluesIF::RETURN_OK; -} +#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "../../timemanager/Clock.h" + +#include +#include +#include +#include +#include + +//#include +uint16_t Clock::leapSeconds = 0; +MutexIF* Clock::timeMutex = NULL; + +uint32_t Clock::getTicksPerSecond(void){ + uint32_t ticks = sysconf(_SC_CLK_TCK); + return ticks; +} + +ReturnValue_t Clock::setClock(const TimeOfDay_t* time) { + timespec timeUnix; + timeval timeTimeval; + convertTimeOfDayToTimeval(time,&timeTimeval); + timeUnix.tv_sec = timeTimeval.tv_sec; + timeUnix.tv_nsec = (__syscall_slong_t) timeTimeval.tv_usec * 1000; + + int status = clock_settime(CLOCK_REALTIME,&timeUnix); + if(status!=0){ + //TODO errno + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Clock::setClock(const timeval* time) { + timespec timeUnix; + timeUnix.tv_sec = time->tv_sec; + timeUnix.tv_nsec = (__syscall_slong_t) time->tv_usec * 1000; + int status = clock_settime(CLOCK_REALTIME,&timeUnix); + if(status!=0){ + //TODO errno + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Clock::getClock_timeval(timeval* time) { + timespec timeUnix; + int status = clock_gettime(CLOCK_REALTIME,&timeUnix); + if(status!=0){ + return HasReturnvaluesIF::RETURN_FAILED; + } + time->tv_sec = timeUnix.tv_sec; + time->tv_usec = timeUnix.tv_nsec / 1000.0; + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Clock::getClock_usecs(uint64_t* time) { + timeval timeVal; + ReturnValue_t result = getClock_timeval(&timeVal); + if(result != HasReturnvaluesIF::RETURN_OK){ + return result; + } + *time = (uint64_t)timeVal.tv_sec*1e6 + timeVal.tv_usec; + + return HasReturnvaluesIF::RETURN_OK; +} + +timeval Clock::getUptime() { + timeval uptime; + auto result = getUptime(&uptime); + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::error << "Clock::getUptime: Error getting uptime" << std::endl; + } + return uptime; +} + +ReturnValue_t Clock::getUptime(timeval* uptime) { + //TODO This is not posix compatible and delivers only seconds precision + struct sysinfo sysInfo; + int result = sysinfo(&sysInfo); + if(result != 0){ + return HasReturnvaluesIF::RETURN_FAILED; + } + uptime->tv_sec = sysInfo.uptime; + uptime->tv_usec = 0; + + + //Linux specific file read but more precise +// double uptimeSeconds; +// if(std::ifstream("/proc/uptime",std::ios::in) >> uptimeSeconds){ +// uptime->tv_sec = uptimeSeconds; +// uptime->tv_usec = uptimeSeconds *(double) 1e6 - (uptime->tv_sec *1e6); +// } + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) { + timeval uptime; + ReturnValue_t result = getUptime(&uptime); + if(result != HasReturnvaluesIF::RETURN_OK){ + return result; + } + *uptimeMs = uptime.tv_sec * 1e3 + uptime.tv_usec / 1e3; + return HasReturnvaluesIF::RETURN_OK; +} + + + +ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) { + timespec timeUnix; + int status = clock_gettime(CLOCK_REALTIME,&timeUnix); + if(status != 0){ + //TODO errno + return HasReturnvaluesIF::RETURN_FAILED; + } + + struct tm* timeInfo; + timeInfo = gmtime(&timeUnix.tv_sec); + time->year = timeInfo->tm_year + 1900; + time->month = timeInfo->tm_mon+1; + time->day = timeInfo->tm_mday; + time->hour = timeInfo->tm_hour; + time->minute = timeInfo->tm_min; + time->second = timeInfo->tm_sec; + time->usecond = timeUnix.tv_nsec / 1000.0; + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from, + timeval* to) { + + tm fromTm; + //Note: Fails for years before AD + fromTm.tm_year = from->year - 1900; + fromTm.tm_mon = from->month - 1; + fromTm.tm_mday = from->day; + fromTm.tm_hour = from->hour; + fromTm.tm_min = from->minute; + fromTm.tm_sec = from->second; + + to->tv_sec = mktime(&fromTm); + to->tv_usec = from->usecond; + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) { + *JD2000 = (time.tv_sec - 946728000. + time.tv_usec / 1000000.) / 24. + / 3600.; + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) { + //SHOULDDO: works not for dates in the past (might have less leap seconds) + if (timeMutex == NULL) { + return HasReturnvaluesIF::RETURN_FAILED; + } + + uint16_t leapSeconds; + ReturnValue_t result = getLeapSeconds(&leapSeconds); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + timeval leapSeconds_timeval = { 0, 0 }; + leapSeconds_timeval.tv_sec = leapSeconds; + + //initial offset between UTC and TAI + timeval UTCtoTAI1972 = { 10, 0 }; + + timeval TAItoTT = { 32, 184000 }; + + *tt = utc + leapSeconds_timeval + UTCtoTAI1972 + TAItoTT; + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) { + if(checkOrCreateClockMutex()!=HasReturnvaluesIF::RETURN_OK){ + return HasReturnvaluesIF::RETURN_FAILED; + } + ReturnValue_t result = timeMutex->lockMutex(MutexIF::BLOCKING); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + leapSeconds = leapSeconds_; + + result = timeMutex->unlockMutex(); + return result; +} + +ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) { + if(timeMutex==NULL){ + return HasReturnvaluesIF::RETURN_FAILED; + } + ReturnValue_t result = timeMutex->lockMutex(MutexIF::BLOCKING); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + *leapSeconds_ = leapSeconds; + + result = timeMutex->unlockMutex(); + return result; +} + +ReturnValue_t Clock::checkOrCreateClockMutex(){ + if(timeMutex==NULL){ + MutexFactory* mutexFactory = MutexFactory::instance(); + if (mutexFactory == NULL) { + return HasReturnvaluesIF::RETURN_FAILED; + } + timeMutex = mutexFactory->createMutex(); + if (timeMutex == NULL) { + return HasReturnvaluesIF::RETURN_FAILED; + } + } + return HasReturnvaluesIF::RETURN_OK; +} diff --git a/osal/linux/CountingSemaphore.cpp b/osal/linux/CountingSemaphore.cpp index dfc4d801..ef32539b 100644 --- a/osal/linux/CountingSemaphore.cpp +++ b/osal/linux/CountingSemaphore.cpp @@ -1,54 +1,54 @@ -#include -#include - -CountingSemaphore::CountingSemaphore(const uint8_t maxCount, uint8_t initCount): - maxCount(maxCount), initCount(initCount) { - if(initCount > maxCount) { - sif::error << "CountingSemaphoreUsingTask: Max count bigger than " - "intial cout. Setting initial count to max count." << std::endl; - initCount = maxCount; - } - - initSemaphore(initCount); -} - -CountingSemaphore::CountingSemaphore(CountingSemaphore&& other): - maxCount(other.maxCount), initCount(other.initCount) { - initSemaphore(initCount); -} - -CountingSemaphore& CountingSemaphore::operator =( - CountingSemaphore&& other) { - initSemaphore(other.initCount); - return * this; -} - -ReturnValue_t CountingSemaphore::release() { - ReturnValue_t result = checkCount(&handle, maxCount); - if(result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - return CountingSemaphore::release(&this->handle); -} - -ReturnValue_t CountingSemaphore::release(sem_t* handle) { - int result = sem_post(handle); - if(result == 0) { - return HasReturnvaluesIF::RETURN_OK; - } - - switch(errno) { - case(EINVAL): - // Semaphore invalid - return SemaphoreIF::SEMAPHORE_INVALID; - case(EOVERFLOW): - // SEM_MAX_VALUE overflow. This should never happen - default: - return HasReturnvaluesIF::RETURN_FAILED; - } -} - -uint8_t CountingSemaphore::getMaxCount() const { - return maxCount; -} - +#include "../../osal/linux/CountingSemaphore.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" + +CountingSemaphore::CountingSemaphore(const uint8_t maxCount, uint8_t initCount): + maxCount(maxCount), initCount(initCount) { + if(initCount > maxCount) { + sif::error << "CountingSemaphoreUsingTask: Max count bigger than " + "intial cout. Setting initial count to max count." << std::endl; + initCount = maxCount; + } + + initSemaphore(initCount); +} + +CountingSemaphore::CountingSemaphore(CountingSemaphore&& other): + maxCount(other.maxCount), initCount(other.initCount) { + initSemaphore(initCount); +} + +CountingSemaphore& CountingSemaphore::operator =( + CountingSemaphore&& other) { + initSemaphore(other.initCount); + return * this; +} + +ReturnValue_t CountingSemaphore::release() { + ReturnValue_t result = checkCount(&handle, maxCount); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return CountingSemaphore::release(&this->handle); +} + +ReturnValue_t CountingSemaphore::release(sem_t* handle) { + int result = sem_post(handle); + if(result == 0) { + return HasReturnvaluesIF::RETURN_OK; + } + + switch(errno) { + case(EINVAL): + // Semaphore invalid + return SemaphoreIF::SEMAPHORE_INVALID; + case(EOVERFLOW): + // SEM_MAX_VALUE overflow. This should never happen + default: + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +uint8_t CountingSemaphore::getMaxCount() const { + return maxCount; +} + diff --git a/osal/linux/CountingSemaphore.h b/osal/linux/CountingSemaphore.h index ba606595..afe21a61 100644 --- a/osal/linux/CountingSemaphore.h +++ b/osal/linux/CountingSemaphore.h @@ -1,37 +1,37 @@ -#ifndef FRAMEWORK_OSAL_LINUX_COUNTINGSEMAPHORE_H_ -#define FRAMEWORK_OSAL_LINUX_COUNTINGSEMAPHORE_H_ -#include - -/** - * @brief Counting semaphores, which can be acquired more than once. - * @details - * See: https://www.freertos.org/CreateCounting.html - * API of counting semaphores is almost identical to binary semaphores, - * so we just inherit from binary semaphore and provide the respective - * constructors. - */ -class CountingSemaphore: public BinarySemaphore { -public: - CountingSemaphore(const uint8_t maxCount, uint8_t initCount); - //! @brief Copy ctor, disabled - CountingSemaphore(const CountingSemaphore&) = delete; - //! @brief Copy assignment, disabled - CountingSemaphore& operator=(const CountingSemaphore&) = delete; - //! @brief Move ctor - CountingSemaphore (CountingSemaphore &&); - //! @brief Move assignment - CountingSemaphore & operator=(CountingSemaphore &&); - - ReturnValue_t release() override; - static ReturnValue_t release(sem_t* sem); - /* Same API as binary semaphore otherwise. acquire() can be called - * until there are not semaphores left and release() can be called - * until maxCount is reached. */ - - uint8_t getMaxCount() const; -private: - const uint8_t maxCount; - uint8_t initCount = 0; -}; - -#endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ */ +#ifndef FRAMEWORK_OSAL_LINUX_COUNTINGSEMAPHORE_H_ +#define FRAMEWORK_OSAL_LINUX_COUNTINGSEMAPHORE_H_ +#include "../../osal/linux/BinarySemaphore.h" + +/** + * @brief Counting semaphores, which can be acquired more than once. + * @details + * See: https://www.freertos.org/CreateCounting.html + * API of counting semaphores is almost identical to binary semaphores, + * so we just inherit from binary semaphore and provide the respective + * constructors. + */ +class CountingSemaphore: public BinarySemaphore { +public: + CountingSemaphore(const uint8_t maxCount, uint8_t initCount); + //! @brief Copy ctor, disabled + CountingSemaphore(const CountingSemaphore&) = delete; + //! @brief Copy assignment, disabled + CountingSemaphore& operator=(const CountingSemaphore&) = delete; + //! @brief Move ctor + CountingSemaphore (CountingSemaphore &&); + //! @brief Move assignment + CountingSemaphore & operator=(CountingSemaphore &&); + + ReturnValue_t release() override; + static ReturnValue_t release(sem_t* sem); + /* Same API as binary semaphore otherwise. acquire() can be called + * until there are not semaphores left and release() can be called + * until maxCount is reached. */ + + uint8_t getMaxCount() const; +private: + const uint8_t maxCount; + uint8_t initCount = 0; +}; + +#endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ */ diff --git a/osal/linux/FixedTimeslotTask.cpp b/osal/linux/FixedTimeslotTask.cpp index 9d7d08f6..60ce9a63 100644 --- a/osal/linux/FixedTimeslotTask.cpp +++ b/osal/linux/FixedTimeslotTask.cpp @@ -1,91 +1,91 @@ -#include -#include - -#include - -uint32_t FixedTimeslotTask::deadlineMissedCount = 0; -const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = PTHREAD_STACK_MIN; - -FixedTimeslotTask::FixedTimeslotTask(const char* name_, int priority_, - size_t stackSize_, uint32_t periodMs_): - PosixThread(name_,priority_,stackSize_),pst(periodMs_),started(false) { -} - -FixedTimeslotTask::~FixedTimeslotTask() { - -} - -void* FixedTimeslotTask::taskEntryPoint(void* arg) { - //The argument is re-interpreted as PollingTask. - FixedTimeslotTask *originalTask(reinterpret_cast(arg)); - //The task's functionality is called. - originalTask->taskFunctionality(); - return nullptr; -} - -ReturnValue_t FixedTimeslotTask::startTask() { - started = true; - createTask(&taskEntryPoint,this); - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) { - return PosixThread::sleep((uint64_t)ms*1000000); -} - -uint32_t FixedTimeslotTask::getPeriodMs() const { - return pst.getLengthMs(); -} - -ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, - uint32_t slotTimeMs, int8_t executionStep) { - if (objectManager->get(componentId) != nullptr) { - pst.addSlot(componentId, slotTimeMs, executionStep, this); - return HasReturnvaluesIF::RETURN_OK; - } - - sif::error << "Component " << std::hex << componentId << - " not found, not adding it to pst" << std::dec << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; -} - -ReturnValue_t FixedTimeslotTask::checkSequence() const { - return pst.checkSequence(); -} - -void FixedTimeslotTask::taskFunctionality() { - //Like FreeRTOS pthreads are running as soon as they are created - if (!started) { - suspend(); - } - //The start time for the first entry is read. - uint64_t lastWakeTime = getCurrentMonotonicTimeMs(); - uint64_t interval = pst.getIntervalToNextSlotMs(); - - - //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 = this->pst.getIntervalToPreviousSlotMs(); - //The period is checked and restarted with the new interval. - //If the deadline was missed, the deadlineMissedFunc is called. - if(!PosixThread::delayUntil(&lastWakeTime,interval)) { - //No time left on timer -> we missed the deadline - missedDeadlineCounter(); - } - } - //The device handler for this slot is executed and the next one is chosen. - this->pst.executeAndAdvance(); - } -} - -void FixedTimeslotTask::missedDeadlineCounter() { - FixedTimeslotTask::deadlineMissedCount++; - if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) { - sif::error << "PST missed " << FixedTimeslotTask::deadlineMissedCount - << " deadlines." << std::endl; - } -} +#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "../../osal/linux/FixedTimeslotTask.h" + +#include + +uint32_t FixedTimeslotTask::deadlineMissedCount = 0; +const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = PTHREAD_STACK_MIN; + +FixedTimeslotTask::FixedTimeslotTask(const char* name_, int priority_, + size_t stackSize_, uint32_t periodMs_): + PosixThread(name_,priority_,stackSize_),pst(periodMs_),started(false) { +} + +FixedTimeslotTask::~FixedTimeslotTask() { + +} + +void* FixedTimeslotTask::taskEntryPoint(void* arg) { + //The argument is re-interpreted as PollingTask. + FixedTimeslotTask *originalTask(reinterpret_cast(arg)); + //The task's functionality is called. + originalTask->taskFunctionality(); + return nullptr; +} + +ReturnValue_t FixedTimeslotTask::startTask() { + started = true; + createTask(&taskEntryPoint,this); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) { + return PosixThread::sleep((uint64_t)ms*1000000); +} + +uint32_t FixedTimeslotTask::getPeriodMs() const { + return pst.getLengthMs(); +} + +ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, + uint32_t slotTimeMs, int8_t executionStep) { + if (objectManager->get(componentId) != nullptr) { + pst.addSlot(componentId, slotTimeMs, executionStep, this); + return HasReturnvaluesIF::RETURN_OK; + } + + sif::error << "Component " << std::hex << componentId << + " not found, not adding it to pst" << std::dec << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; +} + +ReturnValue_t FixedTimeslotTask::checkSequence() const { + return pst.checkSequence(); +} + +void FixedTimeslotTask::taskFunctionality() { + //Like FreeRTOS pthreads are running as soon as they are created + if (!started) { + suspend(); + } + //The start time for the first entry is read. + uint64_t lastWakeTime = getCurrentMonotonicTimeMs(); + uint64_t interval = pst.getIntervalToNextSlotMs(); + + + //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 = this->pst.getIntervalToPreviousSlotMs(); + //The period is checked and restarted with the new interval. + //If the deadline was missed, the deadlineMissedFunc is called. + if(!PosixThread::delayUntil(&lastWakeTime,interval)) { + //No time left on timer -> we missed the deadline + missedDeadlineCounter(); + } + } + //The device handler for this slot is executed and the next one is chosen. + this->pst.executeAndAdvance(); + } +} + +void FixedTimeslotTask::missedDeadlineCounter() { + FixedTimeslotTask::deadlineMissedCount++; + if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) { + sif::error << "PST missed " << FixedTimeslotTask::deadlineMissedCount + << " deadlines." << std::endl; + } +} diff --git a/osal/linux/FixedTimeslotTask.h b/osal/linux/FixedTimeslotTask.h index 409cd982..83bf203e 100644 --- a/osal/linux/FixedTimeslotTask.h +++ b/osal/linux/FixedTimeslotTask.h @@ -1,77 +1,77 @@ -#ifndef FRAMEWORK_OSAL_LINUX_FIXEDTIMESLOTTASK_H_ -#define FRAMEWORK_OSAL_LINUX_FIXEDTIMESLOTTASK_H_ - -#include -#include -#include -#include - -class FixedTimeslotTask: public FixedTimeslotTaskIF, public PosixThread { -public: - /** - * Create a generic periodic task. - * @param name_ - * Name, maximum allowed size of linux is 16 chars, everything else will - * be truncated. - * @param priority_ - * Real-time priority, ranges from 1 to 99 for Linux. - * See: https://man7.org/linux/man-pages/man7/sched.7.html - * @param stackSize_ - * @param period_ - * @param deadlineMissedFunc_ - */ - FixedTimeslotTask(const char* name_, int priority_, size_t stackSize_, - uint32_t periodMs_); - virtual ~FixedTimeslotTask(); - - virtual ReturnValue_t startTask(); - - virtual ReturnValue_t sleepFor(uint32_t ms); - - virtual uint32_t getPeriodMs() const; - - virtual ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs, - int8_t executionStep); - - virtual ReturnValue_t checkSequence() const; - - /** - * 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; - -protected: - /** - * @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. - */ - virtual void taskFunctionality(); - -private: - /** - * @brief This is the entry point in a new thread. - * - * @details - * This method, that is the entry point in the new thread and calls - * taskFunctionality of the child class. Needs a valid pointer to the - * derived class. - * - * The void* returnvalue is not used yet but could be used to return - * arbitrary data. - */ - static void* taskEntryPoint(void* arg); - FixedSlotSequence pst; - - bool started; -}; - -#endif /* FRAMEWORK_OSAL_LINUX_FIXEDTIMESLOTTASK_H_ */ +#ifndef FRAMEWORK_OSAL_LINUX_FIXEDTIMESLOTTASK_H_ +#define FRAMEWORK_OSAL_LINUX_FIXEDTIMESLOTTASK_H_ + +#include "../../tasks/FixedTimeslotTaskIF.h" +#include "../../tasks/FixedSlotSequence.h" +#include "../../osal/linux/PosixThread.h" +#include + +class FixedTimeslotTask: public FixedTimeslotTaskIF, public PosixThread { +public: + /** + * Create a generic periodic task. + * @param name_ + * Name, maximum allowed size of linux is 16 chars, everything else will + * be truncated. + * @param priority_ + * Real-time priority, ranges from 1 to 99 for Linux. + * See: https://man7.org/linux/man-pages/man7/sched.7.html + * @param stackSize_ + * @param period_ + * @param deadlineMissedFunc_ + */ + FixedTimeslotTask(const char* name_, int priority_, size_t stackSize_, + uint32_t periodMs_); + virtual ~FixedTimeslotTask(); + + virtual ReturnValue_t startTask(); + + virtual ReturnValue_t sleepFor(uint32_t ms); + + virtual uint32_t getPeriodMs() const; + + virtual ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs, + int8_t executionStep); + + virtual ReturnValue_t checkSequence() const; + + /** + * 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; + +protected: + /** + * @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. + */ + virtual void taskFunctionality(); + +private: + /** + * @brief This is the entry point in a new thread. + * + * @details + * This method, that is the entry point in the new thread and calls + * taskFunctionality of the child class. Needs a valid pointer to the + * derived class. + * + * The void* returnvalue is not used yet but could be used to return + * arbitrary data. + */ + static void* taskEntryPoint(void* arg); + FixedSlotSequence pst; + + bool started; +}; + +#endif /* FRAMEWORK_OSAL_LINUX_FIXEDTIMESLOTTASK_H_ */ diff --git a/osal/linux/InternalErrorCodes.cpp b/osal/linux/InternalErrorCodes.cpp index 7f83663b..724cb4bc 100644 --- a/osal/linux/InternalErrorCodes.cpp +++ b/osal/linux/InternalErrorCodes.cpp @@ -1,14 +1,14 @@ -#include - -ReturnValue_t InternalErrorCodes::translate(uint8_t code) { - //TODO This class can be removed - return HasReturnvaluesIF::RETURN_FAILED; -} - -InternalErrorCodes::InternalErrorCodes() { -} - -InternalErrorCodes::~InternalErrorCodes() { - -} - +#include "../../osal/InternalErrorCodes.h" + +ReturnValue_t InternalErrorCodes::translate(uint8_t code) { + //TODO This class can be removed + return HasReturnvaluesIF::RETURN_FAILED; +} + +InternalErrorCodes::InternalErrorCodes() { +} + +InternalErrorCodes::~InternalErrorCodes() { + +} + diff --git a/osal/linux/MessageQueue.cpp b/osal/linux/MessageQueue.cpp index 236e61b6..97c89552 100644 --- a/osal/linux/MessageQueue.cpp +++ b/osal/linux/MessageQueue.cpp @@ -1,369 +1,369 @@ -#include -#include - -#include - -#include /* For O_* constants */ -#include /* For mode constants */ -#include -#include - - -MessageQueue::MessageQueue(uint32_t messageDepth, size_t maxMessageSize): - id(MessageQueueIF::NO_QUEUE),lastPartner(MessageQueueIF::NO_QUEUE), - defaultDestination(MessageQueueIF::NO_QUEUE), - maxMessageSize(maxMessageSize) { - //debug << "MessageQueue::MessageQueue: Creating a queue" << std::endl; - mq_attr attributes; - this->id = 0; - //Set attributes - attributes.mq_curmsgs = 0; - attributes.mq_maxmsg = messageDepth; - attributes.mq_msgsize = maxMessageSize; - attributes.mq_flags = 0; //Flags are ignored on Linux during mq_open - //Set the name of the queue. The slash is mandatory! - sprintf(name, "/FSFW_MQ%u\n", queueCounter++); - - // Create a nonblocking queue if the name is available (the queue is read - // and writable for the owner as well as the group) - int oflag = O_NONBLOCK | O_RDWR | O_CREAT | O_EXCL; - mode_t mode = S_IWUSR | S_IREAD | S_IWGRP | S_IRGRP | S_IROTH | S_IWOTH; - mqd_t tempId = mq_open(name, oflag, mode, &attributes); - if (tempId == -1) { - handleError(&attributes, messageDepth); - } - else { - //Successful mq_open call - this->id = tempId; - } -} - -MessageQueue::~MessageQueue() { - int status = mq_close(this->id); - if(status != 0){ - sif::error << "MessageQueue::Destructor: mq_close Failed with status: " - << strerror(errno) <> - defaultMqMaxMsg and defaultMqMaxMsg < messageDepth) { - /* - See: https://www.man7.org/linux/man-pages/man3/mq_open.3.html - This happens if the msg_max value is not large enough - It is ignored if the executable is run in privileged mode. - Run the unlockRealtime script or grant the mode manually by using: - sudo setcap 'CAP_SYS_RESOURCE=+ep' - - Persistent solution for session: - echo | sudo tee /proc/sys/fs/mqueue/msg_max - - Permanent solution: - sudo nano /etc/sysctl.conf - Append at end: fs/mqueue/msg_max = - Apply changes with: sudo sysctl -p - */ - sif::error << "MessageQueue::MessageQueue: Default MQ size " - << defaultMqMaxMsg << " is too small for requested size " - << messageDepth << std::endl; - sif::error << "This error can be fixed by setting the maximum " - "allowed message size higher!" << std::endl; - - } - break; - } - case(EEXIST): { - // An error occured during open - // We need to distinguish if it is caused by an already created queue - //There's another queue with the same name - //We unlink the other queue - int status = mq_unlink(name); - if (status != 0) { - sif::error << "mq_unlink Failed with status: " << strerror(errno) - << std::endl; - } - else { - // Successful unlinking, try to open again - mqd_t tempId = mq_open(name, - O_NONBLOCK | O_RDWR | O_CREAT | O_EXCL, - S_IWUSR | S_IREAD | S_IWGRP | S_IRGRP, attributes); - if (tempId != -1) { - //Successful mq_open - this->id = tempId; - return HasReturnvaluesIF::RETURN_OK; - } - } - break; - } - - default: - // Failed either the first time or the second time - sif::error << "MessageQueue::MessageQueue: Creating Queue " << std::hex - << name << std::dec << " failed with status: " - << strerror(errno) << std::endl; - - } - return HasReturnvaluesIF::RETURN_FAILED; - - - -} - -ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, - MessageQueueMessageIF* message, bool ignoreFault) { - return sendMessageFrom(sendTo, message, this->getId(), false); -} - -ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessageIF* message) { - return sendToDefaultFrom(message, this->getId()); -} - -ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) { - if (this->lastPartner != 0) { - return sendMessageFrom(this->lastPartner, message, this->getId()); - } else { - return NO_REPLY_PARTNER; - } -} - -ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message, - MessageQueueId_t* receivedFrom) { - ReturnValue_t status = this->receiveMessage(message); - *receivedFrom = this->lastPartner; - return status; -} - -ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) { - if(message == nullptr) { - sif::error << "MessageQueue::receiveMessage: Message is " - "nullptr!" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - - if(message->getMaximumMessageSize() < maxMessageSize) { - sif::error << "MessageQueue::receiveMessage: Message size " - << message->getMaximumMessageSize() - << " too small to receive data!" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - - unsigned int messagePriority = 0; - int status = mq_receive(id,reinterpret_cast(message->getBuffer()), - message->getMaximumMessageSize(),&messagePriority); - if (status > 0) { - this->lastPartner = message->getSender(); - //Check size of incoming message. - if (message->getMessageSize() < message->getMinimumMessageSize()) { - return HasReturnvaluesIF::RETURN_FAILED; - } - return HasReturnvaluesIF::RETURN_OK; - }else if(status==0){ - //Success but no message received - return MessageQueueIF::EMPTY; - } else { - //No message was received. Keep lastPartner anyway, I might send - //something later. But still, delete packet content. - memset(message->getData(), 0, message->getMaximumMessageSize()); - switch(errno){ - case EAGAIN: - //O_NONBLOCK or MQ_NONBLOCK was set and there are no messages - //currently on the specified queue. - return MessageQueueIF::EMPTY; - case EBADF: - //mqdes doesn't represent a valid queue open for reading. - sif::error << "MessageQueue::receive: configuration error " - << strerror(errno) << std::endl; - /*NO BREAK*/ - case EINVAL: - /* - * This value indicates one of the following: - * - The pointer to the buffer for storing the received message, - * msg_ptr, is NULL. - * - The number of bytes requested, msg_len is less than zero. - * - msg_len is anything other than the mq_msgsize of the specified - * queue, and the QNX extended option MQ_READBUF_DYNAMIC hasn't - * been set in the queue's mq_flags. - */ - sif::error << "MessageQueue::receive: configuration error " - << strerror(errno) << std::endl; - /*NO BREAK*/ - case EMSGSIZE: - /* - * This value indicates one of the following: - * - the QNX extended option MQ_READBUF_DYNAMIC hasn't been set, - * and the given msg_len is shorter than the mq_msgsize for - * the given queue. - * - the extended option MQ_READBUF_DYNAMIC has been set, but the - * given msg_len is too short for the message that would have - * been received. - */ - sif::error << "MessageQueue::receive: configuration error " - << strerror(errno) << std::endl; - /*NO BREAK*/ - case EINTR: - //The operation was interrupted by a signal. - default: - - return HasReturnvaluesIF::RETURN_FAILED; - } - - } -} - -MessageQueueId_t MessageQueue::getLastPartner() const { - return this->lastPartner; -} - -ReturnValue_t MessageQueue::flush(uint32_t* count) { - mq_attr attrib; - int status = mq_getattr(id,&attrib); - if(status != 0){ - switch(errno){ - case EBADF: - //mqdes doesn't represent a valid message queue. - sif::error << "MessageQueue::flush configuration error, " - "called flush with an invalid queue ID" << std::endl; - /*NO BREAK*/ - case EINVAL: - //mq_attr is NULL - default: - return HasReturnvaluesIF::RETURN_FAILED; - } - } - *count = attrib.mq_curmsgs; - attrib.mq_curmsgs = 0; - status = mq_setattr(id,&attrib,NULL); - if(status != 0){ - switch(errno){ - case EBADF: - //mqdes doesn't represent a valid message queue. - sif::error << "MessageQueue::flush configuration error, " - "called flush with an invalid queue ID" << std::endl; - /*NO BREAK*/ - case EINVAL: - /* - * This value indicates one of the following: - * - mq_attr is NULL. - * - MQ_MULT_NOTIFY had been set for this queue, and the given - * mq_flags includes a 0 in the MQ_MULT_NOTIFY bit. Once - * MQ_MULT_NOTIFY has been turned on, it may never be turned off. - */ - default: - return HasReturnvaluesIF::RETURN_FAILED; - } - } - return HasReturnvaluesIF::RETURN_OK; -} - -MessageQueueId_t MessageQueue::getId() const { - return this->id; -} - -void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) { - this->defaultDestination = defaultDestination; -} - -ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message, - MessageQueueId_t sentFrom, bool ignoreFault) { - return sendMessageFrom(defaultDestination, message, sentFrom, ignoreFault); -} - - -ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, - MessageQueueMessageIF* message, MessageQueueId_t sentFrom, - bool ignoreFault) { - return sendMessageFromMessageQueue(sendTo,message, sentFrom,ignoreFault); - -} - -MessageQueueId_t MessageQueue::getDefaultDestination() const { - return this->defaultDestination; -} - -bool MessageQueue::isDefaultDestinationSet() const { - return (defaultDestination != NO_QUEUE); -} - -uint16_t MessageQueue::queueCounter = 0; - -ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, - MessageQueueMessageIF *message, MessageQueueId_t sentFrom, - bool ignoreFault) { - if(message == nullptr) { - sif::error << "MessageQueue::sendMessageFromMessageQueue: Message is " - "nullptr!" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - - message->setSender(sentFrom); - int result = mq_send(sendTo, - reinterpret_cast(message->getBuffer()), - message->getMessageSize(),0); - - //TODO: Check if we're in ISR. - if (result != 0) { - if(!ignoreFault){ - InternalErrorReporterIF* internalErrorReporter = - objectManager->get( - objects::INTERNAL_ERROR_REPORTER); - if (internalErrorReporter != NULL) { - internalErrorReporter->queueMessageNotSent(); - } - } - switch(errno){ - case EAGAIN: - //The O_NONBLOCK flag was set when opening the queue, or the - //MQ_NONBLOCK flag was set in its attributes, and the - //specified queue is full. - return MessageQueueIF::FULL; - case EBADF: { - //mq_des doesn't represent a valid message queue descriptor, - //or mq_des wasn't opened for writing. - sif::error << "MessageQueue::sendMessage: Configuration error, MQ" - << " destination invalid." << std::endl; - sif::error << strerror(errno) << " in " - <<"mq_send to: " << sendTo << " sent from " - << sentFrom << std::endl; - return DESTINVATION_INVALID; - } - case EINTR: - //The call was interrupted by a signal. - case EINVAL: - /* - * This value indicates one of the following: - * - msg_ptr is NULL. - * - msg_len is negative. - * - msg_prio is greater than MQ_PRIO_MAX. - * - msg_prio is less than 0. - * - MQ_PRIO_RESTRICT is set in the mq_attr of mq_des, and - * msg_prio is greater than the priority of the calling process. - */ - sif::error << "MessageQueue::sendMessage: Configuration error " - << strerror(errno) << " in mq_send" << std::endl; - /*NO BREAK*/ - case EMSGSIZE: - // The msg_len is greater than the msgsize associated with - //the specified queue. - sif::error << "MessageQueue::sendMessage: Size error [" << - strerror(errno) << "] in mq_send" << std::endl; - /*NO BREAK*/ - default: - return HasReturnvaluesIF::RETURN_FAILED; - } - } - return HasReturnvaluesIF::RETURN_OK; -} +#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "../../osal/linux/MessageQueue.h" + +#include + +#include /* For O_* constants */ +#include /* For mode constants */ +#include +#include + + +MessageQueue::MessageQueue(uint32_t messageDepth, size_t maxMessageSize): + id(MessageQueueIF::NO_QUEUE),lastPartner(MessageQueueIF::NO_QUEUE), + defaultDestination(MessageQueueIF::NO_QUEUE), + maxMessageSize(maxMessageSize) { + //debug << "MessageQueue::MessageQueue: Creating a queue" << std::endl; + mq_attr attributes; + this->id = 0; + //Set attributes + attributes.mq_curmsgs = 0; + attributes.mq_maxmsg = messageDepth; + attributes.mq_msgsize = maxMessageSize; + attributes.mq_flags = 0; //Flags are ignored on Linux during mq_open + //Set the name of the queue. The slash is mandatory! + sprintf(name, "/FSFW_MQ%u\n", queueCounter++); + + // Create a nonblocking queue if the name is available (the queue is read + // and writable for the owner as well as the group) + int oflag = O_NONBLOCK | O_RDWR | O_CREAT | O_EXCL; + mode_t mode = S_IWUSR | S_IREAD | S_IWGRP | S_IRGRP | S_IROTH | S_IWOTH; + mqd_t tempId = mq_open(name, oflag, mode, &attributes); + if (tempId == -1) { + handleError(&attributes, messageDepth); + } + else { + //Successful mq_open call + this->id = tempId; + } +} + +MessageQueue::~MessageQueue() { + int status = mq_close(this->id); + if(status != 0){ + sif::error << "MessageQueue::Destructor: mq_close Failed with status: " + << strerror(errno) <> + defaultMqMaxMsg and defaultMqMaxMsg < messageDepth) { + /* + See: https://www.man7.org/linux/man-pages/man3/mq_open.3.html + This happens if the msg_max value is not large enough + It is ignored if the executable is run in privileged mode. + Run the unlockRealtime script or grant the mode manually by using: + sudo setcap 'CAP_SYS_RESOURCE=+ep' + + Persistent solution for session: + echo | sudo tee /proc/sys/fs/mqueue/msg_max + + Permanent solution: + sudo nano /etc/sysctl.conf + Append at end: fs/mqueue/msg_max = + Apply changes with: sudo sysctl -p + */ + sif::error << "MessageQueue::MessageQueue: Default MQ size " + << defaultMqMaxMsg << " is too small for requested size " + << messageDepth << std::endl; + sif::error << "This error can be fixed by setting the maximum " + "allowed message size higher!" << std::endl; + + } + break; + } + case(EEXIST): { + // An error occured during open + // We need to distinguish if it is caused by an already created queue + //There's another queue with the same name + //We unlink the other queue + int status = mq_unlink(name); + if (status != 0) { + sif::error << "mq_unlink Failed with status: " << strerror(errno) + << std::endl; + } + else { + // Successful unlinking, try to open again + mqd_t tempId = mq_open(name, + O_NONBLOCK | O_RDWR | O_CREAT | O_EXCL, + S_IWUSR | S_IREAD | S_IWGRP | S_IRGRP, attributes); + if (tempId != -1) { + //Successful mq_open + this->id = tempId; + return HasReturnvaluesIF::RETURN_OK; + } + } + break; + } + + default: + // Failed either the first time or the second time + sif::error << "MessageQueue::MessageQueue: Creating Queue " << std::hex + << name << std::dec << " failed with status: " + << strerror(errno) << std::endl; + + } + return HasReturnvaluesIF::RETURN_FAILED; + + + +} + +ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, + MessageQueueMessageIF* message, bool ignoreFault) { + return sendMessageFrom(sendTo, message, this->getId(), false); +} + +ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessageIF* message) { + return sendToDefaultFrom(message, this->getId()); +} + +ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) { + if (this->lastPartner != 0) { + return sendMessageFrom(this->lastPartner, message, this->getId()); + } else { + return NO_REPLY_PARTNER; + } +} + +ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message, + MessageQueueId_t* receivedFrom) { + ReturnValue_t status = this->receiveMessage(message); + *receivedFrom = this->lastPartner; + return status; +} + +ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) { + if(message == nullptr) { + sif::error << "MessageQueue::receiveMessage: Message is " + "nullptr!" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + + if(message->getMaximumMessageSize() < maxMessageSize) { + sif::error << "MessageQueue::receiveMessage: Message size " + << message->getMaximumMessageSize() + << " too small to receive data!" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + + unsigned int messagePriority = 0; + int status = mq_receive(id,reinterpret_cast(message->getBuffer()), + message->getMaximumMessageSize(),&messagePriority); + if (status > 0) { + this->lastPartner = message->getSender(); + //Check size of incoming message. + if (message->getMessageSize() < message->getMinimumMessageSize()) { + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; + }else if(status==0){ + //Success but no message received + return MessageQueueIF::EMPTY; + } else { + //No message was received. Keep lastPartner anyway, I might send + //something later. But still, delete packet content. + memset(message->getData(), 0, message->getMaximumMessageSize()); + switch(errno){ + case EAGAIN: + //O_NONBLOCK or MQ_NONBLOCK was set and there are no messages + //currently on the specified queue. + return MessageQueueIF::EMPTY; + case EBADF: + //mqdes doesn't represent a valid queue open for reading. + sif::error << "MessageQueue::receive: configuration error " + << strerror(errno) << std::endl; + /*NO BREAK*/ + case EINVAL: + /* + * This value indicates one of the following: + * - The pointer to the buffer for storing the received message, + * msg_ptr, is NULL. + * - The number of bytes requested, msg_len is less than zero. + * - msg_len is anything other than the mq_msgsize of the specified + * queue, and the QNX extended option MQ_READBUF_DYNAMIC hasn't + * been set in the queue's mq_flags. + */ + sif::error << "MessageQueue::receive: configuration error " + << strerror(errno) << std::endl; + /*NO BREAK*/ + case EMSGSIZE: + /* + * This value indicates one of the following: + * - the QNX extended option MQ_READBUF_DYNAMIC hasn't been set, + * and the given msg_len is shorter than the mq_msgsize for + * the given queue. + * - the extended option MQ_READBUF_DYNAMIC has been set, but the + * given msg_len is too short for the message that would have + * been received. + */ + sif::error << "MessageQueue::receive: configuration error " + << strerror(errno) << std::endl; + /*NO BREAK*/ + case EINTR: + //The operation was interrupted by a signal. + default: + + return HasReturnvaluesIF::RETURN_FAILED; + } + + } +} + +MessageQueueId_t MessageQueue::getLastPartner() const { + return this->lastPartner; +} + +ReturnValue_t MessageQueue::flush(uint32_t* count) { + mq_attr attrib; + int status = mq_getattr(id,&attrib); + if(status != 0){ + switch(errno){ + case EBADF: + //mqdes doesn't represent a valid message queue. + sif::error << "MessageQueue::flush configuration error, " + "called flush with an invalid queue ID" << std::endl; + /*NO BREAK*/ + case EINVAL: + //mq_attr is NULL + default: + return HasReturnvaluesIF::RETURN_FAILED; + } + } + *count = attrib.mq_curmsgs; + attrib.mq_curmsgs = 0; + status = mq_setattr(id,&attrib,NULL); + if(status != 0){ + switch(errno){ + case EBADF: + //mqdes doesn't represent a valid message queue. + sif::error << "MessageQueue::flush configuration error, " + "called flush with an invalid queue ID" << std::endl; + /*NO BREAK*/ + case EINVAL: + /* + * This value indicates one of the following: + * - mq_attr is NULL. + * - MQ_MULT_NOTIFY had been set for this queue, and the given + * mq_flags includes a 0 in the MQ_MULT_NOTIFY bit. Once + * MQ_MULT_NOTIFY has been turned on, it may never be turned off. + */ + default: + return HasReturnvaluesIF::RETURN_FAILED; + } + } + return HasReturnvaluesIF::RETURN_OK; +} + +MessageQueueId_t MessageQueue::getId() const { + return this->id; +} + +void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) { + this->defaultDestination = defaultDestination; +} + +ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message, + MessageQueueId_t sentFrom, bool ignoreFault) { + return sendMessageFrom(defaultDestination, message, sentFrom, ignoreFault); +} + + +ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, + MessageQueueMessageIF* message, MessageQueueId_t sentFrom, + bool ignoreFault) { + return sendMessageFromMessageQueue(sendTo,message, sentFrom,ignoreFault); + +} + +MessageQueueId_t MessageQueue::getDefaultDestination() const { + return this->defaultDestination; +} + +bool MessageQueue::isDefaultDestinationSet() const { + return (defaultDestination != NO_QUEUE); +} + +uint16_t MessageQueue::queueCounter = 0; + +ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, + MessageQueueMessageIF *message, MessageQueueId_t sentFrom, + bool ignoreFault) { + if(message == nullptr) { + sif::error << "MessageQueue::sendMessageFromMessageQueue: Message is " + "nullptr!" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + + message->setSender(sentFrom); + int result = mq_send(sendTo, + reinterpret_cast(message->getBuffer()), + message->getMessageSize(),0); + + //TODO: Check if we're in ISR. + if (result != 0) { + if(!ignoreFault){ + InternalErrorReporterIF* internalErrorReporter = + objectManager->get( + objects::INTERNAL_ERROR_REPORTER); + if (internalErrorReporter != NULL) { + internalErrorReporter->queueMessageNotSent(); + } + } + switch(errno){ + case EAGAIN: + //The O_NONBLOCK flag was set when opening the queue, or the + //MQ_NONBLOCK flag was set in its attributes, and the + //specified queue is full. + return MessageQueueIF::FULL; + case EBADF: { + //mq_des doesn't represent a valid message queue descriptor, + //or mq_des wasn't opened for writing. + sif::error << "MessageQueue::sendMessage: Configuration error, MQ" + << " destination invalid." << std::endl; + sif::error << strerror(errno) << " in " + <<"mq_send to: " << sendTo << " sent from " + << sentFrom << std::endl; + return DESTINVATION_INVALID; + } + case EINTR: + //The call was interrupted by a signal. + case EINVAL: + /* + * This value indicates one of the following: + * - msg_ptr is NULL. + * - msg_len is negative. + * - msg_prio is greater than MQ_PRIO_MAX. + * - msg_prio is less than 0. + * - MQ_PRIO_RESTRICT is set in the mq_attr of mq_des, and + * msg_prio is greater than the priority of the calling process. + */ + sif::error << "MessageQueue::sendMessage: Configuration error " + << strerror(errno) << " in mq_send" << std::endl; + /*NO BREAK*/ + case EMSGSIZE: + // The msg_len is greater than the msgsize associated with + //the specified queue. + sif::error << "MessageQueue::sendMessage: Size error [" << + strerror(errno) << "] in mq_send" << std::endl; + /*NO BREAK*/ + default: + return HasReturnvaluesIF::RETURN_FAILED; + } + } + return HasReturnvaluesIF::RETURN_OK; +} diff --git a/osal/linux/MessageQueue.h b/osal/linux/MessageQueue.h index 8e3a5191..35d16e25 100644 --- a/osal/linux/MessageQueue.h +++ b/osal/linux/MessageQueue.h @@ -1,187 +1,187 @@ -#ifndef MESSAGEQUEUE_H_ -#define MESSAGEQUEUE_H_ - -#include -#include -#include - -#include -/** - * @brief This class manages sending and receiving of message queue messages. - * - * @details - * Message queues are used to pass asynchronous messages between processes. - * They work like post boxes, where all incoming messages are stored in FIFO - * order. This class creates a new receiving queue and provides methods to fetch - * received messages. Being a child of MessageQueueSender, this class also - * provides methods to send a message to a user-defined or a default destination. - * In addition it also provides a reply method to answer to the queue it - * received its last message from. - * - * The MessageQueue should be used as "post box" for a single owning object. - * So all message queue communication is "n-to-one". - * - * The creation of message queues, as well as sending and receiving messages, - * makes use of the operating system calls provided. - * @ingroup message_queue - */ -class MessageQueue : public MessageQueueIF { - friend class MessageQueueSenderIF; -public: - /** - * @brief The constructor initializes and configures the message queue. - * @details By making use of the according operating system call, a message queue is created - * and initialized. The message depth - the maximum number of messages to be - * buffered - may be set with the help of a parameter, whereas the message size is - * automatically set to the maximum message queue message size. The operating system - * sets the message queue id, or i case of failure, it is set to zero. - * @param message_depth The number of messages to be buffered before passing an error to the - * sender. Default is three. - * @param max_message_size With this parameter, the maximum message size can be adjusted. - * This should be left default. - */ - MessageQueue(uint32_t messageDepth = 3, - size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE ); - /** - * @brief The destructor deletes the formerly created message queue. - * @details This is accomplished by using the delete call provided by the operating system. - */ - virtual ~MessageQueue(); - /** - * @brief This operation sends a message to the given destination. - * @details It directly uses the sendMessage call of the MessageQueueSender parent, but passes its - * queue id as "sentFrom" parameter. - * @param sendTo This parameter specifies the message queue id of the destination message queue. - * @param message A pointer to a previously created message, which is sent. - * @param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. - */ - virtual ReturnValue_t sendMessage(MessageQueueId_t sendTo, - MessageQueueMessageIF* message, bool ignoreFault = false ); - /** - * @brief This operation sends a message to the default destination. - * @details As in the sendMessage method, this function uses the sendToDefault call of the - * MessageQueueSender parent class and adds its queue id as "sentFrom" information. - * @param message A pointer to a previously created message, which is sent. - */ - virtual ReturnValue_t sendToDefault( MessageQueueMessageIF* message ); - /** - * @brief This operation sends a message to the last communication partner. - * @details This operation simplifies answering an incoming message by using the stored - * lastParnter information as destination. If there was no message received yet - * (i.e. lastPartner is zero), an error code is returned. - * @param message A pointer to a previously created message, which is sent. - */ - ReturnValue_t reply( MessageQueueMessageIF* message ); - - /** - * @brief This function reads available messages from the message queue and returns the sender. - * @details It works identically to the other receiveMessage call, but in addition returns the - * sender's queue id. - * @param message A pointer to a message in which the received data is stored. - * @param receivedFrom A pointer to a queue id in which the sender's id is stored. - */ - ReturnValue_t receiveMessage(MessageQueueMessageIF* message, - MessageQueueId_t *receivedFrom); - - /** - * @brief This function reads available messages from the message queue. - * @details If data is available it is stored in the passed message pointer. The message's - * original content is overwritten and the sendFrom information is stored in the - * lastPartner attribute. Else, the lastPartner information remains untouched, the - * message's content is cleared and the function returns immediately. - * @param message A pointer to a message in which the received data is stored. - */ - ReturnValue_t receiveMessage(MessageQueueMessageIF* message); - /** - * Deletes all pending messages in the queue. - * @param count The number of flushed messages. - * @return RETURN_OK on success. - */ - ReturnValue_t flush(uint32_t* count); - /** - * @brief This method returns the message queue id of the last communication partner. - */ - MessageQueueId_t getLastPartner() const; - /** - * @brief This method returns the message queue id of this class's message queue. - */ - MessageQueueId_t getId() const; - /** - * \brief With the sendMessage call, a queue message is sent to a receiving queue. - * \param sendTo This parameter specifies the message queue id to send the message to. - * \param message This is a pointer to a previously created message, which is sent. - * \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. - * This variable is set to zero by default. - * \param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. - */ - virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo, - MessageQueueMessageIF* message, MessageQueueId_t sentFrom, - bool ignoreFault = false ); - /** - * \brief The sendToDefault method sends a queue message to the default destination. - * \details In all other aspects, it works identical to the sendMessage method. - * \param message This is a pointer to a previously created message, which is sent. - * \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. - * This variable is set to zero by default. - */ - virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessageIF* message, - MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false ); - /** - * \brief This method is a simple setter for the default destination. - */ - void setDefaultDestination(MessageQueueId_t defaultDestination); - /** - * \brief This method is a simple getter for the default destination. - */ - MessageQueueId_t getDefaultDestination() const; - - bool isDefaultDestinationSet() const; -protected: - /** - * Implementation to be called from any send Call within MessageQueue and MessageQueueSenderIF - * \details This method takes the message provided, adds the sentFrom information and passes - * it on to the destination provided with an operating system call. The OS's return - * value is returned. - * \param sendTo This parameter specifies the message queue id to send the message to. - * \param message This is a pointer to a previously created message, which is sent. - * \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. - * This variable is set to zero by default. - * \param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. - */ - static ReturnValue_t sendMessageFromMessageQueue(MessageQueueId_t sendTo, - MessageQueueMessageIF* message, MessageQueueId_t sentFrom = NO_QUEUE, - bool ignoreFault=false); -private: - /** - * @brief The class stores the queue id it got assigned from the operating system in this attribute. - * If initialization fails, the queue id is set to zero. - */ - MessageQueueId_t id; - /** - * @brief In this attribute, the queue id of the last communication partner is stored - * to allow for replying. - */ - MessageQueueId_t lastPartner; - /** - * @brief The message queue's name -a user specific information for the operating system- is - * generated automatically with the help of this static counter. - */ - /** - * \brief This attribute stores a default destination to send messages to. - * \details It is stored to simplify sending to always-the-same receiver. The attribute may - * be set in the constructor or by a setter call to setDefaultDestination. - */ - MessageQueueId_t defaultDestination; - - /** - * The name of the message queue, stored for unlinking - */ - char name[16]; - - static uint16_t queueCounter; - const size_t maxMessageSize; - - ReturnValue_t handleError(mq_attr* attributes, uint32_t messageDepth); -}; - -#endif /* MESSAGEQUEUE_H_ */ +#ifndef MESSAGEQUEUE_H_ +#define MESSAGEQUEUE_H_ + +#include "../../internalError/InternalErrorReporterIF.h" +#include "../../ipc/MessageQueueIF.h" +#include "../../ipc/MessageQueueMessage.h" + +#include +/** + * @brief This class manages sending and receiving of message queue messages. + * + * @details + * Message queues are used to pass asynchronous messages between processes. + * They work like post boxes, where all incoming messages are stored in FIFO + * order. This class creates a new receiving queue and provides methods to fetch + * received messages. Being a child of MessageQueueSender, this class also + * provides methods to send a message to a user-defined or a default destination. + * In addition it also provides a reply method to answer to the queue it + * received its last message from. + * + * The MessageQueue should be used as "post box" for a single owning object. + * So all message queue communication is "n-to-one". + * + * The creation of message queues, as well as sending and receiving messages, + * makes use of the operating system calls provided. + * @ingroup message_queue + */ +class MessageQueue : public MessageQueueIF { + friend class MessageQueueSenderIF; +public: + /** + * @brief The constructor initializes and configures the message queue. + * @details By making use of the according operating system call, a message queue is created + * and initialized. The message depth - the maximum number of messages to be + * buffered - may be set with the help of a parameter, whereas the message size is + * automatically set to the maximum message queue message size. The operating system + * sets the message queue id, or i case of failure, it is set to zero. + * @param message_depth The number of messages to be buffered before passing an error to the + * sender. Default is three. + * @param max_message_size With this parameter, the maximum message size can be adjusted. + * This should be left default. + */ + MessageQueue(uint32_t messageDepth = 3, + size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE ); + /** + * @brief The destructor deletes the formerly created message queue. + * @details This is accomplished by using the delete call provided by the operating system. + */ + virtual ~MessageQueue(); + /** + * @brief This operation sends a message to the given destination. + * @details It directly uses the sendMessage call of the MessageQueueSender parent, but passes its + * queue id as "sentFrom" parameter. + * @param sendTo This parameter specifies the message queue id of the destination message queue. + * @param message A pointer to a previously created message, which is sent. + * @param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. + */ + virtual ReturnValue_t sendMessage(MessageQueueId_t sendTo, + MessageQueueMessageIF* message, bool ignoreFault = false ); + /** + * @brief This operation sends a message to the default destination. + * @details As in the sendMessage method, this function uses the sendToDefault call of the + * MessageQueueSender parent class and adds its queue id as "sentFrom" information. + * @param message A pointer to a previously created message, which is sent. + */ + virtual ReturnValue_t sendToDefault( MessageQueueMessageIF* message ); + /** + * @brief This operation sends a message to the last communication partner. + * @details This operation simplifies answering an incoming message by using the stored + * lastParnter information as destination. If there was no message received yet + * (i.e. lastPartner is zero), an error code is returned. + * @param message A pointer to a previously created message, which is sent. + */ + ReturnValue_t reply( MessageQueueMessageIF* message ); + + /** + * @brief This function reads available messages from the message queue and returns the sender. + * @details It works identically to the other receiveMessage call, but in addition returns the + * sender's queue id. + * @param message A pointer to a message in which the received data is stored. + * @param receivedFrom A pointer to a queue id in which the sender's id is stored. + */ + ReturnValue_t receiveMessage(MessageQueueMessageIF* message, + MessageQueueId_t *receivedFrom); + + /** + * @brief This function reads available messages from the message queue. + * @details If data is available it is stored in the passed message pointer. The message's + * original content is overwritten and the sendFrom information is stored in the + * lastPartner attribute. Else, the lastPartner information remains untouched, the + * message's content is cleared and the function returns immediately. + * @param message A pointer to a message in which the received data is stored. + */ + ReturnValue_t receiveMessage(MessageQueueMessageIF* message); + /** + * Deletes all pending messages in the queue. + * @param count The number of flushed messages. + * @return RETURN_OK on success. + */ + ReturnValue_t flush(uint32_t* count); + /** + * @brief This method returns the message queue id of the last communication partner. + */ + MessageQueueId_t getLastPartner() const; + /** + * @brief This method returns the message queue id of this class's message queue. + */ + MessageQueueId_t getId() const; + /** + * \brief With the sendMessage call, a queue message is sent to a receiving queue. + * \param sendTo This parameter specifies the message queue id to send the message to. + * \param message This is a pointer to a previously created message, which is sent. + * \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. + * This variable is set to zero by default. + * \param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. + */ + virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo, + MessageQueueMessageIF* message, MessageQueueId_t sentFrom, + bool ignoreFault = false ); + /** + * \brief The sendToDefault method sends a queue message to the default destination. + * \details In all other aspects, it works identical to the sendMessage method. + * \param message This is a pointer to a previously created message, which is sent. + * \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. + * This variable is set to zero by default. + */ + virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessageIF* message, + MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false ); + /** + * \brief This method is a simple setter for the default destination. + */ + void setDefaultDestination(MessageQueueId_t defaultDestination); + /** + * \brief This method is a simple getter for the default destination. + */ + MessageQueueId_t getDefaultDestination() const; + + bool isDefaultDestinationSet() const; +protected: + /** + * Implementation to be called from any send Call within MessageQueue and MessageQueueSenderIF + * \details This method takes the message provided, adds the sentFrom information and passes + * it on to the destination provided with an operating system call. The OS's return + * value is returned. + * \param sendTo This parameter specifies the message queue id to send the message to. + * \param message This is a pointer to a previously created message, which is sent. + * \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. + * This variable is set to zero by default. + * \param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. + */ + static ReturnValue_t sendMessageFromMessageQueue(MessageQueueId_t sendTo, + MessageQueueMessageIF* message, MessageQueueId_t sentFrom = NO_QUEUE, + bool ignoreFault=false); +private: + /** + * @brief The class stores the queue id it got assigned from the operating system in this attribute. + * If initialization fails, the queue id is set to zero. + */ + MessageQueueId_t id; + /** + * @brief In this attribute, the queue id of the last communication partner is stored + * to allow for replying. + */ + MessageQueueId_t lastPartner; + /** + * @brief The message queue's name -a user specific information for the operating system- is + * generated automatically with the help of this static counter. + */ + /** + * \brief This attribute stores a default destination to send messages to. + * \details It is stored to simplify sending to always-the-same receiver. The attribute may + * be set in the constructor or by a setter call to setDefaultDestination. + */ + MessageQueueId_t defaultDestination; + + /** + * The name of the message queue, stored for unlinking + */ + char name[16]; + + static uint16_t queueCounter; + const size_t maxMessageSize; + + ReturnValue_t handleError(mq_attr* attributes, uint32_t messageDepth); +}; + +#endif /* MESSAGEQUEUE_H_ */ diff --git a/osal/linux/Mutex.cpp b/osal/linux/Mutex.cpp index 03789e62..20be8aee 100644 --- a/osal/linux/Mutex.cpp +++ b/osal/linux/Mutex.cpp @@ -1,111 +1,111 @@ -#include -#include -#include - -uint8_t Mutex::count = 0; - - -#include -#include - -Mutex::Mutex() { - pthread_mutexattr_t mutexAttr; - int status = pthread_mutexattr_init(&mutexAttr); - if (status != 0) { - sif::error << "Mutex: Attribute init failed with: " << strerror(status) << std::endl; - } - status = pthread_mutexattr_setprotocol(&mutexAttr, PTHREAD_PRIO_INHERIT); - if (status != 0) { - sif::error << "Mutex: Attribute set PRIO_INHERIT failed with: " << strerror(status) - << std::endl; - } - status = pthread_mutex_init(&mutex, &mutexAttr); - if (status != 0) { - sif::error << "Mutex: creation with name, id " << mutex.__data.__count - << ", " << " failed with " << strerror(status) << std::endl; - } - // After a mutex attributes object has been used to initialize one or more - // mutexes, any function affecting the attributes object - // (including destruction) shall not affect any previously initialized mutexes. - status = pthread_mutexattr_destroy(&mutexAttr); - if (status != 0) { - sif::error << "Mutex: Attribute destroy failed with " << strerror(status) << std::endl; - } -} - -Mutex::~Mutex() { - //No Status check yet - pthread_mutex_destroy(&mutex); -} - -ReturnValue_t Mutex::lockMutex(TimeoutType timeoutType, uint32_t timeoutMs) { - int status = 0; - - if(timeoutType == TimeoutType::POLLING) { - status = pthread_mutex_trylock(&mutex); - } - else if (timeoutType == TimeoutType::WAITING) { - timespec timeOut; - clock_gettime(CLOCK_REALTIME, &timeOut); - uint64_t nseconds = timeOut.tv_sec * 1000000000 + timeOut.tv_nsec; - nseconds += timeoutMs * 1000000; - timeOut.tv_sec = nseconds / 1000000000; - timeOut.tv_nsec = nseconds - timeOut.tv_sec * 1000000000; - status = pthread_mutex_timedlock(&mutex, &timeOut); - } - else if(timeoutType == TimeoutType::BLOCKING) { - status = pthread_mutex_lock(&mutex); - } - - switch (status) { - case EINVAL: - // The mutex was created with the protocol attribute having the value - // PTHREAD_PRIO_PROTECT and the calling thread's priority is higher - // than the mutex's current priority ceiling. - return WRONG_ATTRIBUTE_SETTING; - // The process or thread would have blocked, and the abs_timeout - // parameter specified a nanoseconds field value less than zero or - // greater than or equal to 1000 million. - // The value specified by mutex does not refer to an initialized mutex object. - //return MUTEX_NOT_FOUND; - case EBUSY: - // The mutex could not be acquired because it was already locked. - return MUTEX_ALREADY_LOCKED; - case ETIMEDOUT: - // The mutex could not be locked before the specified timeout expired. - return MUTEX_TIMEOUT; - case EAGAIN: - // The mutex could not be acquired because the maximum number of - // recursive locks for mutex has been exceeded. - return MUTEX_MAX_LOCKS; - case EDEADLK: - // A deadlock condition was detected or the current thread - // already owns the mutex. - return CURR_THREAD_ALREADY_OWNS_MUTEX; - case 0: - //Success - return HasReturnvaluesIF::RETURN_OK; - default: - return HasReturnvaluesIF::RETURN_FAILED; - }; -} - -ReturnValue_t Mutex::unlockMutex() { - int status = pthread_mutex_unlock(&mutex); - switch (status) { - case EINVAL: - //The value specified by mutex does not refer to an initialized mutex object. - return MUTEX_NOT_FOUND; - case EAGAIN: - //The mutex could not be acquired because the maximum number of recursive locks for mutex has been exceeded. - return MUTEX_MAX_LOCKS; - case EPERM: - //The current thread does not own the mutex. - return CURR_THREAD_DOES_NOT_OWN_MUTEX; - case 0: - //Success - return HasReturnvaluesIF::RETURN_OK; - default: - return HasReturnvaluesIF::RETURN_FAILED; - }; -} +#include "../../osal/linux/Mutex.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "../../timemanager/Clock.h" + +uint8_t Mutex::count = 0; + + +#include +#include + +Mutex::Mutex() { + pthread_mutexattr_t mutexAttr; + int status = pthread_mutexattr_init(&mutexAttr); + if (status != 0) { + sif::error << "Mutex: Attribute init failed with: " << strerror(status) << std::endl; + } + status = pthread_mutexattr_setprotocol(&mutexAttr, PTHREAD_PRIO_INHERIT); + if (status != 0) { + sif::error << "Mutex: Attribute set PRIO_INHERIT failed with: " << strerror(status) + << std::endl; + } + status = pthread_mutex_init(&mutex, &mutexAttr); + if (status != 0) { + sif::error << "Mutex: creation with name, id " << mutex.__data.__count + << ", " << " failed with " << strerror(status) << std::endl; + } + // After a mutex attributes object has been used to initialize one or more + // mutexes, any function affecting the attributes object + // (including destruction) shall not affect any previously initialized mutexes. + status = pthread_mutexattr_destroy(&mutexAttr); + if (status != 0) { + sif::error << "Mutex: Attribute destroy failed with " << strerror(status) << std::endl; + } +} + +Mutex::~Mutex() { + //No Status check yet + pthread_mutex_destroy(&mutex); +} + +ReturnValue_t Mutex::lockMutex(TimeoutType timeoutType, uint32_t timeoutMs) { + int status = 0; + + if(timeoutType == TimeoutType::POLLING) { + status = pthread_mutex_trylock(&mutex); + } + else if (timeoutType == TimeoutType::WAITING) { + timespec timeOut; + clock_gettime(CLOCK_REALTIME, &timeOut); + uint64_t nseconds = timeOut.tv_sec * 1000000000 + timeOut.tv_nsec; + nseconds += timeoutMs * 1000000; + timeOut.tv_sec = nseconds / 1000000000; + timeOut.tv_nsec = nseconds - timeOut.tv_sec * 1000000000; + status = pthread_mutex_timedlock(&mutex, &timeOut); + } + else if(timeoutType == TimeoutType::BLOCKING) { + status = pthread_mutex_lock(&mutex); + } + + switch (status) { + case EINVAL: + // The mutex was created with the protocol attribute having the value + // PTHREAD_PRIO_PROTECT and the calling thread's priority is higher + // than the mutex's current priority ceiling. + return WRONG_ATTRIBUTE_SETTING; + // The process or thread would have blocked, and the abs_timeout + // parameter specified a nanoseconds field value less than zero or + // greater than or equal to 1000 million. + // The value specified by mutex does not refer to an initialized mutex object. + //return MUTEX_NOT_FOUND; + case EBUSY: + // The mutex could not be acquired because it was already locked. + return MUTEX_ALREADY_LOCKED; + case ETIMEDOUT: + // The mutex could not be locked before the specified timeout expired. + return MUTEX_TIMEOUT; + case EAGAIN: + // The mutex could not be acquired because the maximum number of + // recursive locks for mutex has been exceeded. + return MUTEX_MAX_LOCKS; + case EDEADLK: + // A deadlock condition was detected or the current thread + // already owns the mutex. + return CURR_THREAD_ALREADY_OWNS_MUTEX; + case 0: + //Success + return HasReturnvaluesIF::RETURN_OK; + default: + return HasReturnvaluesIF::RETURN_FAILED; + }; +} + +ReturnValue_t Mutex::unlockMutex() { + int status = pthread_mutex_unlock(&mutex); + switch (status) { + case EINVAL: + //The value specified by mutex does not refer to an initialized mutex object. + return MUTEX_NOT_FOUND; + case EAGAIN: + //The mutex could not be acquired because the maximum number of recursive locks for mutex has been exceeded. + return MUTEX_MAX_LOCKS; + case EPERM: + //The current thread does not own the mutex. + return CURR_THREAD_DOES_NOT_OWN_MUTEX; + case 0: + //Success + return HasReturnvaluesIF::RETURN_OK; + default: + return HasReturnvaluesIF::RETURN_FAILED; + }; +} diff --git a/osal/linux/Mutex.h b/osal/linux/Mutex.h index 26420c2e..77a11fe4 100644 --- a/osal/linux/Mutex.h +++ b/osal/linux/Mutex.h @@ -1,22 +1,22 @@ -#ifndef OS_LINUX_MUTEX_H_ -#define OS_LINUX_MUTEX_H_ - -#include - -extern "C" { -#include -} - - -class Mutex : public MutexIF { -public: - Mutex(); - virtual ~Mutex(); - virtual ReturnValue_t lockMutex(TimeoutType timeoutType, uint32_t timeoutMs); - virtual ReturnValue_t unlockMutex(); -private: - pthread_mutex_t mutex; - static uint8_t count; -}; - -#endif /* OS_RTEMS_MUTEX_H_ */ +#ifndef OS_LINUX_MUTEX_H_ +#define OS_LINUX_MUTEX_H_ + +#include "../../ipc/MutexIF.h" + +extern "C" { +#include +} + + +class Mutex : public MutexIF { +public: + Mutex(); + virtual ~Mutex(); + virtual ReturnValue_t lockMutex(TimeoutType timeoutType, uint32_t timeoutMs); + virtual ReturnValue_t unlockMutex(); +private: + pthread_mutex_t mutex; + static uint8_t count; +}; + +#endif /* OS_RTEMS_MUTEX_H_ */ diff --git a/osal/linux/MutexFactory.cpp b/osal/linux/MutexFactory.cpp index d769cc33..70dc3c71 100644 --- a/osal/linux/MutexFactory.cpp +++ b/osal/linux/MutexFactory.cpp @@ -1,23 +1,23 @@ -#include -#include - -//TODO: Different variant than the lazy loading in QueueFactory. What's better and why? -MutexFactory* MutexFactory::factoryInstance = new MutexFactory(); - -MutexFactory::MutexFactory() { -} - -MutexFactory::~MutexFactory() { -} - -MutexFactory* MutexFactory::instance() { - return MutexFactory::factoryInstance; -} - -MutexIF* MutexFactory::createMutex() { - return new Mutex(); -} - -void MutexFactory::deleteMutex(MutexIF* mutex) { - delete mutex; -} +#include "../../ipc/MutexFactory.h" +#include "../../osal/linux/Mutex.h" + +//TODO: Different variant than the lazy loading in QueueFactory. What's better and why? +MutexFactory* MutexFactory::factoryInstance = new MutexFactory(); + +MutexFactory::MutexFactory() { +} + +MutexFactory::~MutexFactory() { +} + +MutexFactory* MutexFactory::instance() { + return MutexFactory::factoryInstance; +} + +MutexIF* MutexFactory::createMutex() { + return new Mutex(); +} + +void MutexFactory::deleteMutex(MutexIF* mutex) { + delete mutex; +} diff --git a/osal/linux/PeriodicPosixTask.cpp b/osal/linux/PeriodicPosixTask.cpp index cd487531..9b6148c5 100644 --- a/osal/linux/PeriodicPosixTask.cpp +++ b/osal/linux/PeriodicPosixTask.cpp @@ -1,82 +1,82 @@ -#include -#include -#include - -#include - -PeriodicPosixTask::PeriodicPosixTask(const char* name_, int priority_, - size_t stackSize_, uint32_t period_, void(deadlineMissedFunc_)()): - PosixThread(name_, priority_, stackSize_), objectList(), started(false), - periodMs(period_), deadlineMissedFunc(deadlineMissedFunc_) { -} - -PeriodicPosixTask::~PeriodicPosixTask() { - //Not Implemented -} - -void* PeriodicPosixTask::taskEntryPoint(void* arg) { - //The argument is re-interpreted as PollingTask. - PeriodicPosixTask *originalTask(reinterpret_cast(arg)); - //The task's functionality is called. - originalTask->taskFunctionality(); - return NULL; -} - -ReturnValue_t PeriodicPosixTask::addComponent(object_id_t object) { - ExecutableObjectIF* newObject = objectManager->get( - object); - if (newObject == nullptr) { - sif::error << "PeriodicTask::addComponent: Invalid object. Make sure" - "it implements ExecutableObjectIF" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - objectList.push_back(newObject); - newObject->setTaskIF(this); - - return newObject->initializeAfterTaskCreation(); -} - -ReturnValue_t PeriodicPosixTask::sleepFor(uint32_t ms) { - return PosixThread::sleep((uint64_t)ms*1000000); -} - - -ReturnValue_t PeriodicPosixTask::startTask(void) { - started = true; - //sif::info << stackSize << std::endl; - PosixThread::createTask(&taskEntryPoint,this); - return HasReturnvaluesIF::RETURN_OK; -} - -void PeriodicPosixTask::taskFunctionality(void) { - if(!started){ - suspend(); - } - uint64_t lastWakeTime = getCurrentMonotonicTimeMs(); - //The task's "infinite" inner loop is entered. - while (1) { - for (ObjectList::iterator it = objectList.begin(); - it != objectList.end(); ++it) { - (*it)->performOperation(); - } - if(!PosixThread::delayUntil(&lastWakeTime,periodMs)){ - char name[20] = {0}; - int status = pthread_getname_np(pthread_self(),name,sizeof(name)); - if(status == 0){ - //sif::error << "PeriodicPosixTask " << name << ": Deadline " - // "missed." << std::endl; - } - else { - //sif::error << "PeriodicPosixTask X: Deadline missed. " << - // status << std::endl; - } - if (this->deadlineMissedFunc != nullptr) { - this->deadlineMissedFunc(); - } - } - } -} - -uint32_t PeriodicPosixTask::getPeriodMs() const { - return periodMs; -} +#include "../../tasks/ExecutableObjectIF.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "../../osal/linux/PeriodicPosixTask.h" + +#include + +PeriodicPosixTask::PeriodicPosixTask(const char* name_, int priority_, + size_t stackSize_, uint32_t period_, void(deadlineMissedFunc_)()): + PosixThread(name_, priority_, stackSize_), objectList(), started(false), + periodMs(period_), deadlineMissedFunc(deadlineMissedFunc_) { +} + +PeriodicPosixTask::~PeriodicPosixTask() { + //Not Implemented +} + +void* PeriodicPosixTask::taskEntryPoint(void* arg) { + //The argument is re-interpreted as PollingTask. + PeriodicPosixTask *originalTask(reinterpret_cast(arg)); + //The task's functionality is called. + originalTask->taskFunctionality(); + return NULL; +} + +ReturnValue_t PeriodicPosixTask::addComponent(object_id_t object) { + ExecutableObjectIF* newObject = objectManager->get( + object); + if (newObject == nullptr) { + sif::error << "PeriodicTask::addComponent: Invalid object. Make sure" + "it implements ExecutableObjectIF" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + objectList.push_back(newObject); + newObject->setTaskIF(this); + + return newObject->initializeAfterTaskCreation(); +} + +ReturnValue_t PeriodicPosixTask::sleepFor(uint32_t ms) { + return PosixThread::sleep((uint64_t)ms*1000000); +} + + +ReturnValue_t PeriodicPosixTask::startTask(void) { + started = true; + //sif::info << stackSize << std::endl; + PosixThread::createTask(&taskEntryPoint,this); + return HasReturnvaluesIF::RETURN_OK; +} + +void PeriodicPosixTask::taskFunctionality(void) { + if(!started){ + suspend(); + } + uint64_t lastWakeTime = getCurrentMonotonicTimeMs(); + //The task's "infinite" inner loop is entered. + while (1) { + for (ObjectList::iterator it = objectList.begin(); + it != objectList.end(); ++it) { + (*it)->performOperation(); + } + if(!PosixThread::delayUntil(&lastWakeTime,periodMs)){ + char name[20] = {0}; + int status = pthread_getname_np(pthread_self(),name,sizeof(name)); + if(status == 0){ + //sif::error << "PeriodicPosixTask " << name << ": Deadline " + // "missed." << std::endl; + } + else { + //sif::error << "PeriodicPosixTask X: Deadline missed. " << + // status << std::endl; + } + if (this->deadlineMissedFunc != nullptr) { + this->deadlineMissedFunc(); + } + } + } +} + +uint32_t PeriodicPosixTask::getPeriodMs() const { + return periodMs; +} diff --git a/osal/linux/PeriodicPosixTask.h b/osal/linux/PeriodicPosixTask.h index 0b2d51cd..59302e43 100644 --- a/osal/linux/PeriodicPosixTask.h +++ b/osal/linux/PeriodicPosixTask.h @@ -1,90 +1,90 @@ -#ifndef FRAMEWORK_OSAL_LINUX_PERIODICPOSIXTASK_H_ -#define FRAMEWORK_OSAL_LINUX_PERIODICPOSIXTASK_H_ - -#include -#include -#include -#include -#include - -class PeriodicPosixTask: public PosixThread, public PeriodicTaskIF { -public: - /** - * Create a generic periodic task. - * @param name_ - * Name, maximum allowed size of linux is 16 chars, everything else will - * be truncated. - * @param priority_ - * Real-time priority, ranges from 1 to 99 for Linux. - * See: https://man7.org/linux/man-pages/man7/sched.7.html - * @param stackSize_ - * @param period_ - * @param deadlineMissedFunc_ - */ - PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_, - uint32_t period_, void(*deadlineMissedFunc_)()); - virtual ~PeriodicPosixTask(); - - /** - * @brief The method to start the task. - * @details The method starts the task with the respective system call. - * Entry point is the taskEntryPoint method described below. - * The address of the task object is passed as an argument - * to the system call. - */ - ReturnValue_t startTask(void) override; - /** - * Adds an object to the list of objects to be executed. - * The objects are executed in the order added. - * @param object Id of the object to add. - * @return RETURN_OK on success, RETURN_FAILED if the object could not be added. - */ - ReturnValue_t addComponent(object_id_t object) override; - - uint32_t getPeriodMs() const override; - - ReturnValue_t sleepFor(uint32_t ms) override; - -private: - typedef std::vector ObjectList; //!< Typedef for the List of objects. - /** - * @brief This attribute holds a list of objects to be executed. - */ - ObjectList objectList; - - /** - * @brief Flag to indicate that the task was started and is allowed to run - */ - bool started; - - - /** - * @brief Period of the task in milliseconds - */ - uint32_t periodMs; - /** - * @brief The function containing the actual functionality of the task. - * @details The method sets and starts - * the task's period, then enters a loop that is repeated indefinitely. Within the loop, all performOperation methods of the added - * objects are called. Afterwards the task will be blocked until the next period. - * On missing the deadline, the deadlineMissedFunction is executed. - */ - virtual void taskFunctionality(void); - /** - * @brief This is the entry point in a new thread. - * - * @details This method, that is the entry point in the new thread and calls taskFunctionality of the child class. - * Needs a valid pointer to the derived class. - */ - static void* taskEntryPoint(void* arg); - /** - * @brief The pointer to the deadline-missed function. - * @details This pointer stores the function that is executed if the task's deadline is missed. - * So, each may react individually on a timing failure. The pointer may be NULL, - * then nothing happens on missing the deadline. The deadline is equal to the next execution - * of the periodic task. - */ - void (*deadlineMissedFunc)(); -}; - -#endif /* FRAMEWORK_OSAL_LINUX_PERIODICPOSIXTASK_H_ */ +#ifndef FRAMEWORK_OSAL_LINUX_PERIODICPOSIXTASK_H_ +#define FRAMEWORK_OSAL_LINUX_PERIODICPOSIXTASK_H_ + +#include "../../tasks/PeriodicTaskIF.h" +#include "../../objectmanager/ObjectManagerIF.h" +#include "../../osal/linux/PosixThread.h" +#include "../../tasks/ExecutableObjectIF.h" +#include + +class PeriodicPosixTask: public PosixThread, public PeriodicTaskIF { +public: + /** + * Create a generic periodic task. + * @param name_ + * Name, maximum allowed size of linux is 16 chars, everything else will + * be truncated. + * @param priority_ + * Real-time priority, ranges from 1 to 99 for Linux. + * See: https://man7.org/linux/man-pages/man7/sched.7.html + * @param stackSize_ + * @param period_ + * @param deadlineMissedFunc_ + */ + PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_, + uint32_t period_, void(*deadlineMissedFunc_)()); + virtual ~PeriodicPosixTask(); + + /** + * @brief The method to start the task. + * @details The method starts the task with the respective system call. + * Entry point is the taskEntryPoint method described below. + * The address of the task object is passed as an argument + * to the system call. + */ + ReturnValue_t startTask(void) override; + /** + * Adds an object to the list of objects to be executed. + * The objects are executed in the order added. + * @param object Id of the object to add. + * @return RETURN_OK on success, RETURN_FAILED if the object could not be added. + */ + ReturnValue_t addComponent(object_id_t object) override; + + uint32_t getPeriodMs() const override; + + ReturnValue_t sleepFor(uint32_t ms) override; + +private: + typedef std::vector ObjectList; //!< Typedef for the List of objects. + /** + * @brief This attribute holds a list of objects to be executed. + */ + ObjectList objectList; + + /** + * @brief Flag to indicate that the task was started and is allowed to run + */ + bool started; + + + /** + * @brief Period of the task in milliseconds + */ + uint32_t periodMs; + /** + * @brief The function containing the actual functionality of the task. + * @details The method sets and starts + * the task's period, then enters a loop that is repeated indefinitely. Within the loop, all performOperation methods of the added + * objects are called. Afterwards the task will be blocked until the next period. + * On missing the deadline, the deadlineMissedFunction is executed. + */ + virtual void taskFunctionality(void); + /** + * @brief This is the entry point in a new thread. + * + * @details This method, that is the entry point in the new thread and calls taskFunctionality of the child class. + * Needs a valid pointer to the derived class. + */ + static void* taskEntryPoint(void* arg); + /** + * @brief The pointer to the deadline-missed function. + * @details This pointer stores the function that is executed if the task's deadline is missed. + * So, each may react individually on a timing failure. The pointer may be NULL, + * then nothing happens on missing the deadline. The deadline is equal to the next execution + * of the periodic task. + */ + void (*deadlineMissedFunc)(); +}; + +#endif /* FRAMEWORK_OSAL_LINUX_PERIODICPOSIXTASK_H_ */ diff --git a/osal/linux/PosixThread.cpp b/osal/linux/PosixThread.cpp index d84c8d9d..70c63c4a 100644 --- a/osal/linux/PosixThread.cpp +++ b/osal/linux/PosixThread.cpp @@ -1,217 +1,217 @@ -#include -#include -#include -#include - -PosixThread::PosixThread(const char* name_, int priority_, size_t stackSize_): - thread(0),priority(priority_),stackSize(stackSize_) { - name[0] = '\0'; - std::strncat(name, name_, PTHREAD_MAX_NAMELEN - 1); -} - -PosixThread::~PosixThread() { - //No deletion and no free of Stack Pointer -} - -ReturnValue_t PosixThread::sleep(uint64_t ns) { - //TODO sleep might be better with timer instead of sleep() - timespec time; - time.tv_sec = ns/1000000000; - time.tv_nsec = ns - time.tv_sec*1e9; - - //Remaining Time is not set here - int status = nanosleep(&time,NULL); - if(status != 0){ - switch(errno){ - case EINTR: - //The nanosleep() function was interrupted by a signal. - return HasReturnvaluesIF::RETURN_FAILED; - case EINVAL: - //The rqtp argument specified a nanosecond value less than zero or - // greater than or equal to 1000 million. - return HasReturnvaluesIF::RETURN_FAILED; - default: - return HasReturnvaluesIF::RETURN_FAILED; - } - - } - return HasReturnvaluesIF::RETURN_OK; -} - -void PosixThread::suspend() { - //Wait for SIGUSR1 - int caughtSig = 0; - sigset_t waitSignal; - sigemptyset(&waitSignal); - sigaddset(&waitSignal, SIGUSR1); - sigwait(&waitSignal, &caughtSig); - if (caughtSig != SIGUSR1) { - sif::error << "FixedTimeslotTask: Unknown Signal received: " << - caughtSig << std::endl; - } -} - -void PosixThread::resume(){ - /* Signal the thread to start. Makes sense to call kill to start or? ;) - * - * According to Posix raise(signal) will call pthread_kill(pthread_self(), sig), - * but as the call must be done from the thread itsself this is not possible here - */ - pthread_kill(thread,SIGUSR1); -} - -bool PosixThread::delayUntil(uint64_t* const prevoiusWakeTime_ms, - const uint64_t delayTime_ms) { - uint64_t nextTimeToWake_ms; - bool shouldDelay = false; - //Get current Time - const uint64_t currentTime_ms = getCurrentMonotonicTimeMs(); - /* Generate the tick time at which the task wants to wake. */ - nextTimeToWake_ms = (*prevoiusWakeTime_ms) + delayTime_ms; - - if (currentTime_ms < *prevoiusWakeTime_ms) { - /* The tick count has overflowed since this function was - lasted called. In this case the only time we should ever - actually delay is if the wake time has also overflowed, - and the wake time is greater than the tick time. When this - is the case it is as if neither time had overflowed. */ - if ((nextTimeToWake_ms < *prevoiusWakeTime_ms) - && (nextTimeToWake_ms > currentTime_ms)) { - shouldDelay = true; - } - } else { - /* The tick time has not overflowed. In this case we will - delay if either the wake time has overflowed, and/or the - tick time is less than the wake time. */ - if ((nextTimeToWake_ms < *prevoiusWakeTime_ms) - || (nextTimeToWake_ms > currentTime_ms)) { - shouldDelay = true; - } - } - - /* Update the wake time ready for the next call. */ - - (*prevoiusWakeTime_ms) = nextTimeToWake_ms; - - if (shouldDelay) { - uint64_t sleepTime = nextTimeToWake_ms - currentTime_ms; - PosixThread::sleep(sleepTime * 1000000ull); - return true; - } - //We are shifting the time in case the deadline was missed like rtems - (*prevoiusWakeTime_ms) = currentTime_ms; - return false; - -} - - -uint64_t PosixThread::getCurrentMonotonicTimeMs(){ - timespec timeNow; - clock_gettime(CLOCK_MONOTONIC_RAW, &timeNow); - uint64_t currentTime_ms = (uint64_t) timeNow.tv_sec * 1000 - + timeNow.tv_nsec / 1000000; - - return currentTime_ms; -} - - -void PosixThread::createTask(void* (*fnc_)(void*), void* arg_) { - //sif::debug << "PosixThread::createTask" << std::endl; - /* - * The attr argument points to a pthread_attr_t structure whose contents - are used at thread creation time to determine attributes for the new - thread; this structure is initialized using pthread_attr_init(3) and - related functions. If attr is NULL, then the thread is created with - default attributes. - */ - pthread_attr_t attributes; - int status = pthread_attr_init(&attributes); - if(status != 0){ - sif::error << "Posix Thread attribute init failed with: " << - strerror(status) << std::endl; - } - void* stackPointer; - status = posix_memalign(&stackPointer, sysconf(_SC_PAGESIZE), stackSize); - if(status != 0){ - sif::error << "PosixThread::createTask: Stack init failed with: " << - strerror(status) << std::endl; - if(errno == ENOMEM) { - uint64_t stackMb = stackSize/10e6; - sif::error << "PosixThread::createTask: Insufficient memory for" - " the requested " << stackMb << " MB" << std::endl; - } - else if(errno == EINVAL) { - sif::error << "PosixThread::createTask: Wrong alignment argument!" - << std::endl; - } - return; - } - - status = pthread_attr_setstack(&attributes, stackPointer, stackSize); - if(status != 0){ - sif::error << "PosixThread::createTask: pthread_attr_setstack " - " failed with: " << strerror(status) << std::endl; - sif::error << "Make sure the specified stack size is valid and is " - "larger than the minimum allowed stack size." << std::endl; - } - - status = pthread_attr_setinheritsched(&attributes, PTHREAD_EXPLICIT_SCHED); - if(status != 0){ - sif::error << "Posix Thread attribute setinheritsched failed with: " << - strerror(status) << std::endl; - } - - // TODO FIFO -> This needs root privileges for the process - status = pthread_attr_setschedpolicy(&attributes,SCHED_FIFO); - if(status != 0){ - sif::error << "Posix Thread attribute schedule policy failed with: " << - strerror(status) << std::endl; - } - - sched_param scheduleParams; - scheduleParams.__sched_priority = priority; - status = pthread_attr_setschedparam(&attributes, &scheduleParams); - if(status != 0){ - sif::error << "Posix Thread attribute schedule params failed with: " << - strerror(status) << std::endl; - } - - //Set Signal Mask for suspend until startTask is called - sigset_t waitSignal; - sigemptyset(&waitSignal); - sigaddset(&waitSignal, SIGUSR1); - status = pthread_sigmask(SIG_BLOCK, &waitSignal, NULL); - if(status != 0){ - sif::error << "Posix Thread sigmask failed failed with: " << - strerror(status) << " errno: " << strerror(errno) << std::endl; - } - - - status = pthread_create(&thread,&attributes,fnc_,arg_); - if(status != 0){ - sif::error << "Posix Thread create failed with: " << - strerror(status) << std::endl; - } - - status = pthread_setname_np(thread,name); - if(status != 0){ - sif::error << "PosixThread::createTask: setname failed with: " << - strerror(status) << std::endl; - if(status == ERANGE) { - sif::error << "PosixThread::createTask: Task name length longer" - " than 16 chars. Truncating.." << std::endl; - name[15] = '\0'; - status = pthread_setname_np(thread,name); - if(status != 0){ - sif::error << "PosixThread::createTask: Setting name" - " did not work.." << std::endl; - } - } - } - - status = pthread_attr_destroy(&attributes); - if(status!=0){ - sif::error << "Posix Thread attribute destroy failed with: " << - strerror(status) << std::endl; - } -} +#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "../../osal/linux/PosixThread.h" +#include +#include + +PosixThread::PosixThread(const char* name_, int priority_, size_t stackSize_): + thread(0),priority(priority_),stackSize(stackSize_) { + name[0] = '\0'; + std::strncat(name, name_, PTHREAD_MAX_NAMELEN - 1); +} + +PosixThread::~PosixThread() { + //No deletion and no free of Stack Pointer +} + +ReturnValue_t PosixThread::sleep(uint64_t ns) { + //TODO sleep might be better with timer instead of sleep() + timespec time; + time.tv_sec = ns/1000000000; + time.tv_nsec = ns - time.tv_sec*1e9; + + //Remaining Time is not set here + int status = nanosleep(&time,NULL); + if(status != 0){ + switch(errno){ + case EINTR: + //The nanosleep() function was interrupted by a signal. + return HasReturnvaluesIF::RETURN_FAILED; + case EINVAL: + //The rqtp argument specified a nanosecond value less than zero or + // greater than or equal to 1000 million. + return HasReturnvaluesIF::RETURN_FAILED; + default: + return HasReturnvaluesIF::RETURN_FAILED; + } + + } + return HasReturnvaluesIF::RETURN_OK; +} + +void PosixThread::suspend() { + //Wait for SIGUSR1 + int caughtSig = 0; + sigset_t waitSignal; + sigemptyset(&waitSignal); + sigaddset(&waitSignal, SIGUSR1); + sigwait(&waitSignal, &caughtSig); + if (caughtSig != SIGUSR1) { + sif::error << "FixedTimeslotTask: Unknown Signal received: " << + caughtSig << std::endl; + } +} + +void PosixThread::resume(){ + /* Signal the thread to start. Makes sense to call kill to start or? ;) + * + * According to Posix raise(signal) will call pthread_kill(pthread_self(), sig), + * but as the call must be done from the thread itsself this is not possible here + */ + pthread_kill(thread,SIGUSR1); +} + +bool PosixThread::delayUntil(uint64_t* const prevoiusWakeTime_ms, + const uint64_t delayTime_ms) { + uint64_t nextTimeToWake_ms; + bool shouldDelay = false; + //Get current Time + const uint64_t currentTime_ms = getCurrentMonotonicTimeMs(); + /* Generate the tick time at which the task wants to wake. */ + nextTimeToWake_ms = (*prevoiusWakeTime_ms) + delayTime_ms; + + if (currentTime_ms < *prevoiusWakeTime_ms) { + /* The tick count has overflowed since this function was + lasted called. In this case the only time we should ever + actually delay is if the wake time has also overflowed, + and the wake time is greater than the tick time. When this + is the case it is as if neither time had overflowed. */ + if ((nextTimeToWake_ms < *prevoiusWakeTime_ms) + && (nextTimeToWake_ms > currentTime_ms)) { + shouldDelay = true; + } + } else { + /* The tick time has not overflowed. In this case we will + delay if either the wake time has overflowed, and/or the + tick time is less than the wake time. */ + if ((nextTimeToWake_ms < *prevoiusWakeTime_ms) + || (nextTimeToWake_ms > currentTime_ms)) { + shouldDelay = true; + } + } + + /* Update the wake time ready for the next call. */ + + (*prevoiusWakeTime_ms) = nextTimeToWake_ms; + + if (shouldDelay) { + uint64_t sleepTime = nextTimeToWake_ms - currentTime_ms; + PosixThread::sleep(sleepTime * 1000000ull); + return true; + } + //We are shifting the time in case the deadline was missed like rtems + (*prevoiusWakeTime_ms) = currentTime_ms; + return false; + +} + + +uint64_t PosixThread::getCurrentMonotonicTimeMs(){ + timespec timeNow; + clock_gettime(CLOCK_MONOTONIC_RAW, &timeNow); + uint64_t currentTime_ms = (uint64_t) timeNow.tv_sec * 1000 + + timeNow.tv_nsec / 1000000; + + return currentTime_ms; +} + + +void PosixThread::createTask(void* (*fnc_)(void*), void* arg_) { + //sif::debug << "PosixThread::createTask" << std::endl; + /* + * The attr argument points to a pthread_attr_t structure whose contents + are used at thread creation time to determine attributes for the new + thread; this structure is initialized using pthread_attr_init(3) and + related functions. If attr is NULL, then the thread is created with + default attributes. + */ + pthread_attr_t attributes; + int status = pthread_attr_init(&attributes); + if(status != 0){ + sif::error << "Posix Thread attribute init failed with: " << + strerror(status) << std::endl; + } + void* stackPointer; + status = posix_memalign(&stackPointer, sysconf(_SC_PAGESIZE), stackSize); + if(status != 0){ + sif::error << "PosixThread::createTask: Stack init failed with: " << + strerror(status) << std::endl; + if(errno == ENOMEM) { + uint64_t stackMb = stackSize/10e6; + sif::error << "PosixThread::createTask: Insufficient memory for" + " the requested " << stackMb << " MB" << std::endl; + } + else if(errno == EINVAL) { + sif::error << "PosixThread::createTask: Wrong alignment argument!" + << std::endl; + } + return; + } + + status = pthread_attr_setstack(&attributes, stackPointer, stackSize); + if(status != 0){ + sif::error << "PosixThread::createTask: pthread_attr_setstack " + " failed with: " << strerror(status) << std::endl; + sif::error << "Make sure the specified stack size is valid and is " + "larger than the minimum allowed stack size." << std::endl; + } + + status = pthread_attr_setinheritsched(&attributes, PTHREAD_EXPLICIT_SCHED); + if(status != 0){ + sif::error << "Posix Thread attribute setinheritsched failed with: " << + strerror(status) << std::endl; + } + + // TODO FIFO -> This needs root privileges for the process + status = pthread_attr_setschedpolicy(&attributes,SCHED_FIFO); + if(status != 0){ + sif::error << "Posix Thread attribute schedule policy failed with: " << + strerror(status) << std::endl; + } + + sched_param scheduleParams; + scheduleParams.__sched_priority = priority; + status = pthread_attr_setschedparam(&attributes, &scheduleParams); + if(status != 0){ + sif::error << "Posix Thread attribute schedule params failed with: " << + strerror(status) << std::endl; + } + + //Set Signal Mask for suspend until startTask is called + sigset_t waitSignal; + sigemptyset(&waitSignal); + sigaddset(&waitSignal, SIGUSR1); + status = pthread_sigmask(SIG_BLOCK, &waitSignal, NULL); + if(status != 0){ + sif::error << "Posix Thread sigmask failed failed with: " << + strerror(status) << " errno: " << strerror(errno) << std::endl; + } + + + status = pthread_create(&thread,&attributes,fnc_,arg_); + if(status != 0){ + sif::error << "Posix Thread create failed with: " << + strerror(status) << std::endl; + } + + status = pthread_setname_np(thread,name); + if(status != 0){ + sif::error << "PosixThread::createTask: setname failed with: " << + strerror(status) << std::endl; + if(status == ERANGE) { + sif::error << "PosixThread::createTask: Task name length longer" + " than 16 chars. Truncating.." << std::endl; + name[15] = '\0'; + status = pthread_setname_np(thread,name); + if(status != 0){ + sif::error << "PosixThread::createTask: Setting name" + " did not work.." << std::endl; + } + } + } + + status = pthread_attr_destroy(&attributes); + if(status!=0){ + sif::error << "Posix Thread attribute destroy failed with: " << + strerror(status) << std::endl; + } +} diff --git a/osal/linux/PosixThread.h b/osal/linux/PosixThread.h index e9d31728..9d6097f7 100644 --- a/osal/linux/PosixThread.h +++ b/osal/linux/PosixThread.h @@ -1,77 +1,77 @@ -#ifndef FRAMEWORK_OSAL_LINUX_POSIXTHREAD_H_ -#define FRAMEWORK_OSAL_LINUX_POSIXTHREAD_H_ - -#include -#include -#include -#include -#include - -class PosixThread { -public: - static constexpr uint8_t PTHREAD_MAX_NAMELEN = 16; - PosixThread(const char* name_, int priority_, size_t stackSize_); - virtual ~PosixThread(); - /** - * Set the Thread to sleep state - * @param ns Nanosecond sleep time - * @return Returns Failed if sleep fails - */ - static ReturnValue_t sleep(uint64_t ns); - /** - * @brief Function to suspend the task until SIGUSR1 was received - * - * @details Will be called in the beginning to suspend execution until startTask() is called explicitly. - */ - void suspend(); - - /** - * @brief Function to allow a other thread to start the thread again from suspend state - * - * @details Restarts the Thread after suspend call - */ - void resume(); - - - /** - * Delay function similar to FreeRtos delayUntil function - * - * @param prevoiusWakeTime_ms Needs the previous wake time and returns the next wakeup time - * @param delayTime_ms Time period to delay - * - * @return False If deadline was missed; True if task was delayed - */ - static bool delayUntil(uint64_t* const prevoiusWakeTime_ms, const uint64_t delayTime_ms); - - /** - * Returns the current time in milliseconds from CLOCK_MONOTONIC - * - * @return current time in milliseconds from CLOCK_MONOTONIC - */ - static uint64_t getCurrentMonotonicTimeMs(); - -protected: - pthread_t thread; - - /** - * @brief Function that has to be called by derived class because the - * derived class pointer has to be valid as argument. - * @details - * This function creates a pthread with the given parameters. As the - * function requires a pointer to the derived object it has to be called - * after the this pointer of the derived object is valid. - * Sets the taskEntryPoint as function to be called by new a thread. - * @param fnc_ Function which will be executed by the thread. - * @param arg_ - * argument of the taskEntryPoint function, needs to be this pointer - * of derived class - */ - void createTask(void* (*fnc_)(void*),void* arg_); - -private: - char name[PTHREAD_MAX_NAMELEN]; - int priority; - size_t stackSize = 0; -}; - -#endif /* FRAMEWORK_OSAL_LINUX_POSIXTHREAD_H_ */ +#ifndef FRAMEWORK_OSAL_LINUX_POSIXTHREAD_H_ +#define FRAMEWORK_OSAL_LINUX_POSIXTHREAD_H_ + +#include "../../returnvalues/HasReturnvaluesIF.h" +#include +#include +#include +#include + +class PosixThread { +public: + static constexpr uint8_t PTHREAD_MAX_NAMELEN = 16; + PosixThread(const char* name_, int priority_, size_t stackSize_); + virtual ~PosixThread(); + /** + * Set the Thread to sleep state + * @param ns Nanosecond sleep time + * @return Returns Failed if sleep fails + */ + static ReturnValue_t sleep(uint64_t ns); + /** + * @brief Function to suspend the task until SIGUSR1 was received + * + * @details Will be called in the beginning to suspend execution until startTask() is called explicitly. + */ + void suspend(); + + /** + * @brief Function to allow a other thread to start the thread again from suspend state + * + * @details Restarts the Thread after suspend call + */ + void resume(); + + + /** + * Delay function similar to FreeRtos delayUntil function + * + * @param prevoiusWakeTime_ms Needs the previous wake time and returns the next wakeup time + * @param delayTime_ms Time period to delay + * + * @return False If deadline was missed; True if task was delayed + */ + static bool delayUntil(uint64_t* const prevoiusWakeTime_ms, const uint64_t delayTime_ms); + + /** + * Returns the current time in milliseconds from CLOCK_MONOTONIC + * + * @return current time in milliseconds from CLOCK_MONOTONIC + */ + static uint64_t getCurrentMonotonicTimeMs(); + +protected: + pthread_t thread; + + /** + * @brief Function that has to be called by derived class because the + * derived class pointer has to be valid as argument. + * @details + * This function creates a pthread with the given parameters. As the + * function requires a pointer to the derived object it has to be called + * after the this pointer of the derived object is valid. + * Sets the taskEntryPoint as function to be called by new a thread. + * @param fnc_ Function which will be executed by the thread. + * @param arg_ + * argument of the taskEntryPoint function, needs to be this pointer + * of derived class + */ + void createTask(void* (*fnc_)(void*),void* arg_); + +private: + char name[PTHREAD_MAX_NAMELEN]; + int priority; + size_t stackSize = 0; +}; + +#endif /* FRAMEWORK_OSAL_LINUX_POSIXTHREAD_H_ */ diff --git a/osal/linux/QueueFactory.cpp b/osal/linux/QueueFactory.cpp index 8bd9d52c..d1332504 100644 --- a/osal/linux/QueueFactory.cpp +++ b/osal/linux/QueueFactory.cpp @@ -1,38 +1,38 @@ -#include -#include -#include -#include -#include -#include - -QueueFactory* QueueFactory::factoryInstance = nullptr; - - -ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo, - MessageQueueMessageIF* message, MessageQueueId_t sentFrom, - bool ignoreFault) { - return MessageQueue::sendMessageFromMessageQueue(sendTo,message, - sentFrom,ignoreFault); -} - -QueueFactory* QueueFactory::instance() { - if (factoryInstance == nullptr) { - factoryInstance = new QueueFactory; - } - return factoryInstance; -} - -QueueFactory::QueueFactory() { -} - -QueueFactory::~QueueFactory() { -} - -MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, - size_t maxMessageSize) { - return new MessageQueue(messageDepth, maxMessageSize); -} - -void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { - delete queue; -} +#include "../../ipc/QueueFactory.h" +#include +#include +#include "../../osal/linux/MessageQueue.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" +#include + +QueueFactory* QueueFactory::factoryInstance = nullptr; + + +ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo, + MessageQueueMessageIF* message, MessageQueueId_t sentFrom, + bool ignoreFault) { + return MessageQueue::sendMessageFromMessageQueue(sendTo,message, + sentFrom,ignoreFault); +} + +QueueFactory* QueueFactory::instance() { + if (factoryInstance == nullptr) { + factoryInstance = new QueueFactory; + } + return factoryInstance; +} + +QueueFactory::QueueFactory() { +} + +QueueFactory::~QueueFactory() { +} + +MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, + size_t maxMessageSize) { + return new MessageQueue(messageDepth, maxMessageSize); +} + +void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { + delete queue; +} diff --git a/osal/linux/SemaphoreFactory.cpp b/osal/linux/SemaphoreFactory.cpp index 4fbd60d9..43b1978d 100644 --- a/osal/linux/SemaphoreFactory.cpp +++ b/osal/linux/SemaphoreFactory.cpp @@ -1,36 +1,36 @@ -#include -#include -#include -#include - -const uint32_t SemaphoreIF::POLLING = 0; -const uint32_t SemaphoreIF::BLOCKING = 0xffffffff; - -SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr; - -SemaphoreFactory::SemaphoreFactory() { -} - -SemaphoreFactory::~SemaphoreFactory() { - delete factoryInstance; -} - -SemaphoreFactory* SemaphoreFactory::instance() { - if (factoryInstance == nullptr){ - factoryInstance = new SemaphoreFactory(); - } - return SemaphoreFactory::factoryInstance; -} - -SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t arguments) { - return new BinarySemaphore(); -} - -SemaphoreIF* SemaphoreFactory::createCountingSemaphore(const uint8_t maxCount, - uint8_t initCount, uint32_t arguments) { - return new CountingSemaphore(maxCount, initCount); -} - -void SemaphoreFactory::deleteSemaphore(SemaphoreIF* semaphore) { - delete semaphore; -} +#include "../../tasks/SemaphoreFactory.h" +#include "../../osal/linux/BinarySemaphore.h" +#include "../../osal/linux/CountingSemaphore.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" + +const uint32_t SemaphoreIF::POLLING = 0; +const uint32_t SemaphoreIF::BLOCKING = 0xffffffff; + +SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr; + +SemaphoreFactory::SemaphoreFactory() { +} + +SemaphoreFactory::~SemaphoreFactory() { + delete factoryInstance; +} + +SemaphoreFactory* SemaphoreFactory::instance() { + if (factoryInstance == nullptr){ + factoryInstance = new SemaphoreFactory(); + } + return SemaphoreFactory::factoryInstance; +} + +SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t arguments) { + return new BinarySemaphore(); +} + +SemaphoreIF* SemaphoreFactory::createCountingSemaphore(const uint8_t maxCount, + uint8_t initCount, uint32_t arguments) { + return new CountingSemaphore(maxCount, initCount); +} + +void SemaphoreFactory::deleteSemaphore(SemaphoreIF* semaphore) { + delete semaphore; +} diff --git a/osal/linux/TaskFactory.cpp b/osal/linux/TaskFactory.cpp index 219630a7..1cd0b2b1 100644 --- a/osal/linux/TaskFactory.cpp +++ b/osal/linux/TaskFactory.cpp @@ -1,42 +1,42 @@ -#include -#include -#include -#include - -//TODO: Different variant than the lazy loading in QueueFactory. What's better and why? -TaskFactory* TaskFactory::factoryInstance = new TaskFactory(); - -TaskFactory::~TaskFactory() { -} - -TaskFactory* TaskFactory::instance() { - return TaskFactory::factoryInstance; -} - -PeriodicTaskIF* TaskFactory::createPeriodicTask(TaskName name_, - TaskPriority taskPriority_,TaskStackSize stackSize_, - TaskPeriod periodInSeconds_, - TaskDeadlineMissedFunction deadLineMissedFunction_) { - return new PeriodicPosixTask(name_, taskPriority_,stackSize_, - periodInSeconds_ * 1000, deadLineMissedFunction_); -} - -FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(TaskName name_, - TaskPriority taskPriority_,TaskStackSize stackSize_, - TaskPeriod periodInSeconds_, - TaskDeadlineMissedFunction deadLineMissedFunction_) { - return new FixedTimeslotTask(name_, taskPriority_,stackSize_, - periodInSeconds_*1000); -} - -ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) { - //TODO not implemented - return HasReturnvaluesIF::RETURN_FAILED; -} - -ReturnValue_t TaskFactory::delayTask(uint32_t delayMs){ - return PosixThread::sleep(delayMs*1000000ull); -} - -TaskFactory::TaskFactory() { -} +#include "../../osal/linux/FixedTimeslotTask.h" +#include "../../osal/linux/PeriodicPosixTask.h" +#include "../../tasks/TaskFactory.h" +#include "../../returnvalues/HasReturnvaluesIF.h" + +//TODO: Different variant than the lazy loading in QueueFactory. What's better and why? +TaskFactory* TaskFactory::factoryInstance = new TaskFactory(); + +TaskFactory::~TaskFactory() { +} + +TaskFactory* TaskFactory::instance() { + return TaskFactory::factoryInstance; +} + +PeriodicTaskIF* TaskFactory::createPeriodicTask(TaskName name_, + TaskPriority taskPriority_,TaskStackSize stackSize_, + TaskPeriod periodInSeconds_, + TaskDeadlineMissedFunction deadLineMissedFunction_) { + return new PeriodicPosixTask(name_, taskPriority_,stackSize_, + periodInSeconds_ * 1000, deadLineMissedFunction_); +} + +FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(TaskName name_, + TaskPriority taskPriority_,TaskStackSize stackSize_, + TaskPeriod periodInSeconds_, + TaskDeadlineMissedFunction deadLineMissedFunction_) { + return new FixedTimeslotTask(name_, taskPriority_,stackSize_, + periodInSeconds_*1000); +} + +ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) { + //TODO not implemented + return HasReturnvaluesIF::RETURN_FAILED; +} + +ReturnValue_t TaskFactory::delayTask(uint32_t delayMs){ + return PosixThread::sleep(delayMs*1000000ull); +} + +TaskFactory::TaskFactory() { +} diff --git a/osal/linux/TcUnixUdpPollingTask.cpp b/osal/linux/TcUnixUdpPollingTask.cpp index 8cf7b285..04c1d255 100644 --- a/osal/linux/TcUnixUdpPollingTask.cpp +++ b/osal/linux/TcUnixUdpPollingTask.cpp @@ -1,137 +1,137 @@ -#include -#include - -TcUnixUdpPollingTask::TcUnixUdpPollingTask(object_id_t objectId, - object_id_t tmtcUnixUdpBridge, size_t frameSize, - double timeoutSeconds): SystemObject(objectId), - tmtcBridgeId(tmtcUnixUdpBridge) { - - if(frameSize > 0) { - this->frameSize = frameSize; - } - else { - this->frameSize = DEFAULT_MAX_FRAME_SIZE; - } - - // Set up reception buffer with specified frame size. - // For now, it is assumed that only one frame is held in the buffer! - receptionBuffer.reserve(this->frameSize); - receptionBuffer.resize(this->frameSize); - - if(timeoutSeconds == -1) { - receptionTimeout = DEFAULT_TIMEOUT; - } - else { - receptionTimeout = timevalOperations::toTimeval(timeoutSeconds); - } -} - -TcUnixUdpPollingTask::~TcUnixUdpPollingTask() {} - -ReturnValue_t TcUnixUdpPollingTask::performOperation(uint8_t opCode) { - // Poll for new UDP datagrams in permanent loop. - while(1) { - //! Sender Address is cached here. - struct sockaddr_in senderAddress; - socklen_t senderSockLen = 0; - ssize_t bytesReceived = recvfrom(serverUdpSocket, - receptionBuffer.data(), frameSize, receptionFlags, - reinterpret_cast(&senderAddress), &senderSockLen); - if(bytesReceived < 0) { - // handle error - sif::error << "TcSocketPollingTask::performOperation: Reception" - "error." << std::endl; - handleReadError(); - - continue; - } -// sif::debug << "TcSocketPollingTask::performOperation: " << bytesReceived -// << " bytes received" << std::endl; - - ReturnValue_t result = handleSuccessfullTcRead(bytesReceived); - if(result != HasReturnvaluesIF::RETURN_FAILED) { - - } - tmtcBridge->registerCommConnect(); - tmtcBridge->checkAndSetClientAddress(senderAddress); - } - return HasReturnvaluesIF::RETURN_OK; -} - - -ReturnValue_t TcUnixUdpPollingTask::handleSuccessfullTcRead(size_t bytesRead) { - store_address_t storeId; - ReturnValue_t result = tcStore->addData(&storeId, - receptionBuffer.data(), bytesRead); - // arrayprinter::print(receptionBuffer.data(), bytesRead); - if (result != HasReturnvaluesIF::RETURN_OK) { - sif::error << "TcSerialPollingTask::transferPusToSoftwareBus: Data " - "storage failed" << std::endl; - sif::error << "Packet size: " << bytesRead << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - - TmTcMessage message(storeId); - - result = MessageQueueSenderIF::sendMessage(targetTcDestination, &message); - if (result != HasReturnvaluesIF::RETURN_OK) { - sif::error << "Serial Polling: Sending message to queue failed" - << std::endl; - tcStore->deleteData(storeId); - } - return result; -} - -ReturnValue_t TcUnixUdpPollingTask::initialize() { - tcStore = objectManager->get(objects::TC_STORE); - if (tcStore == nullptr) { - sif::error << "TcSerialPollingTask::initialize: TC Store uninitialized!" - << std::endl; - return ObjectManagerIF::CHILD_INIT_FAILED; - } - - tmtcBridge = objectManager->get(tmtcBridgeId); - if(tmtcBridge == nullptr) { - sif::error << "TcSocketPollingTask::TcSocketPollingTask: Invalid" - " TMTC bridge object!" << std::endl; - return ObjectManagerIF::CHILD_INIT_FAILED; - } - - serverUdpSocket = tmtcBridge->serverSocket; - - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t TcUnixUdpPollingTask::initializeAfterTaskCreation() { - // Initialize the destination after task creation. This ensures - // that the destination will be set in the TMTC bridge. - targetTcDestination = tmtcBridge->getRequestQueue(); - return HasReturnvaluesIF::RETURN_OK; -} - -void TcUnixUdpPollingTask::setTimeout(double timeoutSeconds) { - timeval tval; - tval = timevalOperations::toTimeval(timeoutSeconds); - int result = setsockopt(serverUdpSocket, SOL_SOCKET, SO_RCVTIMEO, - &tval, sizeof(receptionTimeout)); - if(result == -1) { - sif::error << "TcSocketPollingTask::TcSocketPollingTask: Setting " - "receive timeout failed with " << strerror(errno) << std::endl; - } -} - -void TcUnixUdpPollingTask::handleReadError() { - switch(errno) { - case(EAGAIN): { - // todo: When working in timeout mode, this will occur more often - // and is not an error. - sif::error << "TcUnixUdpPollingTask::handleReadError: Timeout." - << std::endl; - break; - } - default: { - sif::error << "TcUnixUdpPollingTask::handleReadError: " - << strerror(errno) << std::endl; - } - } -} +#include "../../osal/linux/TcUnixUdpPollingTask.h" +#include "../../globalfunctions/arrayprinter.h" + +TcUnixUdpPollingTask::TcUnixUdpPollingTask(object_id_t objectId, + object_id_t tmtcUnixUdpBridge, size_t frameSize, + double timeoutSeconds): SystemObject(objectId), + tmtcBridgeId(tmtcUnixUdpBridge) { + + if(frameSize > 0) { + this->frameSize = frameSize; + } + else { + this->frameSize = DEFAULT_MAX_FRAME_SIZE; + } + + // Set up reception buffer with specified frame size. + // For now, it is assumed that only one frame is held in the buffer! + receptionBuffer.reserve(this->frameSize); + receptionBuffer.resize(this->frameSize); + + if(timeoutSeconds == -1) { + receptionTimeout = DEFAULT_TIMEOUT; + } + else { + receptionTimeout = timevalOperations::toTimeval(timeoutSeconds); + } +} + +TcUnixUdpPollingTask::~TcUnixUdpPollingTask() {} + +ReturnValue_t TcUnixUdpPollingTask::performOperation(uint8_t opCode) { + // Poll for new UDP datagrams in permanent loop. + while(1) { + //! Sender Address is cached here. + struct sockaddr_in senderAddress; + socklen_t senderSockLen = 0; + ssize_t bytesReceived = recvfrom(serverUdpSocket, + receptionBuffer.data(), frameSize, receptionFlags, + reinterpret_cast(&senderAddress), &senderSockLen); + if(bytesReceived < 0) { + // handle error + sif::error << "TcSocketPollingTask::performOperation: Reception" + "error." << std::endl; + handleReadError(); + + continue; + } +// sif::debug << "TcSocketPollingTask::performOperation: " << bytesReceived +// << " bytes received" << std::endl; + + ReturnValue_t result = handleSuccessfullTcRead(bytesReceived); + if(result != HasReturnvaluesIF::RETURN_FAILED) { + + } + tmtcBridge->registerCommConnect(); + tmtcBridge->checkAndSetClientAddress(senderAddress); + } + return HasReturnvaluesIF::RETURN_OK; +} + + +ReturnValue_t TcUnixUdpPollingTask::handleSuccessfullTcRead(size_t bytesRead) { + store_address_t storeId; + ReturnValue_t result = tcStore->addData(&storeId, + receptionBuffer.data(), bytesRead); + // arrayprinter::print(receptionBuffer.data(), bytesRead); + if (result != HasReturnvaluesIF::RETURN_OK) { + sif::error << "TcSerialPollingTask::transferPusToSoftwareBus: Data " + "storage failed" << std::endl; + sif::error << "Packet size: " << bytesRead << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + + TmTcMessage message(storeId); + + result = MessageQueueSenderIF::sendMessage(targetTcDestination, &message); + if (result != HasReturnvaluesIF::RETURN_OK) { + sif::error << "Serial Polling: Sending message to queue failed" + << std::endl; + tcStore->deleteData(storeId); + } + return result; +} + +ReturnValue_t TcUnixUdpPollingTask::initialize() { + tcStore = objectManager->get(objects::TC_STORE); + if (tcStore == nullptr) { + sif::error << "TcSerialPollingTask::initialize: TC Store uninitialized!" + << std::endl; + return ObjectManagerIF::CHILD_INIT_FAILED; + } + + tmtcBridge = objectManager->get(tmtcBridgeId); + if(tmtcBridge == nullptr) { + sif::error << "TcSocketPollingTask::TcSocketPollingTask: Invalid" + " TMTC bridge object!" << std::endl; + return ObjectManagerIF::CHILD_INIT_FAILED; + } + + serverUdpSocket = tmtcBridge->serverSocket; + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t TcUnixUdpPollingTask::initializeAfterTaskCreation() { + // Initialize the destination after task creation. This ensures + // that the destination will be set in the TMTC bridge. + targetTcDestination = tmtcBridge->getRequestQueue(); + return HasReturnvaluesIF::RETURN_OK; +} + +void TcUnixUdpPollingTask::setTimeout(double timeoutSeconds) { + timeval tval; + tval = timevalOperations::toTimeval(timeoutSeconds); + int result = setsockopt(serverUdpSocket, SOL_SOCKET, SO_RCVTIMEO, + &tval, sizeof(receptionTimeout)); + if(result == -1) { + sif::error << "TcSocketPollingTask::TcSocketPollingTask: Setting " + "receive timeout failed with " << strerror(errno) << std::endl; + } +} + +void TcUnixUdpPollingTask::handleReadError() { + switch(errno) { + case(EAGAIN): { + // todo: When working in timeout mode, this will occur more often + // and is not an error. + sif::error << "TcUnixUdpPollingTask::handleReadError: Timeout." + << std::endl; + break; + } + default: { + sif::error << "TcUnixUdpPollingTask::handleReadError: " + << strerror(errno) << std::endl; + } + } +} diff --git a/osal/linux/TcUnixUdpPollingTask.h b/osal/linux/TcUnixUdpPollingTask.h index d8de1458..9d678a81 100644 --- a/osal/linux/TcUnixUdpPollingTask.h +++ b/osal/linux/TcUnixUdpPollingTask.h @@ -1,67 +1,67 @@ -#ifndef FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_ -#define FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_ - -#include -#include -#include - -#include -#include - -/** - * @brief This class can be used to implement the polling of a Unix socket, - * using UDP for now. - * @details - * The task will be blocked while the specified number of bytes has not been - * received, so TC reception is handled inside a separate task. - * This class caches the IP address of the sender. It is assumed there - * is only one sender for now. - */ -class TcUnixUdpPollingTask: public SystemObject, - public ExecutableObjectIF { - friend class TmTcUnixUdpBridge; -public: - static constexpr size_t DEFAULT_MAX_FRAME_SIZE = 2048; - //! 0.5 default milliseconds timeout for now. - static constexpr timeval DEFAULT_TIMEOUT = {.tv_sec = 0, .tv_usec = 500}; - - TcUnixUdpPollingTask(object_id_t objectId, object_id_t tmtcUnixUdpBridge, - size_t frameSize = 0, double timeoutSeconds = -1); - virtual~ TcUnixUdpPollingTask(); - - /** - * Turn on optional timeout for UDP polling. In the default mode, - * the receive function will block until a packet is received. - * @param timeoutSeconds - */ - void setTimeout(double timeoutSeconds); - - virtual ReturnValue_t performOperation(uint8_t opCode) override; - virtual ReturnValue_t initialize() override; - virtual ReturnValue_t initializeAfterTaskCreation() override; - -protected: - StorageManagerIF* tcStore = nullptr; - -private: - //! TMTC bridge is cached. - object_id_t tmtcBridgeId = objects::NO_OBJECT; - TmTcUnixUdpBridge* tmtcBridge = nullptr; - MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE; - //! Reception flags: https://linux.die.net/man/2/recvfrom. - int receptionFlags = 0; - - //! Server socket, which is member of TMTC bridge and is assigned in - //! constructor - int serverUdpSocket = 0; - - std::vector receptionBuffer; - - size_t frameSize = 0; - timeval receptionTimeout; - - ReturnValue_t handleSuccessfullTcRead(size_t bytesRead); - void handleReadError(); -}; - -#endif /* FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_ */ +#ifndef FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_ +#define FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_ + +#include "../../objectmanager/SystemObject.h" +#include "../../osal/linux/TmTcUnixUdpBridge.h" +#include "../../tasks/ExecutableObjectIF.h" + +#include +#include + +/** + * @brief This class can be used to implement the polling of a Unix socket, + * using UDP for now. + * @details + * The task will be blocked while the specified number of bytes has not been + * received, so TC reception is handled inside a separate task. + * This class caches the IP address of the sender. It is assumed there + * is only one sender for now. + */ +class TcUnixUdpPollingTask: public SystemObject, + public ExecutableObjectIF { + friend class TmTcUnixUdpBridge; +public: + static constexpr size_t DEFAULT_MAX_FRAME_SIZE = 2048; + //! 0.5 default milliseconds timeout for now. + static constexpr timeval DEFAULT_TIMEOUT = {.tv_sec = 0, .tv_usec = 500}; + + TcUnixUdpPollingTask(object_id_t objectId, object_id_t tmtcUnixUdpBridge, + size_t frameSize = 0, double timeoutSeconds = -1); + virtual~ TcUnixUdpPollingTask(); + + /** + * Turn on optional timeout for UDP polling. In the default mode, + * the receive function will block until a packet is received. + * @param timeoutSeconds + */ + void setTimeout(double timeoutSeconds); + + virtual ReturnValue_t performOperation(uint8_t opCode) override; + virtual ReturnValue_t initialize() override; + virtual ReturnValue_t initializeAfterTaskCreation() override; + +protected: + StorageManagerIF* tcStore = nullptr; + +private: + //! TMTC bridge is cached. + object_id_t tmtcBridgeId = objects::NO_OBJECT; + TmTcUnixUdpBridge* tmtcBridge = nullptr; + MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE; + //! Reception flags: https://linux.die.net/man/2/recvfrom. + int receptionFlags = 0; + + //! Server socket, which is member of TMTC bridge and is assigned in + //! constructor + int serverUdpSocket = 0; + + std::vector receptionBuffer; + + size_t frameSize = 0; + timeval receptionTimeout; + + ReturnValue_t handleSuccessfullTcRead(size_t bytesRead); + void handleReadError(); +}; + +#endif /* FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_ */ diff --git a/osal/linux/Timer.cpp b/osal/linux/Timer.cpp index 5e27c328..e4539521 100644 --- a/osal/linux/Timer.cpp +++ b/osal/linux/Timer.cpp @@ -1,42 +1,42 @@ -#include -#include -#include - -Timer::Timer() { - sigevent sigEvent; - sigEvent.sigev_notify = SIGEV_NONE; - sigEvent.sigev_signo = 0; - sigEvent.sigev_value.sival_ptr = &timerId; - int status = timer_create(CLOCK_MONOTONIC, &sigEvent, &timerId); - if(status!=0){ - sif::error << "Timer creation failed with: " << status << - " errno: " << errno << std::endl; - } -} - -Timer::~Timer() { - timer_delete(timerId); -} - -int Timer::setTimer(uint32_t intervalMs) { - itimerspec timer; - timer.it_value.tv_sec = intervalMs / 1000; - timer.it_value.tv_nsec = (intervalMs * 1000000) % (1000000000); - timer.it_interval.tv_sec = 0; - timer.it_interval.tv_nsec = 0; - return timer_settime(timerId, 0, &timer, NULL); -} - - -int Timer::getTimer(uint32_t* remainingTimeMs){ - itimerspec timer; - timer.it_value.tv_sec = 0; - timer.it_value.tv_nsec = 0; - timer.it_interval.tv_sec = 0; - timer.it_interval.tv_nsec = 0; - int status = timer_gettime(timerId, &timer); - - *remainingTimeMs = timer.it_value.tv_sec * 1000 + timer.it_value.tv_nsec / 1000000; - - return status; -} +#include "../../serviceinterface/ServiceInterfaceStream.h" +#include +#include "../../osal/linux/Timer.h" + +Timer::Timer() { + sigevent sigEvent; + sigEvent.sigev_notify = SIGEV_NONE; + sigEvent.sigev_signo = 0; + sigEvent.sigev_value.sival_ptr = &timerId; + int status = timer_create(CLOCK_MONOTONIC, &sigEvent, &timerId); + if(status!=0){ + sif::error << "Timer creation failed with: " << status << + " errno: " << errno << std::endl; + } +} + +Timer::~Timer() { + timer_delete(timerId); +} + +int Timer::setTimer(uint32_t intervalMs) { + itimerspec timer; + timer.it_value.tv_sec = intervalMs / 1000; + timer.it_value.tv_nsec = (intervalMs * 1000000) % (1000000000); + timer.it_interval.tv_sec = 0; + timer.it_interval.tv_nsec = 0; + return timer_settime(timerId, 0, &timer, NULL); +} + + +int Timer::getTimer(uint32_t* remainingTimeMs){ + itimerspec timer; + timer.it_value.tv_sec = 0; + timer.it_value.tv_nsec = 0; + timer.it_interval.tv_sec = 0; + timer.it_interval.tv_nsec = 0; + int status = timer_gettime(timerId, &timer); + + *remainingTimeMs = timer.it_value.tv_sec * 1000 + timer.it_value.tv_nsec / 1000000; + + return status; +} diff --git a/osal/linux/TmTcUnixUdpBridge.cpp b/osal/linux/TmTcUnixUdpBridge.cpp index 2cdb93f3..57722b3f 100644 --- a/osal/linux/TmTcUnixUdpBridge.cpp +++ b/osal/linux/TmTcUnixUdpBridge.cpp @@ -1,168 +1,168 @@ -#include -#include -#include - -#include -#include - -TmTcUnixUdpBridge::TmTcUnixUdpBridge(object_id_t objectId, - object_id_t tcDestination, object_id_t tmStoreId, object_id_t tcStoreId, - uint16_t serverPort, uint16_t clientPort): - TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) { - mutex = MutexFactory::instance()->createMutex(); - - uint16_t setServerPort = DEFAULT_UDP_SERVER_PORT; - if(serverPort != 0xFFFF) { - setServerPort = serverPort; - } - - uint16_t setClientPort = DEFAULT_UDP_CLIENT_PORT; - if(clientPort != 0xFFFF) { - setClientPort = clientPort; - } - - // Set up UDP socket: https://man7.org/linux/man-pages/man7/ip.7.html - //clientSocket = socket(AF_INET, SOCK_DGRAM, 0); - serverSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if(socket < 0) { - sif::error << "TmTcUnixUdpBridge::TmTcUnixUdpBridge: Could not open" - " UDP socket!" << std::endl; - handleSocketError(); - return; - } - - serverAddress.sin_family = AF_INET; - - // Accept packets from any interface. - //serverAddress.sin_addr.s_addr = inet_addr("127.73.73.0"); - serverAddress.sin_addr.s_addr = htonl(INADDR_ANY); - serverAddress.sin_port = htons(setServerPort); - serverAddressLen = sizeof(serverAddress); - setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &serverSocketOptions, - sizeof(serverSocketOptions)); - - clientAddress.sin_family = AF_INET; - clientAddress.sin_addr.s_addr = htonl(INADDR_ANY); - clientAddress.sin_port = htons(setClientPort); - clientAddressLen = sizeof(clientAddress); - - int result = bind(serverSocket, - reinterpret_cast(&serverAddress), - serverAddressLen); - if(result == -1) { - sif::error << "TmTcUnixUdpBridge::TmTcUnixUdpBridge: Could not bind " - "local port " << setServerPort << " to server socket!" - << std::endl; - handleBindError(); - return; - } -} - -TmTcUnixUdpBridge::~TmTcUnixUdpBridge() { -} - -ReturnValue_t TmTcUnixUdpBridge::sendTm(const uint8_t *data, size_t dataLen) { - int flags = 0; - - clientAddress.sin_addr.s_addr = htons(INADDR_ANY); - //clientAddress.sin_addr.s_addr = inet_addr("127.73.73.1"); - clientAddressLen = sizeof(serverAddress); - -// char ipAddress [15]; -// sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET, -// &clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl; - - ssize_t bytesSent = sendto(serverSocket, data, dataLen, flags, - reinterpret_cast(&clientAddress), clientAddressLen); - if(bytesSent < 0) { - sif::error << "TmTcUnixUdpBridge::sendTm: Send operation failed." - << std::endl; - handleSendError(); - } -// sif::debug << "TmTcUnixUdpBridge::sendTm: " << bytesSent << " bytes were" -// " sent." << std::endl; - return HasReturnvaluesIF::RETURN_OK; -} - -void TmTcUnixUdpBridge::checkAndSetClientAddress(sockaddr_in newAddress) { - MutexHelper lock(mutex, MutexIF::TimeoutType::WAITING, 10); - -// char ipAddress [15]; -// sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET, -// &newAddress.sin_addr.s_addr, ipAddress, 15) << std::endl; -// sif::debug << "IP Address Old: " << inet_ntop(AF_INET, -// &clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl; - - // Set new IP address if it has changed. - if(clientAddress.sin_addr.s_addr != newAddress.sin_addr.s_addr) { - clientAddress.sin_addr.s_addr = newAddress.sin_addr.s_addr; - clientAddressLen = sizeof(clientAddress); - } -} - -void TmTcUnixUdpBridge::handleSocketError() { - - // See: https://man7.org/linux/man-pages/man2/socket.2.html - switch(errno) { - case(EACCES): - case(EINVAL): - case(EMFILE): - case(ENFILE): - case(EAFNOSUPPORT): - case(ENOBUFS): - case(ENOMEM): - case(EPROTONOSUPPORT): - sif::error << "TmTcUnixBridge::handleSocketError: Socket creation failed" - << " with " << strerror(errno) << std::endl; - break; - default: - sif::error << "TmTcUnixBridge::handleSocketError: Unknown error" - << std::endl; - break; - } -} - -void TmTcUnixUdpBridge::handleBindError() { - // See: https://man7.org/linux/man-pages/man2/bind.2.html - switch(errno) { - case(EACCES): { - /* - Ephermeral ports can be shown with following command: - sysctl -A | grep ip_local_port_range - */ - sif::error << "TmTcUnixBridge::handleBindError: Port access issue." - "Ports 1-1024 are reserved on UNIX systems and require root " - "rights while ephermeral ports should not be used as well." - << std::endl; - } - break; - case(EADDRINUSE): - case(EBADF): - case(EINVAL): - case(ENOTSOCK): - case(EADDRNOTAVAIL): - case(EFAULT): - case(ELOOP): - case(ENAMETOOLONG): - case(ENOENT): - case(ENOMEM): - case(ENOTDIR): - case(EROFS): { - sif::error << "TmTcUnixBridge::handleBindError: Socket creation failed" - << " with " << strerror(errno) << std::endl; - break; - } - default: - sif::error << "TmTcUnixBridge::handleBindError: Unknown error" - << std::endl; - break; - } -} - -void TmTcUnixUdpBridge::handleSendError() { - switch(errno) { - default: - sif::error << "Error: " << strerror(errno) << std::endl; - } -} - +#include "../../osal/linux/TmTcUnixUdpBridge.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "../../ipc/MutexHelper.h" + +#include +#include + +TmTcUnixUdpBridge::TmTcUnixUdpBridge(object_id_t objectId, + object_id_t tcDestination, object_id_t tmStoreId, object_id_t tcStoreId, + uint16_t serverPort, uint16_t clientPort): + TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) { + mutex = MutexFactory::instance()->createMutex(); + + uint16_t setServerPort = DEFAULT_UDP_SERVER_PORT; + if(serverPort != 0xFFFF) { + setServerPort = serverPort; + } + + uint16_t setClientPort = DEFAULT_UDP_CLIENT_PORT; + if(clientPort != 0xFFFF) { + setClientPort = clientPort; + } + + // Set up UDP socket: https://man7.org/linux/man-pages/man7/ip.7.html + //clientSocket = socket(AF_INET, SOCK_DGRAM, 0); + serverSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if(socket < 0) { + sif::error << "TmTcUnixUdpBridge::TmTcUnixUdpBridge: Could not open" + " UDP socket!" << std::endl; + handleSocketError(); + return; + } + + serverAddress.sin_family = AF_INET; + + // Accept packets from any interface. + //serverAddress.sin_addr.s_addr = inet_addr("127.73.73.0"); + serverAddress.sin_addr.s_addr = htonl(INADDR_ANY); + serverAddress.sin_port = htons(setServerPort); + serverAddressLen = sizeof(serverAddress); + setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &serverSocketOptions, + sizeof(serverSocketOptions)); + + clientAddress.sin_family = AF_INET; + clientAddress.sin_addr.s_addr = htonl(INADDR_ANY); + clientAddress.sin_port = htons(setClientPort); + clientAddressLen = sizeof(clientAddress); + + int result = bind(serverSocket, + reinterpret_cast(&serverAddress), + serverAddressLen); + if(result == -1) { + sif::error << "TmTcUnixUdpBridge::TmTcUnixUdpBridge: Could not bind " + "local port " << setServerPort << " to server socket!" + << std::endl; + handleBindError(); + return; + } +} + +TmTcUnixUdpBridge::~TmTcUnixUdpBridge() { +} + +ReturnValue_t TmTcUnixUdpBridge::sendTm(const uint8_t *data, size_t dataLen) { + int flags = 0; + + clientAddress.sin_addr.s_addr = htons(INADDR_ANY); + //clientAddress.sin_addr.s_addr = inet_addr("127.73.73.1"); + clientAddressLen = sizeof(serverAddress); + +// char ipAddress [15]; +// sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET, +// &clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl; + + ssize_t bytesSent = sendto(serverSocket, data, dataLen, flags, + reinterpret_cast(&clientAddress), clientAddressLen); + if(bytesSent < 0) { + sif::error << "TmTcUnixUdpBridge::sendTm: Send operation failed." + << std::endl; + handleSendError(); + } +// sif::debug << "TmTcUnixUdpBridge::sendTm: " << bytesSent << " bytes were" +// " sent." << std::endl; + return HasReturnvaluesIF::RETURN_OK; +} + +void TmTcUnixUdpBridge::checkAndSetClientAddress(sockaddr_in newAddress) { + MutexHelper lock(mutex, MutexIF::TimeoutType::WAITING, 10); + +// char ipAddress [15]; +// sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET, +// &newAddress.sin_addr.s_addr, ipAddress, 15) << std::endl; +// sif::debug << "IP Address Old: " << inet_ntop(AF_INET, +// &clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl; + + // Set new IP address if it has changed. + if(clientAddress.sin_addr.s_addr != newAddress.sin_addr.s_addr) { + clientAddress.sin_addr.s_addr = newAddress.sin_addr.s_addr; + clientAddressLen = sizeof(clientAddress); + } +} + +void TmTcUnixUdpBridge::handleSocketError() { + + // See: https://man7.org/linux/man-pages/man2/socket.2.html + switch(errno) { + case(EACCES): + case(EINVAL): + case(EMFILE): + case(ENFILE): + case(EAFNOSUPPORT): + case(ENOBUFS): + case(ENOMEM): + case(EPROTONOSUPPORT): + sif::error << "TmTcUnixBridge::handleSocketError: Socket creation failed" + << " with " << strerror(errno) << std::endl; + break; + default: + sif::error << "TmTcUnixBridge::handleSocketError: Unknown error" + << std::endl; + break; + } +} + +void TmTcUnixUdpBridge::handleBindError() { + // See: https://man7.org/linux/man-pages/man2/bind.2.html + switch(errno) { + case(EACCES): { + /* + Ephermeral ports can be shown with following command: + sysctl -A | grep ip_local_port_range + */ + sif::error << "TmTcUnixBridge::handleBindError: Port access issue." + "Ports 1-1024 are reserved on UNIX systems and require root " + "rights while ephermeral ports should not be used as well." + << std::endl; + } + break; + case(EADDRINUSE): + case(EBADF): + case(EINVAL): + case(ENOTSOCK): + case(EADDRNOTAVAIL): + case(EFAULT): + case(ELOOP): + case(ENAMETOOLONG): + case(ENOENT): + case(ENOMEM): + case(ENOTDIR): + case(EROFS): { + sif::error << "TmTcUnixBridge::handleBindError: Socket creation failed" + << " with " << strerror(errno) << std::endl; + break; + } + default: + sif::error << "TmTcUnixBridge::handleBindError: Unknown error" + << std::endl; + break; + } +} + +void TmTcUnixUdpBridge::handleSendError() { + switch(errno) { + default: + sif::error << "Error: " << strerror(errno) << std::endl; + } +} + diff --git a/osal/linux/TmTcUnixUdpBridge.h b/osal/linux/TmTcUnixUdpBridge.h index dbddc6c3..e4aa8b1a 100644 --- a/osal/linux/TmTcUnixUdpBridge.h +++ b/osal/linux/TmTcUnixUdpBridge.h @@ -1,48 +1,48 @@ -#ifndef FRAMEWORK_OSAL_LINUX_TMTCUNIXUDPBRIDGE_H_ -#define FRAMEWORK_OSAL_LINUX_TMTCUNIXUDPBRIDGE_H_ - -#include -#include -#include -#include -#include - -class TmTcUnixUdpBridge: public TmTcBridge { - friend class TcUnixUdpPollingTask; -public: - // The ports chosen here should not be used by any other process. - // List of used ports on Linux: /etc/services - static constexpr uint16_t DEFAULT_UDP_SERVER_PORT = 7301; - static constexpr uint16_t DEFAULT_UDP_CLIENT_PORT = 7302; - - TmTcUnixUdpBridge(object_id_t objectId, object_id_t tcDestination, - object_id_t tmStoreId, object_id_t tcStoreId, - uint16_t serverPort = 0xFFFF,uint16_t clientPort = 0xFFFF); - virtual~ TmTcUnixUdpBridge(); - - void checkAndSetClientAddress(sockaddr_in clientAddress); - -protected: - virtual ReturnValue_t sendTm(const uint8_t * data, size_t dataLen) override; - -private: - int serverSocket = 0; - - const int serverSocketOptions = 0; - - struct sockaddr_in clientAddress; - socklen_t clientAddressLen = 0; - - struct sockaddr_in serverAddress; - socklen_t serverAddressLen = 0; - - //! Access to the client address is mutex protected as it is set - //! by another task. - MutexIF* mutex; - - void handleSocketError(); - void handleBindError(); - void handleSendError(); -}; - -#endif /* FRAMEWORK_OSAL_LINUX_TMTCUNIXUDPBRIDGE_H_ */ +#ifndef FRAMEWORK_OSAL_LINUX_TMTCUNIXUDPBRIDGE_H_ +#define FRAMEWORK_OSAL_LINUX_TMTCUNIXUDPBRIDGE_H_ + +#include "../../tmtcservices/AcceptsTelecommandsIF.h" +#include "../../tmtcservices/TmTcBridge.h" +#include +#include +#include + +class TmTcUnixUdpBridge: public TmTcBridge { + friend class TcUnixUdpPollingTask; +public: + // The ports chosen here should not be used by any other process. + // List of used ports on Linux: /etc/services + static constexpr uint16_t DEFAULT_UDP_SERVER_PORT = 7301; + static constexpr uint16_t DEFAULT_UDP_CLIENT_PORT = 7302; + + TmTcUnixUdpBridge(object_id_t objectId, object_id_t tcDestination, + object_id_t tmStoreId, object_id_t tcStoreId, + uint16_t serverPort = 0xFFFF,uint16_t clientPort = 0xFFFF); + virtual~ TmTcUnixUdpBridge(); + + void checkAndSetClientAddress(sockaddr_in clientAddress); + +protected: + virtual ReturnValue_t sendTm(const uint8_t * data, size_t dataLen) override; + +private: + int serverSocket = 0; + + const int serverSocketOptions = 0; + + struct sockaddr_in clientAddress; + socklen_t clientAddressLen = 0; + + struct sockaddr_in serverAddress; + socklen_t serverAddressLen = 0; + + //! Access to the client address is mutex protected as it is set + //! by another task. + MutexIF* mutex; + + void handleSocketError(); + void handleBindError(); + void handleSendError(); +}; + +#endif /* FRAMEWORK_OSAL_LINUX_TMTCUNIXUDPBRIDGE_H_ */ diff --git a/osal/rtems/Clock.cpp b/osal/rtems/Clock.cpp index 98198dd3..826d0b14 100644 --- a/osal/rtems/Clock.cpp +++ b/osal/rtems/Clock.cpp @@ -1,198 +1,198 @@ -#include -#include "RtemsBasic.h" -#include - -uint16_t Clock::leapSeconds = 0; -MutexIF* Clock::timeMutex = NULL; - -uint32_t Clock::getTicksPerSecond(void){ - rtems_interval ticks_per_second = rtems_clock_get_ticks_per_second(); - return static_cast(ticks_per_second); -} - -ReturnValue_t Clock::setClock(const TimeOfDay_t* time) { - rtems_time_of_day timeRtems; - timeRtems.year = time->year; - timeRtems.month = time->month; - timeRtems.day = time->day; - timeRtems.hour = time->hour; - timeRtems.minute = time->minute; - timeRtems.second = time->second; - timeRtems.ticks = time->usecond * getTicksPerSecond() / 1e6; - rtems_status_code status = rtems_clock_set(&timeRtems); - switch(status){ - case RTEMS_SUCCESSFUL: - return HasReturnvaluesIF::RETURN_OK; - case RTEMS_INVALID_ADDRESS: - return HasReturnvaluesIF::RETURN_FAILED; - case RTEMS_INVALID_CLOCK: - return HasReturnvaluesIF::RETURN_FAILED; - default: - return HasReturnvaluesIF::RETURN_FAILED; - } -} - -ReturnValue_t Clock::setClock(const timeval* time) { - //TODO This routine uses _TOD_Set which is not - timespec newTime; - newTime.tv_sec = time->tv_sec; - newTime.tv_nsec = time->tv_usec * TOD_NANOSECONDS_PER_MICROSECOND; - //SHOULDDO: Not sure if we need to protect this call somehow (by thread lock or something). - //Uli: rtems docu says you can call this from an ISR, not sure if this means no protetion needed - //TODO Second parameter is ISR_lock_Context - _TOD_Set(&newTime,NULL); - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t Clock::getClock_timeval(timeval* time) { - //Callable from ISR - rtems_status_code status = rtems_clock_get_tod_timeval(time); - switch(status){ - case RTEMS_SUCCESSFUL: - return HasReturnvaluesIF::RETURN_OK; - case RTEMS_NOT_DEFINED: - return HasReturnvaluesIF::RETURN_FAILED; - default: - return HasReturnvaluesIF::RETURN_FAILED; - } -} - -ReturnValue_t Clock::getUptime(timeval* uptime) { - //According to docs.rtems.org for rtems 5 this method is more accurate than rtems_clock_get_ticks_since_boot - timespec time; - rtems_status_code status = rtems_clock_get_uptime(&time); - uptime->tv_sec = time.tv_sec; - time.tv_nsec = time.tv_nsec / 1000; - uptime->tv_usec = time.tv_nsec; - switch(status){ - case RTEMS_SUCCESSFUL: - return HasReturnvaluesIF::RETURN_OK; - default: - return HasReturnvaluesIF::RETURN_FAILED; - } -} - -ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) { - //This counter overflows after 50 days - *uptimeMs = rtems_clock_get_ticks_since_boot(); - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t Clock::getClock_usecs(uint64_t* time) { - timeval temp_time; - rtems_status_code returnValue = rtems_clock_get_tod_timeval(&temp_time); - *time = ((uint64_t) temp_time.tv_sec * 1000000) + temp_time.tv_usec; - switch(returnValue){ - case RTEMS_SUCCESSFUL: - return HasReturnvaluesIF::RETURN_OK; - default: - return HasReturnvaluesIF::RETURN_FAILED; - } -} - -ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) { - rtems_time_of_day* timeRtems = reinterpret_cast(time); - rtems_status_code status = rtems_clock_get_tod(timeRtems); - switch (status) { - case RTEMS_SUCCESSFUL: - return HasReturnvaluesIF::RETURN_OK; - case RTEMS_NOT_DEFINED: - //system date and time is not set - return HasReturnvaluesIF::RETURN_FAILED; - case RTEMS_INVALID_ADDRESS: - //time_buffer is NULL - return HasReturnvaluesIF::RETURN_FAILED; - default: - return HasReturnvaluesIF::RETURN_FAILED; - } -} - -ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from, - timeval* to) { - //Fails in 2038.. - rtems_time_of_day timeRtems; - timeRtems.year = from->year; - timeRtems.month = from->month; - timeRtems.day = from->day; - timeRtems.hour = from->hour; - timeRtems.minute = from->minute; - timeRtems.second = from->second; - timeRtems.ticks = from->usecond * getTicksPerSecond() / 1e6; - to->tv_sec = _TOD_To_seconds(&timeRtems); - to->tv_usec = from->usecond; - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) { - *JD2000 = (time.tv_sec - 946728000. + time.tv_usec / 1000000.) / 24. - / 3600.; - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) { - //SHOULDDO: works not for dates in the past (might have less leap seconds) - if (timeMutex == NULL) { - return HasReturnvaluesIF::RETURN_FAILED; - } - - uint16_t leapSeconds; - ReturnValue_t result = getLeapSeconds(&leapSeconds); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - timeval leapSeconds_timeval = { 0, 0 }; - leapSeconds_timeval.tv_sec = leapSeconds; - - //initial offset between UTC and TAI - timeval UTCtoTAI1972 = { 10, 0 }; - - timeval TAItoTT = { 32, 184000 }; - - *tt = utc + leapSeconds_timeval + UTCtoTAI1972 + TAItoTT; - - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) { - if(checkOrCreateClockMutex()!=HasReturnvaluesIF::RETURN_OK){ - return HasReturnvaluesIF::RETURN_FAILED; - } - ReturnValue_t result = timeMutex->lockMutex(MutexIF::NO_TIMEOUT); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - leapSeconds = leapSeconds_; - - result = timeMutex->unlockMutex(); - return result; -} - -ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) { - if(timeMutex==NULL){ - return HasReturnvaluesIF::RETURN_FAILED; - } - ReturnValue_t result = timeMutex->lockMutex(MutexIF::NO_TIMEOUT); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - *leapSeconds_ = leapSeconds; - - result = timeMutex->unlockMutex(); - return result; -} - -ReturnValue_t Clock::checkOrCreateClockMutex(){ - if(timeMutex==NULL){ - MutexFactory* mutexFactory = MutexFactory::instance(); - if (mutexFactory == NULL) { - return HasReturnvaluesIF::RETURN_FAILED; - } - timeMutex = mutexFactory->createMutex(); - if (timeMutex == NULL) { - return HasReturnvaluesIF::RETURN_FAILED; - } - } - return HasReturnvaluesIF::RETURN_OK; -} +#include "../../timemanager/Clock.h" +#include "RtemsBasic.h" +#include + +uint16_t Clock::leapSeconds = 0; +MutexIF* Clock::timeMutex = NULL; + +uint32_t Clock::getTicksPerSecond(void){ + rtems_interval ticks_per_second = rtems_clock_get_ticks_per_second(); + return static_cast(ticks_per_second); +} + +ReturnValue_t Clock::setClock(const TimeOfDay_t* time) { + rtems_time_of_day timeRtems; + timeRtems.year = time->year; + timeRtems.month = time->month; + timeRtems.day = time->day; + timeRtems.hour = time->hour; + timeRtems.minute = time->minute; + timeRtems.second = time->second; + timeRtems.ticks = time->usecond * getTicksPerSecond() / 1e6; + rtems_status_code status = rtems_clock_set(&timeRtems); + switch(status){ + case RTEMS_SUCCESSFUL: + return HasReturnvaluesIF::RETURN_OK; + case RTEMS_INVALID_ADDRESS: + return HasReturnvaluesIF::RETURN_FAILED; + case RTEMS_INVALID_CLOCK: + return HasReturnvaluesIF::RETURN_FAILED; + default: + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +ReturnValue_t Clock::setClock(const timeval* time) { + //TODO This routine uses _TOD_Set which is not + timespec newTime; + newTime.tv_sec = time->tv_sec; + newTime.tv_nsec = time->tv_usec * TOD_NANOSECONDS_PER_MICROSECOND; + //SHOULDDO: Not sure if we need to protect this call somehow (by thread lock or something). + //Uli: rtems docu says you can call this from an ISR, not sure if this means no protetion needed + //TODO Second parameter is ISR_lock_Context + _TOD_Set(&newTime,NULL); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Clock::getClock_timeval(timeval* time) { + //Callable from ISR + rtems_status_code status = rtems_clock_get_tod_timeval(time); + switch(status){ + case RTEMS_SUCCESSFUL: + return HasReturnvaluesIF::RETURN_OK; + case RTEMS_NOT_DEFINED: + return HasReturnvaluesIF::RETURN_FAILED; + default: + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +ReturnValue_t Clock::getUptime(timeval* uptime) { + //According to docs.rtems.org for rtems 5 this method is more accurate than rtems_clock_get_ticks_since_boot + timespec time; + rtems_status_code status = rtems_clock_get_uptime(&time); + uptime->tv_sec = time.tv_sec; + time.tv_nsec = time.tv_nsec / 1000; + uptime->tv_usec = time.tv_nsec; + switch(status){ + case RTEMS_SUCCESSFUL: + return HasReturnvaluesIF::RETURN_OK; + default: + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) { + //This counter overflows after 50 days + *uptimeMs = rtems_clock_get_ticks_since_boot(); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Clock::getClock_usecs(uint64_t* time) { + timeval temp_time; + rtems_status_code returnValue = rtems_clock_get_tod_timeval(&temp_time); + *time = ((uint64_t) temp_time.tv_sec * 1000000) + temp_time.tv_usec; + switch(returnValue){ + case RTEMS_SUCCESSFUL: + return HasReturnvaluesIF::RETURN_OK; + default: + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) { + rtems_time_of_day* timeRtems = reinterpret_cast(time); + rtems_status_code status = rtems_clock_get_tod(timeRtems); + switch (status) { + case RTEMS_SUCCESSFUL: + return HasReturnvaluesIF::RETURN_OK; + case RTEMS_NOT_DEFINED: + //system date and time is not set + return HasReturnvaluesIF::RETURN_FAILED; + case RTEMS_INVALID_ADDRESS: + //time_buffer is NULL + return HasReturnvaluesIF::RETURN_FAILED; + default: + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from, + timeval* to) { + //Fails in 2038.. + rtems_time_of_day timeRtems; + timeRtems.year = from->year; + timeRtems.month = from->month; + timeRtems.day = from->day; + timeRtems.hour = from->hour; + timeRtems.minute = from->minute; + timeRtems.second = from->second; + timeRtems.ticks = from->usecond * getTicksPerSecond() / 1e6; + to->tv_sec = _TOD_To_seconds(&timeRtems); + to->tv_usec = from->usecond; + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) { + *JD2000 = (time.tv_sec - 946728000. + time.tv_usec / 1000000.) / 24. + / 3600.; + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) { + //SHOULDDO: works not for dates in the past (might have less leap seconds) + if (timeMutex == NULL) { + return HasReturnvaluesIF::RETURN_FAILED; + } + + uint16_t leapSeconds; + ReturnValue_t result = getLeapSeconds(&leapSeconds); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + timeval leapSeconds_timeval = { 0, 0 }; + leapSeconds_timeval.tv_sec = leapSeconds; + + //initial offset between UTC and TAI + timeval UTCtoTAI1972 = { 10, 0 }; + + timeval TAItoTT = { 32, 184000 }; + + *tt = utc + leapSeconds_timeval + UTCtoTAI1972 + TAItoTT; + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) { + if(checkOrCreateClockMutex()!=HasReturnvaluesIF::RETURN_OK){ + return HasReturnvaluesIF::RETURN_FAILED; + } + ReturnValue_t result = timeMutex->lockMutex(MutexIF::NO_TIMEOUT); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + leapSeconds = leapSeconds_; + + result = timeMutex->unlockMutex(); + return result; +} + +ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) { + if(timeMutex==NULL){ + return HasReturnvaluesIF::RETURN_FAILED; + } + ReturnValue_t result = timeMutex->lockMutex(MutexIF::NO_TIMEOUT); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + *leapSeconds_ = leapSeconds; + + result = timeMutex->unlockMutex(); + return result; +} + +ReturnValue_t Clock::checkOrCreateClockMutex(){ + if(timeMutex==NULL){ + MutexFactory* mutexFactory = MutexFactory::instance(); + if (mutexFactory == NULL) { + return HasReturnvaluesIF::RETURN_FAILED; + } + timeMutex = mutexFactory->createMutex(); + if (timeMutex == NULL) { + return HasReturnvaluesIF::RETURN_FAILED; + } + } + return HasReturnvaluesIF::RETURN_OK; +} diff --git a/osal/rtems/CpuUsage.cpp b/osal/rtems/CpuUsage.cpp index 61b66c3d..c5fac653 100644 --- a/osal/rtems/CpuUsage.cpp +++ b/osal/rtems/CpuUsage.cpp @@ -1,183 +1,183 @@ -#include "CpuUsage.h" -#include -#include -#include - -extern "C" { -#include -} - -int handlePrint(void * token, const char *format, ...) { - CpuUsage *cpuUsage = (CpuUsage *) token; - - if (cpuUsage->counter == 0) { - //header - cpuUsage->counter++; - return 0; - } - - if (cpuUsage->counter % 2 == 1) { - { - //we can not tell when the last call is so we assume it be every uneven time - va_list vl; - va_start(vl, format); - float timeSinceLastReset = va_arg(vl,uint32_t); - uint32_t timeSinceLastResetDecimals = va_arg(vl,uint32_t); - - timeSinceLastReset = timeSinceLastReset - + (timeSinceLastResetDecimals / 1000.); - - cpuUsage->timeSinceLastReset = timeSinceLastReset; - - va_end(vl); - } - //task name and id - va_list vl; - va_start(vl, format); - - cpuUsage->cachedValue.id = va_arg(vl,uint32_t); - const char *name = va_arg(vl,const char *); - memcpy(cpuUsage->cachedValue.name, name, - CpuUsage::ThreadData::MAX_LENGTH_OF_THREAD_NAME); - - va_end(vl); - - } else { - //statistics - va_list vl; - va_start(vl, format); - float run = va_arg(vl,uint32_t); - uint32_t runDecimals = va_arg(vl,uint32_t); - float percent = va_arg(vl,uint32_t); - uint32_t percent_decimals = va_arg(vl,uint32_t); - - run = run + (runDecimals / 1000.); - percent = percent + (percent_decimals / 1000.); - - cpuUsage->cachedValue.percentUsage = percent; - cpuUsage->cachedValue.timeRunning = run; - - cpuUsage->threadData.insert(cpuUsage->cachedValue); - - va_end(vl); - } - cpuUsage->counter++; - - return 0; -} - -CpuUsage::CpuUsage() : - counter(0), timeSinceLastReset(0) { - -} - -CpuUsage::~CpuUsage() { - -} - -void CpuUsage::resetCpuUsage() { - rtems_cpu_usage_reset(); -} - -void CpuUsage::read() { - //rtems_cpu_usage_report_with_plugin(this, &handlePrint); -} - -void CpuUsage::clear() { - counter = 0; - timeSinceLastReset = 0; - threadData.clear(); -} - -ReturnValue_t CpuUsage::serialize(uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) const { - ReturnValue_t result = SerializeAdapter::serialize( - &timeSinceLastReset, buffer, size, maxSize, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - return SerialArrayListAdapter::serialize(&threadData, buffer, - size, maxSize, streamEndianness); -} - -uint32_t CpuUsage::getSerializedSize() const { - uint32_t size = 0; - - size += sizeof(timeSinceLastReset); - size += SerialArrayListAdapter::getSerializedSize(&threadData); - - return size; -} - -ReturnValue_t CpuUsage::deSerialize(const uint8_t** buffer, size_t* size, - Endianness streamEndianness) { - ReturnValue_t result = SerializeAdapter::deSerialize( - &timeSinceLastReset, buffer, size, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - return SerialArrayListAdapter::deSerialize(&threadData, buffer, - size, streamEndianness); -} - -ReturnValue_t CpuUsage::ThreadData::serialize(uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) const { - ReturnValue_t result = SerializeAdapter::serialize(&id, buffer, - size, maxSize, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - if (*size + MAX_LENGTH_OF_THREAD_NAME > maxSize) { - return BUFFER_TOO_SHORT; - } - memcpy(*buffer, name, MAX_LENGTH_OF_THREAD_NAME); - *size += MAX_LENGTH_OF_THREAD_NAME; - *buffer += MAX_LENGTH_OF_THREAD_NAME; - result = SerializeAdapter::serialize(&timeRunning, - buffer, size, maxSize, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - result = SerializeAdapter::serialize(&percentUsage, - buffer, size, maxSize, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - return HasReturnvaluesIF::RETURN_OK; -} - -uint32_t CpuUsage::ThreadData::getSerializedSize() const { - uint32_t size = 0; - - size += sizeof(id); - size += MAX_LENGTH_OF_THREAD_NAME; - size += sizeof(timeRunning); - size += sizeof(percentUsage); - - return size; -} - -ReturnValue_t CpuUsage::ThreadData::deSerialize(const uint8_t** buffer, - int32_t* size, Endianness streamEndianness) { - ReturnValue_t result = SerializeAdapter::deSerialize(&id, buffer, - size, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - if ((*size = *size - MAX_LENGTH_OF_THREAD_NAME) < 0) { - return STREAM_TOO_SHORT; - } - memcpy(name, *buffer, MAX_LENGTH_OF_THREAD_NAME); - *buffer -= MAX_LENGTH_OF_THREAD_NAME; - result = SerializeAdapter::deSerialize(&timeRunning, - buffer, size, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - result = SerializeAdapter::deSerialize(&percentUsage, - buffer, size, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - return HasReturnvaluesIF::RETURN_OK; -} +#include "CpuUsage.h" +#include "../../serialize/SerialArrayListAdapter.h" +#include "../../serialize/SerializeAdapter.h" +#include + +extern "C" { +#include +} + +int handlePrint(void * token, const char *format, ...) { + CpuUsage *cpuUsage = (CpuUsage *) token; + + if (cpuUsage->counter == 0) { + //header + cpuUsage->counter++; + return 0; + } + + if (cpuUsage->counter % 2 == 1) { + { + //we can not tell when the last call is so we assume it be every uneven time + va_list vl; + va_start(vl, format); + float timeSinceLastReset = va_arg(vl,uint32_t); + uint32_t timeSinceLastResetDecimals = va_arg(vl,uint32_t); + + timeSinceLastReset = timeSinceLastReset + + (timeSinceLastResetDecimals / 1000.); + + cpuUsage->timeSinceLastReset = timeSinceLastReset; + + va_end(vl); + } + //task name and id + va_list vl; + va_start(vl, format); + + cpuUsage->cachedValue.id = va_arg(vl,uint32_t); + const char *name = va_arg(vl,const char *); + memcpy(cpuUsage->cachedValue.name, name, + CpuUsage::ThreadData::MAX_LENGTH_OF_THREAD_NAME); + + va_end(vl); + + } else { + //statistics + va_list vl; + va_start(vl, format); + float run = va_arg(vl,uint32_t); + uint32_t runDecimals = va_arg(vl,uint32_t); + float percent = va_arg(vl,uint32_t); + uint32_t percent_decimals = va_arg(vl,uint32_t); + + run = run + (runDecimals / 1000.); + percent = percent + (percent_decimals / 1000.); + + cpuUsage->cachedValue.percentUsage = percent; + cpuUsage->cachedValue.timeRunning = run; + + cpuUsage->threadData.insert(cpuUsage->cachedValue); + + va_end(vl); + } + cpuUsage->counter++; + + return 0; +} + +CpuUsage::CpuUsage() : + counter(0), timeSinceLastReset(0) { + +} + +CpuUsage::~CpuUsage() { + +} + +void CpuUsage::resetCpuUsage() { + rtems_cpu_usage_reset(); +} + +void CpuUsage::read() { + //rtems_cpu_usage_report_with_plugin(this, &handlePrint); +} + +void CpuUsage::clear() { + counter = 0; + timeSinceLastReset = 0; + threadData.clear(); +} + +ReturnValue_t CpuUsage::serialize(uint8_t** buffer, size_t* size, + size_t maxSize, Endianness streamEndianness) const { + ReturnValue_t result = SerializeAdapter::serialize( + &timeSinceLastReset, buffer, size, maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return SerialArrayListAdapter::serialize(&threadData, buffer, + size, maxSize, streamEndianness); +} + +uint32_t CpuUsage::getSerializedSize() const { + uint32_t size = 0; + + size += sizeof(timeSinceLastReset); + size += SerialArrayListAdapter::getSerializedSize(&threadData); + + return size; +} + +ReturnValue_t CpuUsage::deSerialize(const uint8_t** buffer, size_t* size, + Endianness streamEndianness) { + ReturnValue_t result = SerializeAdapter::deSerialize( + &timeSinceLastReset, buffer, size, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return SerialArrayListAdapter::deSerialize(&threadData, buffer, + size, streamEndianness); +} + +ReturnValue_t CpuUsage::ThreadData::serialize(uint8_t** buffer, size_t* size, + size_t maxSize, Endianness streamEndianness) const { + ReturnValue_t result = SerializeAdapter::serialize(&id, buffer, + size, maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if (*size + MAX_LENGTH_OF_THREAD_NAME > maxSize) { + return BUFFER_TOO_SHORT; + } + memcpy(*buffer, name, MAX_LENGTH_OF_THREAD_NAME); + *size += MAX_LENGTH_OF_THREAD_NAME; + *buffer += MAX_LENGTH_OF_THREAD_NAME; + result = SerializeAdapter::serialize(&timeRunning, + buffer, size, maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = SerializeAdapter::serialize(&percentUsage, + buffer, size, maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return HasReturnvaluesIF::RETURN_OK; +} + +uint32_t CpuUsage::ThreadData::getSerializedSize() const { + uint32_t size = 0; + + size += sizeof(id); + size += MAX_LENGTH_OF_THREAD_NAME; + size += sizeof(timeRunning); + size += sizeof(percentUsage); + + return size; +} + +ReturnValue_t CpuUsage::ThreadData::deSerialize(const uint8_t** buffer, + int32_t* size, Endianness streamEndianness) { + ReturnValue_t result = SerializeAdapter::deSerialize(&id, buffer, + size, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if ((*size = *size - MAX_LENGTH_OF_THREAD_NAME) < 0) { + return STREAM_TOO_SHORT; + } + memcpy(name, *buffer, MAX_LENGTH_OF_THREAD_NAME); + *buffer -= MAX_LENGTH_OF_THREAD_NAME; + result = SerializeAdapter::deSerialize(&timeRunning, + buffer, size, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = SerializeAdapter::deSerialize(&percentUsage, + buffer, size, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return HasReturnvaluesIF::RETURN_OK; +} diff --git a/osal/rtems/CpuUsage.h b/osal/rtems/CpuUsage.h index eb03c5e3..24cbb919 100644 --- a/osal/rtems/CpuUsage.h +++ b/osal/rtems/CpuUsage.h @@ -1,53 +1,53 @@ -#ifndef CPUUSAGE_H_ -#define CPUUSAGE_H_ - -#include -#include -#include - -class CpuUsage : public SerializeIF { -public: - static const uint8_t MAXIMUM_NUMBER_OF_THREADS = 30; - - class ThreadData: public SerializeIF { - public: - static const uint8_t MAX_LENGTH_OF_THREAD_NAME = 4; - - uint32_t id; - char name[MAX_LENGTH_OF_THREAD_NAME]; - float timeRunning; - float percentUsage; - - virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) const override; - - virtual size_t getSerializedSize() const override; - - virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - Endianness streamEndianness) override; - }; - - CpuUsage(); - virtual ~CpuUsage(); - - uint8_t counter; - float timeSinceLastReset; - FixedArrayList threadData; - ThreadData cachedValue; - - static void resetCpuUsage(); - - void read(); - - void clear(); - - virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) const override; - - virtual size_t getSerializedSize() const override; - - virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - Endianness streamEndianness) override; -}; - -#endif /* CPUUSAGE_H_ */ +#ifndef CPUUSAGE_H_ +#define CPUUSAGE_H_ + +#include "../../container/FixedArrayList.h" +#include "../../serialize/SerializeIF.h" +#include + +class CpuUsage : public SerializeIF { +public: + static const uint8_t MAXIMUM_NUMBER_OF_THREADS = 30; + + class ThreadData: public SerializeIF { + public: + static const uint8_t MAX_LENGTH_OF_THREAD_NAME = 4; + + uint32_t id; + char name[MAX_LENGTH_OF_THREAD_NAME]; + float timeRunning; + float percentUsage; + + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + size_t maxSize, Endianness streamEndianness) const override; + + virtual size_t getSerializedSize() const override; + + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + Endianness streamEndianness) override; + }; + + CpuUsage(); + virtual ~CpuUsage(); + + uint8_t counter; + float timeSinceLastReset; + FixedArrayList threadData; + ThreadData cachedValue; + + static void resetCpuUsage(); + + void read(); + + void clear(); + + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + size_t maxSize, Endianness streamEndianness) const override; + + virtual size_t getSerializedSize() const override; + + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + Endianness streamEndianness) override; +}; + +#endif /* CPUUSAGE_H_ */ diff --git a/osal/rtems/InternalErrorCodes.cpp b/osal/rtems/InternalErrorCodes.cpp index dbe3172e..3542ecce 100644 --- a/osal/rtems/InternalErrorCodes.cpp +++ b/osal/rtems/InternalErrorCodes.cpp @@ -1,60 +1,60 @@ -#include -#include - -ReturnValue_t InternalErrorCodes::translate(uint8_t code) { - switch (code) { - //TODO It looks like RTEMS-5 does not provide the same error codes -// case INTERNAL_ERROR_NO_CONFIGURATION_TABLE: -// return NO_CONFIGURATION_TABLE; -// case INTERNAL_ERROR_NO_CPU_TABLE: -// return NO_CPU_TABLE; -// case INTERNAL_ERROR_INVALID_WORKSPACE_ADDRESS: -// return INVALID_WORKSPACE_ADDRESS; - case INTERNAL_ERROR_TOO_LITTLE_WORKSPACE: - return TOO_LITTLE_WORKSPACE; - case INTERNAL_ERROR_WORKSPACE_ALLOCATION: - return WORKSPACE_ALLOCATION; -// case INTERNAL_ERROR_INTERRUPT_STACK_TOO_SMALL: -// return INTERRUPT_STACK_TOO_SMALL; - case INTERNAL_ERROR_THREAD_EXITTED: - return THREAD_EXITTED; - case INTERNAL_ERROR_INCONSISTENT_MP_INFORMATION: - return INCONSISTENT_MP_INFORMATION; - case INTERNAL_ERROR_INVALID_NODE: - return INVALID_NODE; - case INTERNAL_ERROR_NO_MPCI: - return NO_MPCI; - case INTERNAL_ERROR_BAD_PACKET: - return BAD_PACKET; - case INTERNAL_ERROR_OUT_OF_PACKETS: - return OUT_OF_PACKETS; - case INTERNAL_ERROR_OUT_OF_GLOBAL_OBJECTS: - return OUT_OF_GLOBAL_OBJECTS; - case INTERNAL_ERROR_OUT_OF_PROXIES: - return OUT_OF_PROXIES; - case INTERNAL_ERROR_INVALID_GLOBAL_ID: - return INVALID_GLOBAL_ID; - case INTERNAL_ERROR_BAD_STACK_HOOK: - return BAD_STACK_HOOK; -// case INTERNAL_ERROR_BAD_ATTRIBUTES: -// return BAD_ATTRIBUTES; -// case INTERNAL_ERROR_IMPLEMENTATION_KEY_CREATE_INCONSISTENCY: -// return IMPLEMENTATION_KEY_CREATE_INCONSISTENCY; -// case INTERNAL_ERROR_IMPLEMENTATION_BLOCKING_OPERATION_CANCEL: -// return IMPLEMENTATION_BLOCKING_OPERATION_CANCEL; -// case INTERNAL_ERROR_MUTEX_OBTAIN_FROM_BAD_STATE: -// return MUTEX_OBTAIN_FROM_BAD_STATE; -// case INTERNAL_ERROR_UNLIMITED_AND_MAXIMUM_IS_0: -// return UNLIMITED_AND_MAXIMUM_IS_0; - default: - return HasReturnvaluesIF::RETURN_FAILED; - } -} - -InternalErrorCodes::InternalErrorCodes() { -} - -InternalErrorCodes::~InternalErrorCodes() { - -} - +#include "../../osal/InternalErrorCodes.h" +#include + +ReturnValue_t InternalErrorCodes::translate(uint8_t code) { + switch (code) { + //TODO It looks like RTEMS-5 does not provide the same error codes +// case INTERNAL_ERROR_NO_CONFIGURATION_TABLE: +// return NO_CONFIGURATION_TABLE; +// case INTERNAL_ERROR_NO_CPU_TABLE: +// return NO_CPU_TABLE; +// case INTERNAL_ERROR_INVALID_WORKSPACE_ADDRESS: +// return INVALID_WORKSPACE_ADDRESS; + case INTERNAL_ERROR_TOO_LITTLE_WORKSPACE: + return TOO_LITTLE_WORKSPACE; + case INTERNAL_ERROR_WORKSPACE_ALLOCATION: + return WORKSPACE_ALLOCATION; +// case INTERNAL_ERROR_INTERRUPT_STACK_TOO_SMALL: +// return INTERRUPT_STACK_TOO_SMALL; + case INTERNAL_ERROR_THREAD_EXITTED: + return THREAD_EXITTED; + case INTERNAL_ERROR_INCONSISTENT_MP_INFORMATION: + return INCONSISTENT_MP_INFORMATION; + case INTERNAL_ERROR_INVALID_NODE: + return INVALID_NODE; + case INTERNAL_ERROR_NO_MPCI: + return NO_MPCI; + case INTERNAL_ERROR_BAD_PACKET: + return BAD_PACKET; + case INTERNAL_ERROR_OUT_OF_PACKETS: + return OUT_OF_PACKETS; + case INTERNAL_ERROR_OUT_OF_GLOBAL_OBJECTS: + return OUT_OF_GLOBAL_OBJECTS; + case INTERNAL_ERROR_OUT_OF_PROXIES: + return OUT_OF_PROXIES; + case INTERNAL_ERROR_INVALID_GLOBAL_ID: + return INVALID_GLOBAL_ID; + case INTERNAL_ERROR_BAD_STACK_HOOK: + return BAD_STACK_HOOK; +// case INTERNAL_ERROR_BAD_ATTRIBUTES: +// return BAD_ATTRIBUTES; +// case INTERNAL_ERROR_IMPLEMENTATION_KEY_CREATE_INCONSISTENCY: +// return IMPLEMENTATION_KEY_CREATE_INCONSISTENCY; +// case INTERNAL_ERROR_IMPLEMENTATION_BLOCKING_OPERATION_CANCEL: +// return IMPLEMENTATION_BLOCKING_OPERATION_CANCEL; +// case INTERNAL_ERROR_MUTEX_OBTAIN_FROM_BAD_STATE: +// return MUTEX_OBTAIN_FROM_BAD_STATE; +// case INTERNAL_ERROR_UNLIMITED_AND_MAXIMUM_IS_0: +// return UNLIMITED_AND_MAXIMUM_IS_0; + default: + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +InternalErrorCodes::InternalErrorCodes() { +} + +InternalErrorCodes::~InternalErrorCodes() { + +} + diff --git a/osal/rtems/Interrupt.h b/osal/rtems/Interrupt.h index c4c21911..076a6704 100644 --- a/osal/rtems/Interrupt.h +++ b/osal/rtems/Interrupt.h @@ -1,50 +1,50 @@ -#ifndef OS_RTEMS_INTERRUPT_H_ -#define OS_RTEMS_INTERRUPT_H_ - -#include -#include -#include - -typedef rtems_isr_entry IsrHandler_t; -typedef rtems_isr IsrReturn_t; -typedef rtems_vector_number InterruptNumber_t; - -class Interrupt { -public: - virtual ~Interrupt(){}; - - /** - * Establishes a new interrupt service routine. - * @param handler The service routine to establish - * @param interrupt The interrupt (NOT trap type) the routine shall react to. - * @return RETURN_OK on success. Otherwise, the OS failure code is returned. - */ - static ReturnValue_t setInterruptServiceRoutine(IsrHandler_t handler, - InterruptNumber_t interrupt, IsrHandler_t *oldHandler = NULL); - static ReturnValue_t enableInterrupt(InterruptNumber_t interruptNumber); - static ReturnValue_t disableInterrupt(InterruptNumber_t interruptNumber); - /** - * Enables the interrupt given. - * The function tests, if the InterruptMask register was written successfully. - * @param interrupt The interrupt to enable. - * @return RETURN_OK if the interrupt was set successfully. RETURN_FAILED else. - */ - static ReturnValue_t enableGpioInterrupt(InterruptNumber_t interrupt); - /** - * Disables the interrupt given. - * @param interrupt The interrupt to disable. - * @return RETURN_OK if the interrupt was set successfully. RETURN_FAILED else. - */ - static ReturnValue_t disableGpioInterrupt(InterruptNumber_t interrupt); - - - /** - * Checks if the current executing context is an ISR. - * @return true if handling an interrupt, false else. - */ - static bool isInterruptInProgress(); - -}; - - -#endif /* OS_RTEMS_INTERRUPT_H_ */ +#ifndef OS_RTEMS_INTERRUPT_H_ +#define OS_RTEMS_INTERRUPT_H_ + +#include "../../returnvalues/HasReturnvaluesIF.h" +#include +#include + +typedef rtems_isr_entry IsrHandler_t; +typedef rtems_isr IsrReturn_t; +typedef rtems_vector_number InterruptNumber_t; + +class Interrupt { +public: + virtual ~Interrupt(){}; + + /** + * Establishes a new interrupt service routine. + * @param handler The service routine to establish + * @param interrupt The interrupt (NOT trap type) the routine shall react to. + * @return RETURN_OK on success. Otherwise, the OS failure code is returned. + */ + static ReturnValue_t setInterruptServiceRoutine(IsrHandler_t handler, + InterruptNumber_t interrupt, IsrHandler_t *oldHandler = NULL); + static ReturnValue_t enableInterrupt(InterruptNumber_t interruptNumber); + static ReturnValue_t disableInterrupt(InterruptNumber_t interruptNumber); + /** + * Enables the interrupt given. + * The function tests, if the InterruptMask register was written successfully. + * @param interrupt The interrupt to enable. + * @return RETURN_OK if the interrupt was set successfully. RETURN_FAILED else. + */ + static ReturnValue_t enableGpioInterrupt(InterruptNumber_t interrupt); + /** + * Disables the interrupt given. + * @param interrupt The interrupt to disable. + * @return RETURN_OK if the interrupt was set successfully. RETURN_FAILED else. + */ + static ReturnValue_t disableGpioInterrupt(InterruptNumber_t interrupt); + + + /** + * Checks if the current executing context is an ISR. + * @return true if handling an interrupt, false else. + */ + static bool isInterruptInProgress(); + +}; + + +#endif /* OS_RTEMS_INTERRUPT_H_ */ diff --git a/osal/rtems/MessageQueue.cpp b/osal/rtems/MessageQueue.cpp index de148fdc..e0752409 100644 --- a/osal/rtems/MessageQueue.cpp +++ b/osal/rtems/MessageQueue.cpp @@ -1,147 +1,147 @@ -#include -#include "MessageQueue.h" -#include "RtemsBasic.h" -#include -MessageQueue::MessageQueue(size_t message_depth, size_t max_message_size) : - id(0), lastPartner(0), defaultDestination(NO_QUEUE), internalErrorReporter(NULL) { - rtems_name name = ('Q' << 24) + (queueCounter++ << 8); - rtems_status_code status = rtems_message_queue_create(name, message_depth, - max_message_size, 0, &(this->id)); - if (status != RTEMS_SUCCESSFUL) { - error << "MessageQueue::MessageQueue: Creating Queue " << std::hex - << name << std::dec << " failed with status:" - << (uint32_t) status << std::endl; - this->id = 0; - } -} - -MessageQueue::~MessageQueue() { - rtems_message_queue_delete(id); -} - -ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, - MessageQueueMessage* message, bool ignoreFault) { - return sendMessageFrom(sendTo, message, this->getId(), ignoreFault); -} - -ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessage* message) { - return sendToDefaultFrom(message, this->getId()); -} - -ReturnValue_t MessageQueue::reply(MessageQueueMessage* message) { - if (this->lastPartner != 0) { - return sendMessage(this->lastPartner, message, this->getId()); - } else { - return NO_REPLY_PARTNER; - } -} - -ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message, - MessageQueueId_t* receivedFrom) { - ReturnValue_t status = this->receiveMessage(message); - *receivedFrom = this->lastPartner; - return status; -} - -ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message) { - rtems_status_code status = rtems_message_queue_receive(id, - message->getBuffer(), &(message->messageSize), - RTEMS_NO_WAIT, 1); - if (status == RTEMS_SUCCESSFUL) { - this->lastPartner = message->getSender(); - //Check size of incoming message. - if (message->messageSize < message->getMinimumMessageSize()) { - return HasReturnvaluesIF::RETURN_FAILED; - } - } else { - //No message was received. Keep lastPartner anyway, I might send something later. - //But still, delete packet content. - memset(message->getData(), 0, message->MAX_DATA_SIZE); - } - return convertReturnCode(status); -} - -MessageQueueId_t MessageQueue::getLastPartner() const { - return this->lastPartner; -} - -ReturnValue_t MessageQueue::flush(uint32_t* count) { - rtems_status_code status = rtems_message_queue_flush(id, count); - return convertReturnCode(status); -} - -MessageQueueId_t MessageQueue::getId() const { - return this->id; -} - -void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) { - this->defaultDestination = defaultDestination; -} - -ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, - MessageQueueMessage* message, MessageQueueId_t sentFrom, - bool ignoreFault) { - - message->setSender(sentFrom); - rtems_status_code result = rtems_message_queue_send(sendTo, - message->getBuffer(), message->messageSize); - - //TODO: Check if we're in ISR. - if (result != RTEMS_SUCCESSFUL && !ignoreFault) { - if (internalErrorReporter == NULL) { - internalErrorReporter = objectManager->get( - objects::INTERNAL_ERROR_REPORTER); - } - if (internalErrorReporter != NULL) { - internalErrorReporter->queueMessageNotSent(); - } - } - - ReturnValue_t returnCode = convertReturnCode(result); - if(result == MessageQueueIF::EMPTY){ - return HasReturnvaluesIF::RETURN_FAILED; - } - - return returnCode; -} - -ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessage* message, - MessageQueueId_t sentFrom, bool ignoreFault) { - return sendMessageFrom(defaultDestination, message, sentFrom, ignoreFault); -} - -MessageQueueId_t MessageQueue::getDefaultDestination() const { - return this->defaultDestination; -} - -bool MessageQueue::isDefaultDestinationSet() const { - return (defaultDestination != NO_QUEUE); -} - -ReturnValue_t MessageQueue::convertReturnCode(rtems_status_code inValue){ - switch(inValue){ - case RTEMS_SUCCESSFUL: - return HasReturnvaluesIF::RETURN_OK; - case RTEMS_INVALID_ID: - return HasReturnvaluesIF::RETURN_FAILED; - case RTEMS_TIMEOUT: - return HasReturnvaluesIF::RETURN_FAILED; - case RTEMS_OBJECT_WAS_DELETED: - return HasReturnvaluesIF::RETURN_FAILED; - case RTEMS_INVALID_ADDRESS: - return HasReturnvaluesIF::RETURN_FAILED; - case RTEMS_INVALID_SIZE: - return HasReturnvaluesIF::RETURN_FAILED; - case RTEMS_TOO_MANY: - return MessageQueueIF::FULL; - case RTEMS_UNSATISFIED: - return MessageQueueIF::EMPTY; - default: - return HasReturnvaluesIF::RETURN_FAILED; - } - -} - - - -uint16_t MessageQueue::queueCounter = 0; +#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "MessageQueue.h" +#include "RtemsBasic.h" +#include +MessageQueue::MessageQueue(size_t message_depth, size_t max_message_size) : + id(0), lastPartner(0), defaultDestination(NO_QUEUE), internalErrorReporter(NULL) { + rtems_name name = ('Q' << 24) + (queueCounter++ << 8); + rtems_status_code status = rtems_message_queue_create(name, message_depth, + max_message_size, 0, &(this->id)); + if (status != RTEMS_SUCCESSFUL) { + error << "MessageQueue::MessageQueue: Creating Queue " << std::hex + << name << std::dec << " failed with status:" + << (uint32_t) status << std::endl; + this->id = 0; + } +} + +MessageQueue::~MessageQueue() { + rtems_message_queue_delete(id); +} + +ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, + MessageQueueMessage* message, bool ignoreFault) { + return sendMessageFrom(sendTo, message, this->getId(), ignoreFault); +} + +ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessage* message) { + return sendToDefaultFrom(message, this->getId()); +} + +ReturnValue_t MessageQueue::reply(MessageQueueMessage* message) { + if (this->lastPartner != 0) { + return sendMessage(this->lastPartner, message, this->getId()); + } else { + return NO_REPLY_PARTNER; + } +} + +ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message, + MessageQueueId_t* receivedFrom) { + ReturnValue_t status = this->receiveMessage(message); + *receivedFrom = this->lastPartner; + return status; +} + +ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message) { + rtems_status_code status = rtems_message_queue_receive(id, + message->getBuffer(), &(message->messageSize), + RTEMS_NO_WAIT, 1); + if (status == RTEMS_SUCCESSFUL) { + this->lastPartner = message->getSender(); + //Check size of incoming message. + if (message->messageSize < message->getMinimumMessageSize()) { + return HasReturnvaluesIF::RETURN_FAILED; + } + } else { + //No message was received. Keep lastPartner anyway, I might send something later. + //But still, delete packet content. + memset(message->getData(), 0, message->MAX_DATA_SIZE); + } + return convertReturnCode(status); +} + +MessageQueueId_t MessageQueue::getLastPartner() const { + return this->lastPartner; +} + +ReturnValue_t MessageQueue::flush(uint32_t* count) { + rtems_status_code status = rtems_message_queue_flush(id, count); + return convertReturnCode(status); +} + +MessageQueueId_t MessageQueue::getId() const { + return this->id; +} + +void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) { + this->defaultDestination = defaultDestination; +} + +ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, + MessageQueueMessage* message, MessageQueueId_t sentFrom, + bool ignoreFault) { + + message->setSender(sentFrom); + rtems_status_code result = rtems_message_queue_send(sendTo, + message->getBuffer(), message->messageSize); + + //TODO: Check if we're in ISR. + if (result != RTEMS_SUCCESSFUL && !ignoreFault) { + if (internalErrorReporter == NULL) { + internalErrorReporter = objectManager->get( + objects::INTERNAL_ERROR_REPORTER); + } + if (internalErrorReporter != NULL) { + internalErrorReporter->queueMessageNotSent(); + } + } + + ReturnValue_t returnCode = convertReturnCode(result); + if(result == MessageQueueIF::EMPTY){ + return HasReturnvaluesIF::RETURN_FAILED; + } + + return returnCode; +} + +ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessage* message, + MessageQueueId_t sentFrom, bool ignoreFault) { + return sendMessageFrom(defaultDestination, message, sentFrom, ignoreFault); +} + +MessageQueueId_t MessageQueue::getDefaultDestination() const { + return this->defaultDestination; +} + +bool MessageQueue::isDefaultDestinationSet() const { + return (defaultDestination != NO_QUEUE); +} + +ReturnValue_t MessageQueue::convertReturnCode(rtems_status_code inValue){ + switch(inValue){ + case RTEMS_SUCCESSFUL: + return HasReturnvaluesIF::RETURN_OK; + case RTEMS_INVALID_ID: + return HasReturnvaluesIF::RETURN_FAILED; + case RTEMS_TIMEOUT: + return HasReturnvaluesIF::RETURN_FAILED; + case RTEMS_OBJECT_WAS_DELETED: + return HasReturnvaluesIF::RETURN_FAILED; + case RTEMS_INVALID_ADDRESS: + return HasReturnvaluesIF::RETURN_FAILED; + case RTEMS_INVALID_SIZE: + return HasReturnvaluesIF::RETURN_FAILED; + case RTEMS_TOO_MANY: + return MessageQueueIF::FULL; + case RTEMS_UNSATISFIED: + return MessageQueueIF::EMPTY; + default: + return HasReturnvaluesIF::RETURN_FAILED; + } + +} + + + +uint16_t MessageQueue::queueCounter = 0; diff --git a/osal/rtems/MessageQueue.h b/osal/rtems/MessageQueue.h index 9bdce7ca..2d1bd8db 100644 --- a/osal/rtems/MessageQueue.h +++ b/osal/rtems/MessageQueue.h @@ -1,181 +1,181 @@ -/** - * @file MessageQueue.h - * - * @date 10/02/2012 - * @author Bastian Baetz - * - * @brief This file contains the definition of the MessageQueue class. - */ - -#ifndef MESSAGEQUEUE_H_ -#define MESSAGEQUEUE_H_ - -#include -#include -#include -#include "RtemsBasic.h" - -/** - * @brief This class manages sending and receiving of message queue messages. - * - * @details Message queues are used to pass asynchronous messages between processes. - * They work like post boxes, where all incoming messages are stored in FIFO - * order. This class creates a new receiving queue and provides methods to fetch - * received messages. Being a child of MessageQueueSender, this class also provides - * methods to send a message to a user-defined or a default destination. In addition - * it also provides a reply method to answer to the queue it received its last message - * from. - * The MessageQueue should be used as "post box" for a single owning object. So all - * message queue communication is "n-to-one". - * For creating the queue, as well as sending and receiving messages, the class makes - * use of the operating system calls provided. - * \ingroup message_queue - */ -class MessageQueue : public MessageQueueIF { -public: - /** - * @brief The constructor initializes and configures the message queue. - * @details By making use of the according operating system call, a message queue is created - * and initialized. The message depth - the maximum number of messages to be - * buffered - may be set with the help of a parameter, whereas the message size is - * automatically set to the maximum message queue message size. The operating system - * sets the message queue id, or i case of failure, it is set to zero. - * @param message_depth The number of messages to be buffered before passing an error to the - * sender. Default is three. - * @param max_message_size With this parameter, the maximum message size can be adjusted. - * This should be left default. - */ - MessageQueue( size_t message_depth = 3, size_t max_message_size = MessageQueueMessage::MAX_MESSAGE_SIZE ); - /** - * @brief The destructor deletes the formerly created message queue. - * @details This is accomplished by using the delete call provided by the operating system. - */ - virtual ~MessageQueue(); - /** - * @brief This operation sends a message to the given destination. - * @details It directly uses the sendMessage call of the MessageQueueSender parent, but passes its - * queue id as "sentFrom" parameter. - * @param sendTo This parameter specifies the message queue id of the destination message queue. - * @param message A pointer to a previously created message, which is sent. - * @param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. - */ - ReturnValue_t sendMessage(MessageQueueId_t sendTo, - MessageQueueMessage* message, bool ignoreFault = false ); - /** - * @brief This operation sends a message to the default destination. - * @details As in the sendMessage method, this function uses the sendToDefault call of the - * MessageQueueSender parent class and adds its queue id as "sentFrom" information. - * @param message A pointer to a previously created message, which is sent. - */ - ReturnValue_t sendToDefault( MessageQueueMessage* message ); - /** - * @brief This operation sends a message to the last communication partner. - * @details This operation simplifies answering an incoming message by using the stored - * lastParnter information as destination. If there was no message received yet - * (i.e. lastPartner is zero), an error code is returned. - * @param message A pointer to a previously created message, which is sent. - */ - ReturnValue_t reply( MessageQueueMessage* message ); - - /** - * @brief This function reads available messages from the message queue and returns the sender. - * @details It works identically to the other receiveMessage call, but in addition returns the - * sender's queue id. - * @param message A pointer to a message in which the received data is stored. - * @param receivedFrom A pointer to a queue id in which the sender's id is stored. - */ - ReturnValue_t receiveMessage(MessageQueueMessage* message, - MessageQueueId_t *receivedFrom); - - /** - * @brief This function reads available messages from the message queue. - * @details If data is available it is stored in the passed message pointer. The message's - * original content is overwritten and the sendFrom information is stored in the - * lastPartner attribute. Else, the lastPartner information remains untouched, the - * message's content is cleared and the function returns immediately. - * @param message A pointer to a message in which the received data is stored. - */ - ReturnValue_t receiveMessage(MessageQueueMessage* message); - /** - * Deletes all pending messages in the queue. - * @param count The number of flushed messages. - * @return RETURN_OK on success. - */ - ReturnValue_t flush(uint32_t* count); - /** - * @brief This method returns the message queue id of the last communication partner. - */ - MessageQueueId_t getLastPartner() const; - /** - * @brief This method returns the message queue id of this class's message queue. - */ - MessageQueueId_t getId() const; - /** - * \brief With the sendMessage call, a queue message is sent to a receiving queue. - * \details This method takes the message provided, adds the sentFrom information and passes - * it on to the destination provided with an operating system call. The OS's return - * value is returned. - * \param sendTo This parameter specifies the message queue id to send the message to. - * \param message This is a pointer to a previously created message, which is sent. - * \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. - * This variable is set to zero by default. - * \param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. - */ - virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo, MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false ); - /** - * \brief The sendToDefault method sends a queue message to the default destination. - * \details In all other aspects, it works identical to the sendMessage method. - * \param message This is a pointer to a previously created message, which is sent. - * \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. - * This variable is set to zero by default. - */ - virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false ); - /** - * \brief This method is a simple setter for the default destination. - */ - void setDefaultDestination(MessageQueueId_t defaultDestination); - /** - * \brief This method is a simple getter for the default destination. - */ - MessageQueueId_t getDefaultDestination() const; - - bool isDefaultDestinationSet() const; -private: - /** - * @brief The class stores the queue id it got assigned from the operating system in this attribute. - * If initialization fails, the queue id is set to zero. - */ - MessageQueueId_t id; - /** - * @brief In this attribute, the queue id of the last communication partner is stored - * to allow for replying. - */ - MessageQueueId_t lastPartner; - /** - * @brief The message queue's name -a user specific information for the operating system- is - * generated automatically with the help of this static counter. - */ - /** - * \brief This attribute stores a default destination to send messages to. - * \details It is stored to simplify sending to always-the-same receiver. The attribute may - * be set in the constructor or by a setter call to setDefaultDestination. - */ - MessageQueueId_t defaultDestination; - - /** - * \brief This attribute stores a reference to the internal error reporter for reporting full queues. - * \details In the event of a full destination queue, the reporter will be notified. The reference is set - * by lazy loading - */ - InternalErrorReporterIF *internalErrorReporter; - - static uint16_t queueCounter; - /** - * A method to convert an OS-specific return code to the frameworks return value concept. - * @param inValue The return code coming from the OS. - * @return The converted return value. - */ - static ReturnValue_t convertReturnCode(rtems_status_code inValue); -}; - -#endif /* MESSAGEQUEUE_H_ */ +/** + * @file MessageQueue.h + * + * @date 10/02/2012 + * @author Bastian Baetz + * + * @brief This file contains the definition of the MessageQueue class. + */ + +#ifndef MESSAGEQUEUE_H_ +#define MESSAGEQUEUE_H_ + +#include "../../internalError/InternalErrorReporterIF.h" +#include "../../ipc/MessageQueueIF.h" +#include "../../ipc/MessageQueueMessage.h" +#include "RtemsBasic.h" + +/** + * @brief This class manages sending and receiving of message queue messages. + * + * @details Message queues are used to pass asynchronous messages between processes. + * They work like post boxes, where all incoming messages are stored in FIFO + * order. This class creates a new receiving queue and provides methods to fetch + * received messages. Being a child of MessageQueueSender, this class also provides + * methods to send a message to a user-defined or a default destination. In addition + * it also provides a reply method to answer to the queue it received its last message + * from. + * The MessageQueue should be used as "post box" for a single owning object. So all + * message queue communication is "n-to-one". + * For creating the queue, as well as sending and receiving messages, the class makes + * use of the operating system calls provided. + * \ingroup message_queue + */ +class MessageQueue : public MessageQueueIF { +public: + /** + * @brief The constructor initializes and configures the message queue. + * @details By making use of the according operating system call, a message queue is created + * and initialized. The message depth - the maximum number of messages to be + * buffered - may be set with the help of a parameter, whereas the message size is + * automatically set to the maximum message queue message size. The operating system + * sets the message queue id, or i case of failure, it is set to zero. + * @param message_depth The number of messages to be buffered before passing an error to the + * sender. Default is three. + * @param max_message_size With this parameter, the maximum message size can be adjusted. + * This should be left default. + */ + MessageQueue( size_t message_depth = 3, size_t max_message_size = MessageQueueMessage::MAX_MESSAGE_SIZE ); + /** + * @brief The destructor deletes the formerly created message queue. + * @details This is accomplished by using the delete call provided by the operating system. + */ + virtual ~MessageQueue(); + /** + * @brief This operation sends a message to the given destination. + * @details It directly uses the sendMessage call of the MessageQueueSender parent, but passes its + * queue id as "sentFrom" parameter. + * @param sendTo This parameter specifies the message queue id of the destination message queue. + * @param message A pointer to a previously created message, which is sent. + * @param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. + */ + ReturnValue_t sendMessage(MessageQueueId_t sendTo, + MessageQueueMessage* message, bool ignoreFault = false ); + /** + * @brief This operation sends a message to the default destination. + * @details As in the sendMessage method, this function uses the sendToDefault call of the + * MessageQueueSender parent class and adds its queue id as "sentFrom" information. + * @param message A pointer to a previously created message, which is sent. + */ + ReturnValue_t sendToDefault( MessageQueueMessage* message ); + /** + * @brief This operation sends a message to the last communication partner. + * @details This operation simplifies answering an incoming message by using the stored + * lastParnter information as destination. If there was no message received yet + * (i.e. lastPartner is zero), an error code is returned. + * @param message A pointer to a previously created message, which is sent. + */ + ReturnValue_t reply( MessageQueueMessage* message ); + + /** + * @brief This function reads available messages from the message queue and returns the sender. + * @details It works identically to the other receiveMessage call, but in addition returns the + * sender's queue id. + * @param message A pointer to a message in which the received data is stored. + * @param receivedFrom A pointer to a queue id in which the sender's id is stored. + */ + ReturnValue_t receiveMessage(MessageQueueMessage* message, + MessageQueueId_t *receivedFrom); + + /** + * @brief This function reads available messages from the message queue. + * @details If data is available it is stored in the passed message pointer. The message's + * original content is overwritten and the sendFrom information is stored in the + * lastPartner attribute. Else, the lastPartner information remains untouched, the + * message's content is cleared and the function returns immediately. + * @param message A pointer to a message in which the received data is stored. + */ + ReturnValue_t receiveMessage(MessageQueueMessage* message); + /** + * Deletes all pending messages in the queue. + * @param count The number of flushed messages. + * @return RETURN_OK on success. + */ + ReturnValue_t flush(uint32_t* count); + /** + * @brief This method returns the message queue id of the last communication partner. + */ + MessageQueueId_t getLastPartner() const; + /** + * @brief This method returns the message queue id of this class's message queue. + */ + MessageQueueId_t getId() const; + /** + * \brief With the sendMessage call, a queue message is sent to a receiving queue. + * \details This method takes the message provided, adds the sentFrom information and passes + * it on to the destination provided with an operating system call. The OS's return + * value is returned. + * \param sendTo This parameter specifies the message queue id to send the message to. + * \param message This is a pointer to a previously created message, which is sent. + * \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. + * This variable is set to zero by default. + * \param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. + */ + virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo, MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false ); + /** + * \brief The sendToDefault method sends a queue message to the default destination. + * \details In all other aspects, it works identical to the sendMessage method. + * \param message This is a pointer to a previously created message, which is sent. + * \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. + * This variable is set to zero by default. + */ + virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false ); + /** + * \brief This method is a simple setter for the default destination. + */ + void setDefaultDestination(MessageQueueId_t defaultDestination); + /** + * \brief This method is a simple getter for the default destination. + */ + MessageQueueId_t getDefaultDestination() const; + + bool isDefaultDestinationSet() const; +private: + /** + * @brief The class stores the queue id it got assigned from the operating system in this attribute. + * If initialization fails, the queue id is set to zero. + */ + MessageQueueId_t id; + /** + * @brief In this attribute, the queue id of the last communication partner is stored + * to allow for replying. + */ + MessageQueueId_t lastPartner; + /** + * @brief The message queue's name -a user specific information for the operating system- is + * generated automatically with the help of this static counter. + */ + /** + * \brief This attribute stores a default destination to send messages to. + * \details It is stored to simplify sending to always-the-same receiver. The attribute may + * be set in the constructor or by a setter call to setDefaultDestination. + */ + MessageQueueId_t defaultDestination; + + /** + * \brief This attribute stores a reference to the internal error reporter for reporting full queues. + * \details In the event of a full destination queue, the reporter will be notified. The reference is set + * by lazy loading + */ + InternalErrorReporterIF *internalErrorReporter; + + static uint16_t queueCounter; + /** + * A method to convert an OS-specific return code to the frameworks return value concept. + * @param inValue The return code coming from the OS. + * @return The converted return value. + */ + static ReturnValue_t convertReturnCode(rtems_status_code inValue); +}; + +#endif /* MESSAGEQUEUE_H_ */ diff --git a/osal/rtems/MultiObjectTask.cpp b/osal/rtems/MultiObjectTask.cpp index 6b9c8c8e..8cec10f7 100644 --- a/osal/rtems/MultiObjectTask.cpp +++ b/osal/rtems/MultiObjectTask.cpp @@ -1,87 +1,87 @@ -/** - * @file MultiObjectTask.cpp - * @brief This file defines the MultiObjectTask class. - * @date 30.01.2014 - * @author baetz - */ - -#include -#include -#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(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) { - error << "ObjectTask::startTask for " << std::hex << this->getId() - << std::dec << " failed." << std::endl; - } - 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); - error << "ObjectTask: " << ptr << " Deadline missed." << std::endl; - if (this->deadlineMissedFunc != NULL) { - this->deadlineMissedFunc(); - } - } - } -} - -ReturnValue_t MultiObjectTask::addComponent(object_id_t object) { - ExecutableObjectIF* newObject = objectManager->get( - object); - if (newObject == NULL) { - return HasReturnvaluesIF::RETURN_FAILED; - } - objectList.push_back(newObject); - ReturnValue_t result = newObject->initializeAfterTaskCreation(); - return result; -} - -uint32_t MultiObjectTask::getPeriodMs() const { - return RtemsBasic::convertTicksToMs(periodTicks); -} +/** + * @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(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) { + error << "ObjectTask::startTask for " << std::hex << this->getId() + << std::dec << " failed." << std::endl; + } + 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); + error << "ObjectTask: " << ptr << " Deadline missed." << std::endl; + if (this->deadlineMissedFunc != NULL) { + this->deadlineMissedFunc(); + } + } + } +} + +ReturnValue_t MultiObjectTask::addComponent(object_id_t object) { + ExecutableObjectIF* newObject = objectManager->get( + object); + if (newObject == NULL) { + return HasReturnvaluesIF::RETURN_FAILED; + } + objectList.push_back(newObject); + ReturnValue_t result = newObject->initializeAfterTaskCreation(); + return result; +} + +uint32_t MultiObjectTask::getPeriodMs() const { + return RtemsBasic::convertTicksToMs(periodTicks); +} diff --git a/osal/rtems/MultiObjectTask.h b/osal/rtems/MultiObjectTask.h index 64b09c52..b3ff66c2 100644 --- a/osal/rtems/MultiObjectTask.h +++ b/osal/rtems/MultiObjectTask.h @@ -1,113 +1,113 @@ -/** - * @file MultiObjectTask.h - * @brief This file defines the MultiObjectTask class. - * @date 30.01.2014 - * @author baetz - */ -#ifndef MULTIOBJECTTASK_H_ -#define MULTIOBJECTTASK_H_ - -#include -#include - -#include "TaskBase.h" -#include - -class ExecutableObjectIF; - -/** - * @brief This class represents a specialized task for periodic activities of multiple objects. - * - * @details MultiObjectTask is an extension to ObjectTask in the way that it is able to execute - * multiple objects that implement the ExecutableObjectIF interface. The objects must be - * added prior to starting the task. - * - * @ingroup task_handling - */ -class MultiObjectTask: public TaskBase, public PeriodicTaskIF { -public: - /** - * @brief Standard constructor of the class. - * @details The class is initialized without allocated objects. These need to be added - * with #addObject. - * In the underlying TaskBase class, a new operating system task is created. - * In addition to the TaskBase parameters, the period, the pointer to the - * aforementioned initialization function and an optional "deadline-missed" - * function pointer is passed. - * @param priority Sets the priority of a task. Values range from a low 0 to a high 99. - * @param stack_size The stack size reserved by the operating system for the task. - * @param setPeriod The length of the period with which the task's functionality will be - * executed. It is expressed in clock ticks. - * @param setDeadlineMissedFunc The function pointer to the deadline missed function - * that shall be assigned. - */ - MultiObjectTask(const char *name, rtems_task_priority setPriority, size_t setStack, rtems_interval setPeriod, - void (*setDeadlineMissedFunc)()); - /** - * @brief Currently, the executed object's lifetime is not coupled with the task object's - * lifetime, so the destructor is empty. - */ - virtual ~MultiObjectTask(void); - - /** - * @brief The method to start the task. - * @details The method starts the task with the respective system call. - * Entry point is the taskEntryPoint method described below. - * The address of the task object is passed as an argument - * to the system call. - */ - ReturnValue_t startTask(void); - /** - * Adds an object to the list of objects to be executed. - * The objects are executed in the order added. - * @param object Id of the object to add. - * @return RETURN_OK on success, RETURN_FAILED if the object could not be added. - */ - ReturnValue_t addComponent(object_id_t object); - - uint32_t getPeriodMs() const; - - ReturnValue_t sleepFor(uint32_t ms); -protected: - typedef std::vector ObjectList; //!< Typedef for the List of objects. - /** - * @brief This attribute holds a list of objects to be executed. - */ - ObjectList objectList; - /** - * @brief The period of the task. - * @details The period determines the frequency of the task's execution. It is expressed in clock ticks. - */ - rtems_interval periodTicks; - /** - * @brief id of the associated OS period - */ - rtems_id periodId; - /** - * @brief The pointer to the deadline-missed function. - * @details This pointer stores the function that is executed if the task's deadline is missed. - * So, each may react individually on a timing failure. The pointer may be NULL, - * then nothing happens on missing the deadline. The deadline is equal to the next execution - * of the periodic task. - */ - void (*deadlineMissedFunc)(void); - /** - * @brief This is the function executed in the new task's context. - * @details It converts the argument back to the thread object type and copies the class instance - * to the task context. The taskFunctionality method is called afterwards. - * @param A pointer to the task object itself is passed as argument. - */ - static rtems_task taskEntryPoint(rtems_task_argument argument); - /** - * @brief The function containing the actual functionality of the task. - * @details The method sets and starts - * the task's period, then enters a loop that is repeated as long as the isRunning - * attribute is true. Within the loop, all performOperation methods of the added - * objects are called. Afterwards the checkAndRestartPeriod system call blocks the task - * until the next period. - * On missing the deadline, the deadlineMissedFunction is executed. - */ - void taskFunctionality(void); -}; - -#endif /* MULTIOBJECTTASK_H_ */ +/** + * @file MultiObjectTask.h + * @brief This file defines the MultiObjectTask class. + * @date 30.01.2014 + * @author baetz + */ +#ifndef MULTIOBJECTTASK_H_ +#define MULTIOBJECTTASK_H_ + +#include "../../objectmanager/ObjectManagerIF.h" +#include "../../tasks/PeriodicTaskIF.h" + +#include "TaskBase.h" +#include + +class ExecutableObjectIF; + +/** + * @brief This class represents a specialized task for periodic activities of multiple objects. + * + * @details MultiObjectTask is an extension to ObjectTask in the way that it is able to execute + * multiple objects that implement the ExecutableObjectIF interface. The objects must be + * added prior to starting the task. + * + * @ingroup task_handling + */ +class MultiObjectTask: public TaskBase, public PeriodicTaskIF { +public: + /** + * @brief Standard constructor of the class. + * @details The class is initialized without allocated objects. These need to be added + * with #addObject. + * In the underlying TaskBase class, a new operating system task is created. + * In addition to the TaskBase parameters, the period, the pointer to the + * aforementioned initialization function and an optional "deadline-missed" + * function pointer is passed. + * @param priority Sets the priority of a task. Values range from a low 0 to a high 99. + * @param stack_size The stack size reserved by the operating system for the task. + * @param setPeriod The length of the period with which the task's functionality will be + * executed. It is expressed in clock ticks. + * @param setDeadlineMissedFunc The function pointer to the deadline missed function + * that shall be assigned. + */ + MultiObjectTask(const char *name, rtems_task_priority setPriority, size_t setStack, rtems_interval setPeriod, + void (*setDeadlineMissedFunc)()); + /** + * @brief Currently, the executed object's lifetime is not coupled with the task object's + * lifetime, so the destructor is empty. + */ + virtual ~MultiObjectTask(void); + + /** + * @brief The method to start the task. + * @details The method starts the task with the respective system call. + * Entry point is the taskEntryPoint method described below. + * The address of the task object is passed as an argument + * to the system call. + */ + ReturnValue_t startTask(void); + /** + * Adds an object to the list of objects to be executed. + * The objects are executed in the order added. + * @param object Id of the object to add. + * @return RETURN_OK on success, RETURN_FAILED if the object could not be added. + */ + ReturnValue_t addComponent(object_id_t object); + + uint32_t getPeriodMs() const; + + ReturnValue_t sleepFor(uint32_t ms); +protected: + typedef std::vector ObjectList; //!< Typedef for the List of objects. + /** + * @brief This attribute holds a list of objects to be executed. + */ + ObjectList objectList; + /** + * @brief The period of the task. + * @details The period determines the frequency of the task's execution. It is expressed in clock ticks. + */ + rtems_interval periodTicks; + /** + * @brief id of the associated OS period + */ + rtems_id periodId; + /** + * @brief The pointer to the deadline-missed function. + * @details This pointer stores the function that is executed if the task's deadline is missed. + * So, each may react individually on a timing failure. The pointer may be NULL, + * then nothing happens on missing the deadline. The deadline is equal to the next execution + * of the periodic task. + */ + void (*deadlineMissedFunc)(void); + /** + * @brief This is the function executed in the new task's context. + * @details It converts the argument back to the thread object type and copies the class instance + * to the task context. The taskFunctionality method is called afterwards. + * @param A pointer to the task object itself is passed as argument. + */ + static rtems_task taskEntryPoint(rtems_task_argument argument); + /** + * @brief The function containing the actual functionality of the task. + * @details The method sets and starts + * the task's period, then enters a loop that is repeated as long as the isRunning + * attribute is true. Within the loop, all performOperation methods of the added + * objects are called. Afterwards the checkAndRestartPeriod system call blocks the task + * until the next period. + * On missing the deadline, the deadlineMissedFunction is executed. + */ + void taskFunctionality(void); +}; + +#endif /* MULTIOBJECTTASK_H_ */ diff --git a/osal/rtems/Mutex.cpp b/osal/rtems/Mutex.cpp index d094e1dc..7ead8851 100644 --- a/osal/rtems/Mutex.cpp +++ b/osal/rtems/Mutex.cpp @@ -1,65 +1,65 @@ -#include "Mutex.h" -#include - -const uint32_t MutexIF::NO_TIMEOUT = RTEMS_NO_TIMEOUT; -uint8_t Mutex::count = 0; - -Mutex::Mutex() : - mutexId(0) { - rtems_name mutexName = ('M' << 24) + ('T' << 16) + ('X' << 8) + count++; - rtems_status_code status = rtems_semaphore_create(mutexName, 1, - RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY, 0, - &mutexId); - if (status != RTEMS_SUCCESSFUL) { - error << "Mutex: creation with name, id " << mutexName << ", " << mutexId - << " failed with " << status << std::endl; - } -} - -Mutex::~Mutex() { - rtems_status_code status = rtems_semaphore_delete(mutexId); - if (status != RTEMS_SUCCESSFUL) { - error << "Mutex: deletion for id " << mutexId - << " failed with " << status << std::endl; - } -} - -ReturnValue_t Mutex::lockMutex(uint32_t timeoutMs) { - rtems_status_code status = rtems_semaphore_obtain(mutexId, RTEMS_WAIT, timeoutMs); - switch(status){ - case RTEMS_SUCCESSFUL: - //semaphore obtained successfully - return HasReturnvaluesIF::RETURN_OK; - case RTEMS_UNSATISFIED: - //semaphore not available - return MUTEX_NOT_FOUND; - case RTEMS_TIMEOUT: - //timed out waiting for semaphore - return MUTEX_TIMEOUT; - case RTEMS_OBJECT_WAS_DELETED: - //semaphore deleted while waiting - return MUTEX_DESTROYED_WHILE_WAITING; - case RTEMS_INVALID_ID: - //invalid semaphore id - return MUTEX_INVALID_ID; - default: - return HasReturnvaluesIF::RETURN_FAILED; - } -} - -ReturnValue_t Mutex::unlockMutex() { - rtems_status_code status = rtems_semaphore_release(mutexId); - switch(status){ - case RTEMS_SUCCESSFUL: - //semaphore obtained successfully - return HasReturnvaluesIF::RETURN_OK; - case RTEMS_NOT_OWNER_OF_RESOURCE: - //semaphore not available - return CURR_THREAD_DOES_NOT_OWN_MUTEX; - case RTEMS_INVALID_ID: - //invalid semaphore id - return MUTEX_INVALID_ID; - default: - return HasReturnvaluesIF::RETURN_FAILED; - } -} +#include "Mutex.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" + +const uint32_t MutexIF::NO_TIMEOUT = RTEMS_NO_TIMEOUT; +uint8_t Mutex::count = 0; + +Mutex::Mutex() : + mutexId(0) { + rtems_name mutexName = ('M' << 24) + ('T' << 16) + ('X' << 8) + count++; + rtems_status_code status = rtems_semaphore_create(mutexName, 1, + RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY, 0, + &mutexId); + if (status != RTEMS_SUCCESSFUL) { + error << "Mutex: creation with name, id " << mutexName << ", " << mutexId + << " failed with " << status << std::endl; + } +} + +Mutex::~Mutex() { + rtems_status_code status = rtems_semaphore_delete(mutexId); + if (status != RTEMS_SUCCESSFUL) { + error << "Mutex: deletion for id " << mutexId + << " failed with " << status << std::endl; + } +} + +ReturnValue_t Mutex::lockMutex(uint32_t timeoutMs) { + rtems_status_code status = rtems_semaphore_obtain(mutexId, RTEMS_WAIT, timeoutMs); + switch(status){ + case RTEMS_SUCCESSFUL: + //semaphore obtained successfully + return HasReturnvaluesIF::RETURN_OK; + case RTEMS_UNSATISFIED: + //semaphore not available + return MUTEX_NOT_FOUND; + case RTEMS_TIMEOUT: + //timed out waiting for semaphore + return MUTEX_TIMEOUT; + case RTEMS_OBJECT_WAS_DELETED: + //semaphore deleted while waiting + return MUTEX_DESTROYED_WHILE_WAITING; + case RTEMS_INVALID_ID: + //invalid semaphore id + return MUTEX_INVALID_ID; + default: + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +ReturnValue_t Mutex::unlockMutex() { + rtems_status_code status = rtems_semaphore_release(mutexId); + switch(status){ + case RTEMS_SUCCESSFUL: + //semaphore obtained successfully + return HasReturnvaluesIF::RETURN_OK; + case RTEMS_NOT_OWNER_OF_RESOURCE: + //semaphore not available + return CURR_THREAD_DOES_NOT_OWN_MUTEX; + case RTEMS_INVALID_ID: + //invalid semaphore id + return MUTEX_INVALID_ID; + default: + return HasReturnvaluesIF::RETURN_FAILED; + } +} diff --git a/osal/rtems/Mutex.h b/osal/rtems/Mutex.h index 19b34e7f..fd76b86a 100644 --- a/osal/rtems/Mutex.h +++ b/osal/rtems/Mutex.h @@ -1,18 +1,18 @@ -#ifndef OS_RTEMS_MUTEX_H_ -#define OS_RTEMS_MUTEX_H_ - -#include -#include "RtemsBasic.h" - -class Mutex : public MutexIF { -public: - Mutex(); - ~Mutex(); - ReturnValue_t lockMutex(uint32_t timeoutMs); - ReturnValue_t unlockMutex(); -private: - rtems_id mutexId; - static uint8_t count; -}; - -#endif /* OS_RTEMS_MUTEX_H_ */ +#ifndef OS_RTEMS_MUTEX_H_ +#define OS_RTEMS_MUTEX_H_ + +#include "../../ipc/MutexIF.h" +#include "RtemsBasic.h" + +class Mutex : public MutexIF { +public: + Mutex(); + ~Mutex(); + ReturnValue_t lockMutex(uint32_t timeoutMs); + ReturnValue_t unlockMutex(); +private: + rtems_id mutexId; + static uint8_t count; +}; + +#endif /* OS_RTEMS_MUTEX_H_ */ diff --git a/osal/rtems/MutexFactory.cpp b/osal/rtems/MutexFactory.cpp index d7bd16bc..3ffab927 100644 --- a/osal/rtems/MutexFactory.cpp +++ b/osal/rtems/MutexFactory.cpp @@ -1,24 +1,24 @@ -#include -#include "Mutex.h" -#include "RtemsBasic.h" - -//TODO: Different variant than the lazy loading in QueueFactory. What's better and why? -MutexFactory* MutexFactory::factoryInstance = new MutexFactory(); - -MutexFactory::MutexFactory() { -} - -MutexFactory::~MutexFactory() { -} - -MutexFactory* MutexFactory::instance() { - return MutexFactory::factoryInstance; -} - -MutexIF* MutexFactory::createMutex() { - return new Mutex(); -} - -void MutexFactory::deleteMutex(MutexIF* mutex) { - delete mutex; -} +#include "../../ipc/MutexFactory.h" +#include "Mutex.h" +#include "RtemsBasic.h" + +//TODO: Different variant than the lazy loading in QueueFactory. What's better and why? +MutexFactory* MutexFactory::factoryInstance = new MutexFactory(); + +MutexFactory::MutexFactory() { +} + +MutexFactory::~MutexFactory() { +} + +MutexFactory* MutexFactory::instance() { + return MutexFactory::factoryInstance; +} + +MutexIF* MutexFactory::createMutex() { + return new Mutex(); +} + +void MutexFactory::deleteMutex(MutexIF* mutex) { + delete mutex; +} diff --git a/osal/rtems/PollingTask.cpp b/osal/rtems/PollingTask.cpp index a6be7ddf..527df367 100644 --- a/osal/rtems/PollingTask.cpp +++ b/osal/rtems/PollingTask.cpp @@ -1,122 +1,122 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -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(argument)); - //The task's functionality is called. - originalTask->taskFunctionality(); - debug << "Polling task " << originalTask->getId() - << " returned from taskFunctionality." << std::endl; -} - -void PollingTask::missedDeadlineCounter() { - PollingTask::deadlineMissedCount++; - if (PollingTask::deadlineMissedCount % 10 == 0) { - error << "PST missed " << PollingTask::deadlineMissedCount - << " deadlines." << std::endl; - } -} - -ReturnValue_t PollingTask::startTask() { - rtems_status_code status = rtems_task_start(id, PollingTask::taskEntryPoint, - rtems_task_argument((void *) this)); - if (status != RTEMS_SUCCESSFUL) { - error << "PollingTask::startTask for " << std::hex << this->getId() - << std::dec << " failed." << std::endl; - } - 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) { - if (objectManager->get(componentId) != nullptr) { - pst.addSlot(componentId, slotTimeMs, executionStep, this); - return HasReturnvaluesIF::RETURN_OK; - } - - sif::error << "Component " << std::hex << componentId << - " not found, not adding it to pst" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; -} - -uint32_t PollingTask::getPeriodMs() const { - return pst.getLengthMs(); -} - -ReturnValue_t PollingTask::checkSequence() const { - return pst.checkSequence(); -} - -#include - -void PollingTask::taskFunctionality() { - // A local iterator for the Polling Sequence Table is created to find the start time for the first entry. - std::list::iterator 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 != NULL) { - 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); -}; +#include "../../tasks/FixedSequenceSlot.h" +#include "../../objectmanager/SystemObjectIF.h" +#include "../../osal/rtems/PollingTask.h" +#include "../../osal/rtems/RtemsBasic.h" +#include "../../returnvalues/HasReturnvaluesIF.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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(argument)); + //The task's functionality is called. + originalTask->taskFunctionality(); + debug << "Polling task " << originalTask->getId() + << " returned from taskFunctionality." << std::endl; +} + +void PollingTask::missedDeadlineCounter() { + PollingTask::deadlineMissedCount++; + if (PollingTask::deadlineMissedCount % 10 == 0) { + error << "PST missed " << PollingTask::deadlineMissedCount + << " deadlines." << std::endl; + } +} + +ReturnValue_t PollingTask::startTask() { + rtems_status_code status = rtems_task_start(id, PollingTask::taskEntryPoint, + rtems_task_argument((void *) this)); + if (status != RTEMS_SUCCESSFUL) { + error << "PollingTask::startTask for " << std::hex << this->getId() + << std::dec << " failed." << std::endl; + } + 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) { + if (objectManager->get(componentId) != nullptr) { + pst.addSlot(componentId, slotTimeMs, executionStep, this); + return HasReturnvaluesIF::RETURN_OK; + } + + sif::error << "Component " << std::hex << componentId << + " not found, not adding it to pst" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; +} + +uint32_t PollingTask::getPeriodMs() const { + return pst.getLengthMs(); +} + +ReturnValue_t PollingTask::checkSequence() const { + return pst.checkSequence(); +} + +#include + +void PollingTask::taskFunctionality() { + // A local iterator for the Polling Sequence Table is created to find the start time for the first entry. + std::list::iterator 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 != NULL) { + 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); +}; diff --git a/osal/rtems/PollingTask.h b/osal/rtems/PollingTask.h index 5bf8cf57..759ed43d 100644 --- a/osal/rtems/PollingTask.h +++ b/osal/rtems/PollingTask.h @@ -1,85 +1,85 @@ -#ifndef POLLINGTASK_H_ -#define POLLINGTASK_H_ - -#include -#include -#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 /* POLLINGTASK_H_ */ +#ifndef POLLINGTASK_H_ +#define 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 /* POLLINGTASK_H_ */ diff --git a/osal/rtems/QueueFactory.cpp b/osal/rtems/QueueFactory.cpp index 8cc9905c..a492d400 100644 --- a/osal/rtems/QueueFactory.cpp +++ b/osal/rtems/QueueFactory.cpp @@ -1,59 +1,59 @@ -#include -#include "MessageQueue.h" -#include "RtemsBasic.h" - -QueueFactory* QueueFactory::factoryInstance = NULL; - - -ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo, - MessageQueueMessage* message, MessageQueueId_t sentFrom,bool ignoreFault) { - //TODO add ignoreFault functionality - message->setSender(sentFrom); - rtems_status_code result = rtems_message_queue_send(sendTo, message->getBuffer(), - message->messageSize); - switch(result){ - case RTEMS_SUCCESSFUL: - //message sent successfully - return HasReturnvaluesIF::RETURN_OK; - case RTEMS_INVALID_ID: - //invalid queue id - return HasReturnvaluesIF::RETURN_FAILED; - case RTEMS_INVALID_SIZE: - // invalid message size - return HasReturnvaluesIF::RETURN_FAILED; - case RTEMS_INVALID_ADDRESS: - //buffer is NULL - return HasReturnvaluesIF::RETURN_FAILED; - case RTEMS_UNSATISFIED: - //out of message buffers - return HasReturnvaluesIF::RETURN_FAILED; - case RTEMS_TOO_MANY: - //queue's limit has been reached - return MessageQueueIF::FULL; - - default: - return HasReturnvaluesIF::RETURN_FAILED; - } -} - -QueueFactory* QueueFactory::instance() { - if (factoryInstance == NULL) { - factoryInstance = new QueueFactory; - } - return factoryInstance; -} - -QueueFactory::QueueFactory() { -} - -QueueFactory::~QueueFactory() { -} - -MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, - size_t maxMessageSize) { - return new MessageQueue(messageDepth, maxMessageSize); -} - -void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { - delete queue; -} +#include "../../ipc/QueueFactory.h" +#include "MessageQueue.h" +#include "RtemsBasic.h" + +QueueFactory* QueueFactory::factoryInstance = NULL; + + +ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo, + MessageQueueMessage* message, MessageQueueId_t sentFrom,bool ignoreFault) { + //TODO add ignoreFault functionality + message->setSender(sentFrom); + rtems_status_code result = rtems_message_queue_send(sendTo, message->getBuffer(), + message->messageSize); + switch(result){ + case RTEMS_SUCCESSFUL: + //message sent successfully + return HasReturnvaluesIF::RETURN_OK; + case RTEMS_INVALID_ID: + //invalid queue id + return HasReturnvaluesIF::RETURN_FAILED; + case RTEMS_INVALID_SIZE: + // invalid message size + return HasReturnvaluesIF::RETURN_FAILED; + case RTEMS_INVALID_ADDRESS: + //buffer is NULL + return HasReturnvaluesIF::RETURN_FAILED; + case RTEMS_UNSATISFIED: + //out of message buffers + return HasReturnvaluesIF::RETURN_FAILED; + case RTEMS_TOO_MANY: + //queue's limit has been reached + return MessageQueueIF::FULL; + + default: + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +QueueFactory* QueueFactory::instance() { + if (factoryInstance == NULL) { + factoryInstance = new QueueFactory; + } + return factoryInstance; +} + +QueueFactory::QueueFactory() { +} + +QueueFactory::~QueueFactory() { +} + +MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, + size_t maxMessageSize) { + return new MessageQueue(messageDepth, maxMessageSize); +} + +void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { + delete queue; +} diff --git a/osal/rtems/RtemsBasic.h b/osal/rtems/RtemsBasic.h index f7ab8614..b9aa33e8 100644 --- a/osal/rtems/RtemsBasic.h +++ b/osal/rtems/RtemsBasic.h @@ -1,25 +1,25 @@ -#ifndef OS_RTEMS_RTEMSBASIC_H_ -#define OS_RTEMS_RTEMSBASIC_H_ - -#include -#include -#include -#include -#include -#include - - -class RtemsBasic { -public: - static rtems_interval convertMsToTicks(uint32_t msIn) { - rtems_interval ticks_per_second = rtems_clock_get_ticks_per_second(); - return (ticks_per_second * msIn) / 1000; - } - - static rtems_interval convertTicksToMs(rtems_interval ticksIn) { - rtems_interval ticks_per_second = rtems_clock_get_ticks_per_second(); - return (ticksIn * 1000) / ticks_per_second; - } -}; - -#endif /* OS_RTEMS_RTEMSBASIC_H_ */ +#ifndef OS_RTEMS_RTEMSBASIC_H_ +#define OS_RTEMS_RTEMSBASIC_H_ + +#include "../../returnvalues/HasReturnvaluesIF.h" +#include +#include +#include +#include +#include + + +class RtemsBasic { +public: + static rtems_interval convertMsToTicks(uint32_t msIn) { + rtems_interval ticks_per_second = rtems_clock_get_ticks_per_second(); + return (ticks_per_second * msIn) / 1000; + } + + static rtems_interval convertTicksToMs(rtems_interval ticksIn) { + rtems_interval ticks_per_second = rtems_clock_get_ticks_per_second(); + return (ticksIn * 1000) / ticks_per_second; + } +}; + +#endif /* OS_RTEMS_RTEMSBASIC_H_ */ diff --git a/osal/rtems/TaskBase.cpp b/osal/rtems/TaskBase.cpp index ad795645..b95ab51f 100644 --- a/osal/rtems/TaskBase.cpp +++ b/osal/rtems/TaskBase.cpp @@ -1,82 +1,82 @@ -#include -#include "TaskBase.h" - -const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE=RTEMS_MINIMUM_STACK_SIZE; - -TaskBase::TaskBase(rtems_task_priority set_priority, size_t stack_size, - const char *name) { - rtems_name osalName = 0; - for (uint8_t i = 0; i < 4; i++) { - if (name[i] == 0) { - break; - } - osalName += name[i] << (8 * (3 - i)); - } - //The task is created with the operating system's system call. - rtems_status_code status = RTEMS_UNSATISFIED; - if (set_priority >= 0 && set_priority <= 99) { - status = rtems_task_create(osalName, - (0xFF - 2 * set_priority), stack_size, - RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR, - RTEMS_FLOATING_POINT, &id); - } - ReturnValue_t result = convertReturnCode(status); - if (result != HasReturnvaluesIF::RETURN_OK) { - error << "TaskBase::TaskBase: createTask with name " << std::hex - << osalName << std::dec << " failed with return code " - << (uint32_t) status << std::endl; - this->id = 0; - } -} - -TaskBase::~TaskBase() { - rtems_task_delete(id); -} - -rtems_id TaskBase::getId() { - return this->id; -} - -ReturnValue_t TaskBase::sleepFor(uint32_t ms) { - rtems_status_code status = rtems_task_wake_after(RtemsBasic::convertMsToTicks(ms)); - return convertReturnCode(status); -} - - -ReturnValue_t TaskBase::convertReturnCode(rtems_status_code inValue) { - switch (inValue) { - case RTEMS_SUCCESSFUL: - return HasReturnvaluesIF::RETURN_OK; - case RTEMS_MP_NOT_CONFIGURED: - return HasReturnvaluesIF::RETURN_FAILED; - case RTEMS_INVALID_NAME: - return HasReturnvaluesIF::RETURN_FAILED; - case RTEMS_TOO_MANY: - return HasReturnvaluesIF::RETURN_FAILED; - case RTEMS_INVALID_ADDRESS: - return HasReturnvaluesIF::RETURN_FAILED; - case RTEMS_UNSATISFIED: - return HasReturnvaluesIF::RETURN_FAILED; - case RTEMS_INVALID_PRIORITY: - return HasReturnvaluesIF::RETURN_FAILED; - default: - return HasReturnvaluesIF::RETURN_FAILED; - } - -} - - -ReturnValue_t TaskBase::setAndStartPeriod(rtems_interval period, rtems_id *periodId) { - rtems_name periodName = (('P' << 24) + ('e' << 16) + ('r' << 8) + 'd'); - rtems_status_code status = rtems_rate_monotonic_create(periodName, periodId); - if (status == RTEMS_SUCCESSFUL) { - status = restartPeriod(period,*periodId); - } - return convertReturnCode(status); -} - -rtems_status_code TaskBase::restartPeriod(rtems_interval period, rtems_id periodId){ - //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); - return status; -} +#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "TaskBase.h" + +const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE=RTEMS_MINIMUM_STACK_SIZE; + +TaskBase::TaskBase(rtems_task_priority set_priority, size_t stack_size, + const char *name) { + rtems_name osalName = 0; + for (uint8_t i = 0; i < 4; i++) { + if (name[i] == 0) { + break; + } + osalName += name[i] << (8 * (3 - i)); + } + //The task is created with the operating system's system call. + rtems_status_code status = RTEMS_UNSATISFIED; + if (set_priority >= 0 && set_priority <= 99) { + status = rtems_task_create(osalName, + (0xFF - 2 * set_priority), stack_size, + RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR, + RTEMS_FLOATING_POINT, &id); + } + ReturnValue_t result = convertReturnCode(status); + if (result != HasReturnvaluesIF::RETURN_OK) { + error << "TaskBase::TaskBase: createTask with name " << std::hex + << osalName << std::dec << " failed with return code " + << (uint32_t) status << std::endl; + this->id = 0; + } +} + +TaskBase::~TaskBase() { + rtems_task_delete(id); +} + +rtems_id TaskBase::getId() { + return this->id; +} + +ReturnValue_t TaskBase::sleepFor(uint32_t ms) { + rtems_status_code status = rtems_task_wake_after(RtemsBasic::convertMsToTicks(ms)); + return convertReturnCode(status); +} + + +ReturnValue_t TaskBase::convertReturnCode(rtems_status_code inValue) { + switch (inValue) { + case RTEMS_SUCCESSFUL: + return HasReturnvaluesIF::RETURN_OK; + case RTEMS_MP_NOT_CONFIGURED: + return HasReturnvaluesIF::RETURN_FAILED; + case RTEMS_INVALID_NAME: + return HasReturnvaluesIF::RETURN_FAILED; + case RTEMS_TOO_MANY: + return HasReturnvaluesIF::RETURN_FAILED; + case RTEMS_INVALID_ADDRESS: + return HasReturnvaluesIF::RETURN_FAILED; + case RTEMS_UNSATISFIED: + return HasReturnvaluesIF::RETURN_FAILED; + case RTEMS_INVALID_PRIORITY: + return HasReturnvaluesIF::RETURN_FAILED; + default: + return HasReturnvaluesIF::RETURN_FAILED; + } + +} + + +ReturnValue_t TaskBase::setAndStartPeriod(rtems_interval period, rtems_id *periodId) { + rtems_name periodName = (('P' << 24) + ('e' << 16) + ('r' << 8) + 'd'); + rtems_status_code status = rtems_rate_monotonic_create(periodName, periodId); + if (status == RTEMS_SUCCESSFUL) { + status = restartPeriod(period,*periodId); + } + return convertReturnCode(status); +} + +rtems_status_code TaskBase::restartPeriod(rtems_interval period, rtems_id periodId){ + //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); + return status; +} diff --git a/osal/rtems/TaskBase.h b/osal/rtems/TaskBase.h index b9c1192a..3010a972 100644 --- a/osal/rtems/TaskBase.h +++ b/osal/rtems/TaskBase.h @@ -1,47 +1,47 @@ -#ifndef TASKBASE_H_ -#define TASKBASE_H_ - -#include "RtemsBasic.h" -#include - -/** - * @brief This is the basic task handling class for rtems. - * - * @details Task creation base class for rtems. - */ -class TaskBase { -protected: - /** - * @brief The class stores the task id it got assigned from the operating system in this attribute. - * If initialization fails, the id is set to zero. - */ - rtems_id id; -public: - /** - * @brief The constructor creates and initializes a task. - * @details This is accomplished by using the operating system call to create a task. The name is - * created automatically with the help od taskCounter. Priority and stack size are - * adjustable, all other attributes are set with default values. - * @param priority Sets the priority of a task. Values range from a low 0 to a high 99. - * @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 - */ - TaskBase( rtems_task_priority priority, size_t stack_size, const char *name); - /** - * @brief In the destructor, the created task is deleted. - */ - virtual ~TaskBase(); - /** - * @brief This method returns the task id of this class. - */ - rtems_id getId(); - - ReturnValue_t sleepFor(uint32_t ms); - static ReturnValue_t setAndStartPeriod(rtems_interval period, rtems_id *periodId); - static rtems_status_code restartPeriod(rtems_interval period, rtems_id periodId); -private: - static ReturnValue_t convertReturnCode(rtems_status_code inValue); -}; - - -#endif /* TASKBASE_H_ */ +#ifndef TASKBASE_H_ +#define TASKBASE_H_ + +#include "RtemsBasic.h" +#include "../../tasks/PeriodicTaskIF.h" + +/** + * @brief This is the basic task handling class for rtems. + * + * @details Task creation base class for rtems. + */ +class TaskBase { +protected: + /** + * @brief The class stores the task id it got assigned from the operating system in this attribute. + * If initialization fails, the id is set to zero. + */ + rtems_id id; +public: + /** + * @brief The constructor creates and initializes a task. + * @details This is accomplished by using the operating system call to create a task. The name is + * created automatically with the help od taskCounter. Priority and stack size are + * adjustable, all other attributes are set with default values. + * @param priority Sets the priority of a task. Values range from a low 0 to a high 99. + * @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 + */ + TaskBase( rtems_task_priority priority, size_t stack_size, const char *name); + /** + * @brief In the destructor, the created task is deleted. + */ + virtual ~TaskBase(); + /** + * @brief This method returns the task id of this class. + */ + rtems_id getId(); + + ReturnValue_t sleepFor(uint32_t ms); + static ReturnValue_t setAndStartPeriod(rtems_interval period, rtems_id *periodId); + static rtems_status_code restartPeriod(rtems_interval period, rtems_id periodId); +private: + static ReturnValue_t convertReturnCode(rtems_status_code inValue); +}; + + +#endif /* TASKBASE_H_ */ diff --git a/osal/rtems/TaskFactory.cpp b/osal/rtems/TaskFactory.cpp index 2bee19c7..f79571f0 100644 --- a/osal/rtems/TaskFactory.cpp +++ b/osal/rtems/TaskFactory.cpp @@ -1,41 +1,41 @@ -#include -#include "MultiObjectTask.h" -#include "PollingTask.h" -#include "InitTask.h" -#include "RtemsBasic.h" -#include - -//TODO: Different variant than the lazy loading in QueueFactory. What's better and why? -TaskFactory* TaskFactory::factoryInstance = new TaskFactory(); - -TaskFactory::~TaskFactory() { -} - -TaskFactory* TaskFactory::instance() { - return TaskFactory::factoryInstance; -} - -PeriodicTaskIF* TaskFactory::createPeriodicTask(TaskName name_,TaskPriority taskPriority_,TaskStackSize stackSize_,TaskPeriod periodInSeconds_,TaskDeadlineMissedFunction deadLineMissedFunction_) { - rtems_interval taskPeriod = periodInSeconds_ * Clock::getTicksPerSecond(); - - return static_cast(new MultiObjectTask(name_,taskPriority_,stackSize_,taskPeriod,deadLineMissedFunction_)); -} - -FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(TaskName name_,TaskPriority taskPriority_,TaskStackSize stackSize_,TaskPeriod periodInSeconds_,TaskDeadlineMissedFunction deadLineMissedFunction_) { - rtems_interval taskPeriod = periodInSeconds_ * Clock::getTicksPerSecond(); - return static_cast(new PollingTask(name_,taskPriority_,stackSize_,taskPeriod,deadLineMissedFunction_)); -} - -ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) { - //TODO not implemented - return HasReturnvaluesIF::RETURN_FAILED; -} - -ReturnValue_t TaskFactory::delayTask(uint32_t delayMs){ - rtems_task_wake_after(RtemsBasic::convertMsToTicks(delayMs)); - //Only return value is "RTEMS_SUCCESSFUL - always successful" so it has been neglected - return HasReturnvaluesIF::RETURN_OK; -} - -TaskFactory::TaskFactory() { -} +#include "../../tasks/TaskFactory.h" +#include "MultiObjectTask.h" +#include "PollingTask.h" +#include "InitTask.h" +#include "RtemsBasic.h" +#include "../../returnvalues/HasReturnvaluesIF.h" + +//TODO: Different variant than the lazy loading in QueueFactory. What's better and why? +TaskFactory* TaskFactory::factoryInstance = new TaskFactory(); + +TaskFactory::~TaskFactory() { +} + +TaskFactory* TaskFactory::instance() { + return TaskFactory::factoryInstance; +} + +PeriodicTaskIF* TaskFactory::createPeriodicTask(TaskName name_,TaskPriority taskPriority_,TaskStackSize stackSize_,TaskPeriod periodInSeconds_,TaskDeadlineMissedFunction deadLineMissedFunction_) { + rtems_interval taskPeriod = periodInSeconds_ * Clock::getTicksPerSecond(); + + return static_cast(new MultiObjectTask(name_,taskPriority_,stackSize_,taskPeriod,deadLineMissedFunction_)); +} + +FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(TaskName name_,TaskPriority taskPriority_,TaskStackSize stackSize_,TaskPeriod periodInSeconds_,TaskDeadlineMissedFunction deadLineMissedFunction_) { + rtems_interval taskPeriod = periodInSeconds_ * Clock::getTicksPerSecond(); + return static_cast(new PollingTask(name_,taskPriority_,stackSize_,taskPeriod,deadLineMissedFunction_)); +} + +ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) { + //TODO not implemented + return HasReturnvaluesIF::RETURN_FAILED; +} + +ReturnValue_t TaskFactory::delayTask(uint32_t delayMs){ + rtems_task_wake_after(RtemsBasic::convertMsToTicks(delayMs)); + //Only return value is "RTEMS_SUCCESSFUL - always successful" so it has been neglected + return HasReturnvaluesIF::RETURN_OK; +} + +TaskFactory::TaskFactory() { +} diff --git a/parameters/HasParametersIF.h b/parameters/HasParametersIF.h index 02f36318..14446e3c 100644 --- a/parameters/HasParametersIF.h +++ b/parameters/HasParametersIF.h @@ -1,67 +1,67 @@ -#ifndef HASPARAMETERSIF_H_ -#define HASPARAMETERSIF_H_ - -#include -#include -#include - -/** Each parameter is identified with a unique parameter ID */ -typedef uint32_t ParameterId_t; - -/** - * @brief This interface is used by components which have modifiable - * parameters, e.g. atittude controllers - * @details - * Each parameter has a unique parameter ID. The first byte of the parameter - * ID is the domain ID which can be used to identify unqiue spacecraft domains - * (e.g. control and sensor domain in the AOCS controller). - * - * The second and third byte represent the matrix ID, which can represent - * a 8-bit row and column number and the last byte... - * - * Yeah, it it matrix ID oder parameter ID now and is index a 16 bit number - * of a 8 bit number now? - */ -class HasParametersIF { -public: - static const uint8_t INTERFACE_ID = CLASS_ID::HAS_PARAMETERS_IF; - static const ReturnValue_t INVALID_MATRIX_ID = MAKE_RETURN_CODE(0x01); - static const ReturnValue_t INVALID_DOMAIN_ID = MAKE_RETURN_CODE(0x02); - static const ReturnValue_t INVALID_VALUE = MAKE_RETURN_CODE(0x03); - static const ReturnValue_t READ_ONLY = MAKE_RETURN_CODE(0x05); - - static uint8_t getDomain(ParameterId_t id) { - return id >> 24; - } - - static uint16_t getMatrixId(ParameterId_t id) { - return id >> 8; - } - - static uint8_t getIndex(ParameterId_t id) { - return id; - } - - static uint32_t getFullParameterId(uint8_t domainId, uint16_t parameterId, - uint8_t index) { - return (domainId << 24) + (parameterId << 8) + index; - } - - virtual ~HasParametersIF() {} - - /** - * Always set parameter before checking newValues! - * - * @param domainId - * @param parameterId - * @param parameterWrapper - * @param newValues - * @param startAtIndex - * @return - */ - virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, - ParameterWrapper *parameterWrapper, - const ParameterWrapper *newValues, uint16_t startAtIndex) = 0; -}; - -#endif /* HASPARAMETERSIF_H_ */ +#ifndef HASPARAMETERSIF_H_ +#define HASPARAMETERSIF_H_ + +#include "../parameters/ParameterWrapper.h" +#include "../returnvalues/HasReturnvaluesIF.h" +#include + +/** Each parameter is identified with a unique parameter ID */ +typedef uint32_t ParameterId_t; + +/** + * @brief This interface is used by components which have modifiable + * parameters, e.g. atittude controllers + * @details + * Each parameter has a unique parameter ID. The first byte of the parameter + * ID is the domain ID which can be used to identify unqiue spacecraft domains + * (e.g. control and sensor domain in the AOCS controller). + * + * The second and third byte represent the matrix ID, which can represent + * a 8-bit row and column number and the last byte... + * + * Yeah, it it matrix ID oder parameter ID now and is index a 16 bit number + * of a 8 bit number now? + */ +class HasParametersIF { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::HAS_PARAMETERS_IF; + static const ReturnValue_t INVALID_MATRIX_ID = MAKE_RETURN_CODE(0x01); + static const ReturnValue_t INVALID_DOMAIN_ID = MAKE_RETURN_CODE(0x02); + static const ReturnValue_t INVALID_VALUE = MAKE_RETURN_CODE(0x03); + static const ReturnValue_t READ_ONLY = MAKE_RETURN_CODE(0x05); + + static uint8_t getDomain(ParameterId_t id) { + return id >> 24; + } + + static uint16_t getMatrixId(ParameterId_t id) { + return id >> 8; + } + + static uint8_t getIndex(ParameterId_t id) { + return id; + } + + static uint32_t getFullParameterId(uint8_t domainId, uint16_t parameterId, + uint8_t index) { + return (domainId << 24) + (parameterId << 8) + index; + } + + virtual ~HasParametersIF() {} + + /** + * Always set parameter before checking newValues! + * + * @param domainId + * @param parameterId + * @param parameterWrapper + * @param newValues + * @param startAtIndex + * @return + */ + virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, + ParameterWrapper *parameterWrapper, + const ParameterWrapper *newValues, uint16_t startAtIndex) = 0; +}; + +#endif /* HASPARAMETERSIF_H_ */ diff --git a/parameters/ParameterHelper.cpp b/parameters/ParameterHelper.cpp index 53f1229f..55633566 100644 --- a/parameters/ParameterHelper.cpp +++ b/parameters/ParameterHelper.cpp @@ -1,132 +1,132 @@ -#include -#include -#include - -ParameterHelper::ParameterHelper(ReceivesParameterMessagesIF* owner) : - owner(owner) {} - -ParameterHelper::~ParameterHelper() { -} - -ReturnValue_t ParameterHelper::handleParameterMessage(CommandMessage *message) { - ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; - switch (message->getCommand()) { - case ParameterMessage::CMD_PARAMETER_DUMP: { - ParameterWrapper description; - uint8_t domain = HasParametersIF::getDomain( - ParameterMessage::getParameterId(message)); - uint16_t parameterId = HasParametersIF::getMatrixId( - ParameterMessage::getParameterId(message)); - result = owner->getParameter(domain, parameterId, - &description, &description, 0); - if (result == HasReturnvaluesIF::RETURN_OK) { - result = sendParameter(message->getSender(), - ParameterMessage::getParameterId(message), &description); - } - } - break; - case ParameterMessage::CMD_PARAMETER_LOAD: { - uint8_t domain = HasParametersIF::getDomain( - ParameterMessage::getParameterId(message)); - uint16_t parameterId = HasParametersIF::getMatrixId( - ParameterMessage::getParameterId(message)); - uint8_t index = HasParametersIF::getIndex( - ParameterMessage::getParameterId(message)); - - const uint8_t *storedStream = nullptr; - size_t storedStreamSize = 0; - result = storage->getData( - ParameterMessage::getStoreId(message), &storedStream, - &storedStreamSize); - if (result != HasReturnvaluesIF::RETURN_OK) { - sif::error << "ParameterHelper::handleParameterMessage: Getting" - " store data failed for load command." << std::endl; - break; - } - - ParameterWrapper streamWrapper; - result = streamWrapper.set(storedStream, storedStreamSize); - if (result != HasReturnvaluesIF::RETURN_OK) { - storage->deleteData(ParameterMessage::getStoreId(message)); - break; - } - - ParameterWrapper ownerWrapper; - result = owner->getParameter(domain, parameterId, &ownerWrapper, - &streamWrapper, index); - if (result != HasReturnvaluesIF::RETURN_OK) { - storage->deleteData(ParameterMessage::getStoreId(message)); - break; - } - - result = ownerWrapper.copyFrom(&streamWrapper, index); - - storage->deleteData(ParameterMessage::getStoreId(message)); - - if (result == HasReturnvaluesIF::RETURN_OK) { - result = sendParameter(message->getSender(), - ParameterMessage::getParameterId(message), &ownerWrapper); - } - } - break; - default: - return HasReturnvaluesIF::RETURN_FAILED; - } - - if (result != HasReturnvaluesIF::RETURN_OK) { - rejectCommand(message->getSender(), result, message->getCommand()); - } - - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t ParameterHelper::sendParameter(MessageQueueId_t to, uint32_t id, - const ParameterWrapper* description) { - size_t serializedSize = description->getSerializedSize(); - - uint8_t *storeElement; - store_address_t address; - - ReturnValue_t result = storage->getFreeElement(&address, serializedSize, - &storeElement); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - size_t storeElementSize = 0; - - result = description->serialize(&storeElement, &storeElementSize, - serializedSize, SerializeIF::Endianness::BIG); - - if (result != HasReturnvaluesIF::RETURN_OK) { - storage->deleteData(address); - return result; - } - - CommandMessage reply; - - ParameterMessage::setParameterDumpReply(&reply, id, address); - - MessageQueueSenderIF::sendMessage(to, &reply, ownerQueueId); - - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t ParameterHelper::initialize() { - ownerQueueId = owner->getCommandQueue(); - - - storage = objectManager->get(objects::IPC_STORE); - if (storage == NULL) { - return HasReturnvaluesIF::RETURN_FAILED; - } else { - return HasReturnvaluesIF::RETURN_OK; - } -} - -void ParameterHelper::rejectCommand(MessageQueueId_t to, ReturnValue_t reason, - Command_t initialCommand) { - CommandMessage reply; - reply.setReplyRejected(reason, initialCommand); - MessageQueueSenderIF::sendMessage(to, &reply, ownerQueueId); -} +#include "../objectmanager/ObjectManagerIF.h" +#include "../parameters/ParameterHelper.h" +#include "../parameters/ParameterMessage.h" + +ParameterHelper::ParameterHelper(ReceivesParameterMessagesIF* owner) : + owner(owner) {} + +ParameterHelper::~ParameterHelper() { +} + +ReturnValue_t ParameterHelper::handleParameterMessage(CommandMessage *message) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; + switch (message->getCommand()) { + case ParameterMessage::CMD_PARAMETER_DUMP: { + ParameterWrapper description; + uint8_t domain = HasParametersIF::getDomain( + ParameterMessage::getParameterId(message)); + uint16_t parameterId = HasParametersIF::getMatrixId( + ParameterMessage::getParameterId(message)); + result = owner->getParameter(domain, parameterId, + &description, &description, 0); + if (result == HasReturnvaluesIF::RETURN_OK) { + result = sendParameter(message->getSender(), + ParameterMessage::getParameterId(message), &description); + } + } + break; + case ParameterMessage::CMD_PARAMETER_LOAD: { + uint8_t domain = HasParametersIF::getDomain( + ParameterMessage::getParameterId(message)); + uint16_t parameterId = HasParametersIF::getMatrixId( + ParameterMessage::getParameterId(message)); + uint8_t index = HasParametersIF::getIndex( + ParameterMessage::getParameterId(message)); + + const uint8_t *storedStream = nullptr; + size_t storedStreamSize = 0; + result = storage->getData( + ParameterMessage::getStoreId(message), &storedStream, + &storedStreamSize); + if (result != HasReturnvaluesIF::RETURN_OK) { + sif::error << "ParameterHelper::handleParameterMessage: Getting" + " store data failed for load command." << std::endl; + break; + } + + ParameterWrapper streamWrapper; + result = streamWrapper.set(storedStream, storedStreamSize); + if (result != HasReturnvaluesIF::RETURN_OK) { + storage->deleteData(ParameterMessage::getStoreId(message)); + break; + } + + ParameterWrapper ownerWrapper; + result = owner->getParameter(domain, parameterId, &ownerWrapper, + &streamWrapper, index); + if (result != HasReturnvaluesIF::RETURN_OK) { + storage->deleteData(ParameterMessage::getStoreId(message)); + break; + } + + result = ownerWrapper.copyFrom(&streamWrapper, index); + + storage->deleteData(ParameterMessage::getStoreId(message)); + + if (result == HasReturnvaluesIF::RETURN_OK) { + result = sendParameter(message->getSender(), + ParameterMessage::getParameterId(message), &ownerWrapper); + } + } + break; + default: + return HasReturnvaluesIF::RETURN_FAILED; + } + + if (result != HasReturnvaluesIF::RETURN_OK) { + rejectCommand(message->getSender(), result, message->getCommand()); + } + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t ParameterHelper::sendParameter(MessageQueueId_t to, uint32_t id, + const ParameterWrapper* description) { + size_t serializedSize = description->getSerializedSize(); + + uint8_t *storeElement; + store_address_t address; + + ReturnValue_t result = storage->getFreeElement(&address, serializedSize, + &storeElement); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + size_t storeElementSize = 0; + + result = description->serialize(&storeElement, &storeElementSize, + serializedSize, SerializeIF::Endianness::BIG); + + if (result != HasReturnvaluesIF::RETURN_OK) { + storage->deleteData(address); + return result; + } + + CommandMessage reply; + + ParameterMessage::setParameterDumpReply(&reply, id, address); + + MessageQueueSenderIF::sendMessage(to, &reply, ownerQueueId); + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t ParameterHelper::initialize() { + ownerQueueId = owner->getCommandQueue(); + + + storage = objectManager->get(objects::IPC_STORE); + if (storage == NULL) { + return HasReturnvaluesIF::RETURN_FAILED; + } else { + return HasReturnvaluesIF::RETURN_OK; + } +} + +void ParameterHelper::rejectCommand(MessageQueueId_t to, ReturnValue_t reason, + Command_t initialCommand) { + CommandMessage reply; + reply.setReplyRejected(reason, initialCommand); + MessageQueueSenderIF::sendMessage(to, &reply, ownerQueueId); +} diff --git a/parameters/ParameterHelper.h b/parameters/ParameterHelper.h index 538aaac6..668bb081 100644 --- a/parameters/ParameterHelper.h +++ b/parameters/ParameterHelper.h @@ -1,36 +1,36 @@ -#ifndef FRAMEWORK_PARAMETERS_PARAMETERHELPER_H_ -#define FRAMEWORK_PARAMETERS_PARAMETERHELPER_H_ - -#include -#include -#include - -/** - * @brief Helper class to handle parameter messages - * @details - * This class simplfiies handling of parameter messages, which are sent - * to a class which implements ReceivesParameterMessagesIF. - */ -class ParameterHelper { -public: - ParameterHelper(ReceivesParameterMessagesIF *owner); - virtual ~ParameterHelper(); - - ReturnValue_t handleParameterMessage(CommandMessage *message); - - ReturnValue_t initialize(); -private: - ReceivesParameterMessagesIF *owner; - - MessageQueueId_t ownerQueueId = MessageQueueIF::NO_QUEUE; - - StorageManagerIF *storage = nullptr; - - ReturnValue_t sendParameter(MessageQueueId_t to, uint32_t id, - const ParameterWrapper *description); - - void rejectCommand(MessageQueueId_t to, ReturnValue_t reason, - Command_t initialCommand); -}; - -#endif /* PARAMETERHELPER_H_ */ +#ifndef FRAMEWORK_PARAMETERS_PARAMETERHELPER_H_ +#define FRAMEWORK_PARAMETERS_PARAMETERHELPER_H_ + +#include "../ipc/MessageQueueIF.h" +#include "../parameters/ParameterMessage.h" +#include "../parameters/ReceivesParameterMessagesIF.h" + +/** + * @brief Helper class to handle parameter messages + * @details + * This class simplfiies handling of parameter messages, which are sent + * to a class which implements ReceivesParameterMessagesIF. + */ +class ParameterHelper { +public: + ParameterHelper(ReceivesParameterMessagesIF *owner); + virtual ~ParameterHelper(); + + ReturnValue_t handleParameterMessage(CommandMessage *message); + + ReturnValue_t initialize(); +private: + ReceivesParameterMessagesIF *owner; + + MessageQueueId_t ownerQueueId = MessageQueueIF::NO_QUEUE; + + StorageManagerIF *storage = nullptr; + + ReturnValue_t sendParameter(MessageQueueId_t to, uint32_t id, + const ParameterWrapper *description); + + void rejectCommand(MessageQueueId_t to, ReturnValue_t reason, + Command_t initialCommand); +}; + +#endif /* PARAMETERHELPER_H_ */ diff --git a/parameters/ParameterMessage.cpp b/parameters/ParameterMessage.cpp index 1c7d6911..0cc4dd90 100644 --- a/parameters/ParameterMessage.cpp +++ b/parameters/ParameterMessage.cpp @@ -1,48 +1,48 @@ -#include -#include - -ParameterId_t ParameterMessage::getParameterId(const CommandMessage* message) { - return message->getParameter(); -} - -store_address_t ParameterMessage::getStoreId(const CommandMessage* message) { - store_address_t address; - address.raw = message->getParameter2(); - return address; -} - -void ParameterMessage::setParameterDumpCommand(CommandMessage* message, - ParameterId_t id) { - message->setCommand(CMD_PARAMETER_DUMP); - message->setParameter(id); -} - -void ParameterMessage::setParameterDumpReply(CommandMessage* message, - ParameterId_t id, store_address_t storageID) { - message->setCommand(REPLY_PARAMETER_DUMP); - message->setParameter(id); - message->setParameter2(storageID.raw); -} - -void ParameterMessage::setParameterLoadCommand(CommandMessage* message, - ParameterId_t id, store_address_t storageID) { - message->setCommand(CMD_PARAMETER_LOAD); - message->setParameter(id); - message->setParameter2(storageID.raw); -} - -void ParameterMessage::clear(CommandMessage* message) { - switch (message->getCommand()) { - case CMD_PARAMETER_LOAD: - case REPLY_PARAMETER_DUMP: { - StorageManagerIF *ipcStore = objectManager->get( - objects::IPC_STORE); - if (ipcStore != NULL) { - ipcStore->deleteData(getStoreId(message)); - } - break; - } - default: - break; - } -} +#include "../parameters/ParameterMessage.h" +#include "../objectmanager/ObjectManagerIF.h" + +ParameterId_t ParameterMessage::getParameterId(const CommandMessage* message) { + return message->getParameter(); +} + +store_address_t ParameterMessage::getStoreId(const CommandMessage* message) { + store_address_t address; + address.raw = message->getParameter2(); + return address; +} + +void ParameterMessage::setParameterDumpCommand(CommandMessage* message, + ParameterId_t id) { + message->setCommand(CMD_PARAMETER_DUMP); + message->setParameter(id); +} + +void ParameterMessage::setParameterDumpReply(CommandMessage* message, + ParameterId_t id, store_address_t storageID) { + message->setCommand(REPLY_PARAMETER_DUMP); + message->setParameter(id); + message->setParameter2(storageID.raw); +} + +void ParameterMessage::setParameterLoadCommand(CommandMessage* message, + ParameterId_t id, store_address_t storageID) { + message->setCommand(CMD_PARAMETER_LOAD); + message->setParameter(id); + message->setParameter2(storageID.raw); +} + +void ParameterMessage::clear(CommandMessage* message) { + switch (message->getCommand()) { + case CMD_PARAMETER_LOAD: + case REPLY_PARAMETER_DUMP: { + StorageManagerIF *ipcStore = objectManager->get( + objects::IPC_STORE); + if (ipcStore != NULL) { + ipcStore->deleteData(getStoreId(message)); + } + break; + } + default: + break; + } +} diff --git a/parameters/ParameterMessage.h b/parameters/ParameterMessage.h index 43283294..51321f2b 100644 --- a/parameters/ParameterMessage.h +++ b/parameters/ParameterMessage.h @@ -1,29 +1,29 @@ -#ifndef PARAMETERMESSAGE_H_ -#define PARAMETERMESSAGE_H_ - -#include -#include -#include - -class ParameterMessage { -private: - ParameterMessage(); -public: - static const uint8_t MESSAGE_ID = messagetypes::PARAMETER; - static const Command_t CMD_PARAMETER_LOAD = MAKE_COMMAND_ID( 0x01 ); - static const Command_t CMD_PARAMETER_DUMP = MAKE_COMMAND_ID( 0x02 ); - static const Command_t REPLY_PARAMETER_DUMP = MAKE_COMMAND_ID( 0x03 ); - - static ParameterId_t getParameterId(const CommandMessage* message); - static store_address_t getStoreId(const CommandMessage* message); - static void setParameterDumpCommand(CommandMessage* message, - ParameterId_t id); - static void setParameterDumpReply(CommandMessage* message, - ParameterId_t id, store_address_t storageID); - static void setParameterLoadCommand(CommandMessage* message, - ParameterId_t id, store_address_t storageID); - static void clear(CommandMessage* message); - -}; - -#endif /* PARAMETERMESSAGE_H_ */ +#ifndef PARAMETERMESSAGE_H_ +#define PARAMETERMESSAGE_H_ + +#include "../ipc/CommandMessage.h" +#include "../parameters/HasParametersIF.h" +#include "../storagemanager/StorageManagerIF.h" + +class ParameterMessage { +private: + ParameterMessage(); +public: + static const uint8_t MESSAGE_ID = messagetypes::PARAMETER; + static const Command_t CMD_PARAMETER_LOAD = MAKE_COMMAND_ID( 0x01 ); + static const Command_t CMD_PARAMETER_DUMP = MAKE_COMMAND_ID( 0x02 ); + static const Command_t REPLY_PARAMETER_DUMP = MAKE_COMMAND_ID( 0x03 ); + + static ParameterId_t getParameterId(const CommandMessage* message); + static store_address_t getStoreId(const CommandMessage* message); + static void setParameterDumpCommand(CommandMessage* message, + ParameterId_t id); + static void setParameterDumpReply(CommandMessage* message, + ParameterId_t id, store_address_t storageID); + static void setParameterLoadCommand(CommandMessage* message, + ParameterId_t id, store_address_t storageID); + static void clear(CommandMessage* message); + +}; + +#endif /* PARAMETERMESSAGE_H_ */ diff --git a/parameters/ParameterWrapper.cpp b/parameters/ParameterWrapper.cpp index 521a6644..8e6dd86c 100644 --- a/parameters/ParameterWrapper.cpp +++ b/parameters/ParameterWrapper.cpp @@ -1,280 +1,280 @@ -#include - -ParameterWrapper::ParameterWrapper() : - pointsToStream(false), type(Type::UNKNOWN_TYPE) { -} - -ParameterWrapper::ParameterWrapper(Type type, uint8_t rows, uint8_t columns, - void *data) : - pointsToStream(false), type(type), rows(rows), columns(columns), - data(data), readonlyData(data) { -} - -ParameterWrapper::ParameterWrapper(Type type, uint8_t rows, uint8_t columns, - const void *data) : - pointsToStream(false), type(type), rows(rows), columns(columns), - data(nullptr), readonlyData(data) { -} - -ParameterWrapper::~ParameterWrapper() { -} - -ReturnValue_t ParameterWrapper::serialize(uint8_t **buffer, size_t *size, - size_t maxSize, Endianness streamEndianness) const { - ReturnValue_t result; - - result = SerializeAdapter::serialize(&type, buffer, size, maxSize, - streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - result = SerializeAdapter::serialize(&columns, buffer, size, maxSize, - streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - result = SerializeAdapter::serialize(&rows, buffer, size, maxSize, - streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - //serialize uses readonlyData, as it is always valid - if (readonlyData == NULL) { - return NOT_SET; - } - switch (type) { - case Type::UINT8_T: - result = serializeData(buffer, size, maxSize, - streamEndianness); - break; - case Type::INT8_T: - result = serializeData(buffer, size, maxSize, streamEndianness); - break; - case Type::UINT16_T: - result = serializeData(buffer, size, maxSize, - streamEndianness); - break; - case Type::INT16_T: - result = serializeData(buffer, size, maxSize, - streamEndianness); - break; - case Type::UINT32_T: - result = serializeData(buffer, size, maxSize, - streamEndianness); - break; - case Type::INT32_T: - result = serializeData(buffer, size, maxSize, - streamEndianness); - break; - case Type::FLOAT: - result = serializeData(buffer, size, maxSize, streamEndianness); - break; - case Type::DOUBLE: - result = serializeData(buffer, size, maxSize, streamEndianness); - break; - default: - result = UNKNOW_DATATYPE; - break; - } - return result; -} - -size_t ParameterWrapper::getSerializedSize() const { - uint32_t serializedSize = 0; - serializedSize += type.getSerializedSize(); - serializedSize += sizeof(rows); - serializedSize += sizeof(columns); - serializedSize += rows * columns * type.getSize(); - - return serializedSize; -} - -template -ReturnValue_t ParameterWrapper::serializeData(uint8_t **buffer, size_t *size, - size_t maxSize, Endianness streamEndianness) const { - const T *element = (const T*) readonlyData; - ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; - uint16_t dataSize = columns * rows; - while (dataSize != 0) { - result = SerializeAdapter::serialize(element, buffer, size, maxSize, - streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - element++; - dataSize--; - } - return result; -} - -template -ReturnValue_t ParameterWrapper::deSerializeData(uint8_t startingRow, - uint8_t startingColumn, const void *from, uint8_t fromRows, - uint8_t fromColumns) { - - //treat from as a continuous Stream as we copy all of it - const uint8_t *fromAsStream = (const uint8_t*) from; - size_t streamSize = fromRows * fromColumns * sizeof(T); - - ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; - - for (uint8_t fromRow = 0; fromRow < fromRows; fromRow++) { - - //get the start element of this row in data - T *dataWithDataType = ((T*) data) - + (((startingRow + fromRow) * columns) + startingColumn); - - for (uint8_t fromColumn = 0; fromColumn < fromColumns; fromColumn++) { - result = SerializeAdapter::deSerialize( - dataWithDataType + fromColumn, &fromAsStream, &streamSize, - SerializeIF::Endianness::BIG); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - } - } - - return result; - -} - - -ReturnValue_t ParameterWrapper::deSerialize(const uint8_t **buffer, - size_t *size, Endianness streamEndianness) { - return deSerialize(buffer, size, streamEndianness, 0); -} - -ReturnValue_t ParameterWrapper::deSerialize(const uint8_t **buffer, - size_t *size, Endianness streamEndianness, - uint16_t startWritingAtIndex) { - ParameterWrapper streamDescription; - - ReturnValue_t result = streamDescription.set(*buffer, *size, buffer, size); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - return copyFrom(&streamDescription, startWritingAtIndex); -} - -ReturnValue_t ParameterWrapper::set(const uint8_t *stream, size_t streamSize, - const uint8_t **remainingStream, size_t *remainingSize) { - ReturnValue_t result = SerializeAdapter::deSerialize(&type, &stream, - &streamSize, SerializeIF::Endianness::BIG); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - result = SerializeAdapter::deSerialize(&columns, &stream, &streamSize, - SerializeIF::Endianness::BIG); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - result = SerializeAdapter::deSerialize(&rows, &stream, &streamSize, - SerializeIF::Endianness::BIG); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - size_t dataSize = type.getSize() * rows * columns; - - if (streamSize < dataSize) { - return SerializeIF::STREAM_TOO_SHORT; - } - - data = nullptr; - readonlyData = stream; - pointsToStream = true; - - stream += dataSize; - if (remainingStream != nullptr) { - *remainingStream = stream; - } - streamSize -= dataSize; - if (remainingSize != nullptr) { - *remainingSize = streamSize; - } - - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t ParameterWrapper::copyFrom(const ParameterWrapper *from, - uint16_t startWritingAtIndex) { - if (data == NULL) { - return READONLY; - } - - if (from->readonlyData == NULL) { - return SOURCE_NOT_SET; - } - - if (type != from->type) { - return DATATYPE_MISSMATCH; - } - - //check if from fits into this - uint8_t startingRow = startWritingAtIndex / columns; - uint8_t startingColumn = startWritingAtIndex % columns; - - if ((from->rows > (rows - startingRow)) - || (from->columns > (columns - startingColumn))) { - return TOO_BIG; - } - - uint8_t typeSize = type.getSize(); - - ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; - //copy data - if (from->pointsToStream) { - switch (type) { - case Type::UINT8_T: - result = deSerializeData(startingRow, startingColumn, - from->readonlyData, from->rows, from->columns); - break; - case Type::INT8_T: - result = deSerializeData(startingRow, startingColumn, - from->readonlyData, from->rows, from->columns); - break; - case Type::UINT16_T: - result = deSerializeData(startingRow, startingColumn, - from->readonlyData, from->rows, from->columns); - break; - case Type::INT16_T: - result = deSerializeData(startingRow, startingColumn, - from->readonlyData, from->rows, from->columns); - break; - case Type::UINT32_T: - result = deSerializeData(startingRow, startingColumn, - from->readonlyData, from->rows, from->columns); - break; - case Type::INT32_T: - result = deSerializeData(startingRow, startingColumn, - from->readonlyData, from->rows, from->columns); - break; - case Type::FLOAT: - result = deSerializeData(startingRow, startingColumn, - from->readonlyData, from->rows, from->columns); - break; - case Type::DOUBLE: - result = deSerializeData(startingRow, startingColumn, - from->readonlyData, from->rows, from->columns); - break; - default: - result = UNKNOW_DATATYPE; - break; - } - } - else { - //need a type to do arithmetic - uint8_t* typedData = static_cast(data); - for (uint8_t fromRow = 0; fromRow < from->rows; fromRow++) { - uint8_t offset = (((startingRow + fromRow) * columns) + startingColumn) * typeSize; - std::memcpy(typedData + offset, from->readonlyData, - typeSize * from->columns); - } - } - - return result; -} +#include "../parameters/ParameterWrapper.h" + +ParameterWrapper::ParameterWrapper() : + pointsToStream(false), type(Type::UNKNOWN_TYPE) { +} + +ParameterWrapper::ParameterWrapper(Type type, uint8_t rows, uint8_t columns, + void *data) : + pointsToStream(false), type(type), rows(rows), columns(columns), + data(data), readonlyData(data) { +} + +ParameterWrapper::ParameterWrapper(Type type, uint8_t rows, uint8_t columns, + const void *data) : + pointsToStream(false), type(type), rows(rows), columns(columns), + data(nullptr), readonlyData(data) { +} + +ParameterWrapper::~ParameterWrapper() { +} + +ReturnValue_t ParameterWrapper::serialize(uint8_t **buffer, size_t *size, + size_t maxSize, Endianness streamEndianness) const { + ReturnValue_t result; + + result = SerializeAdapter::serialize(&type, buffer, size, maxSize, + streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + result = SerializeAdapter::serialize(&columns, buffer, size, maxSize, + streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = SerializeAdapter::serialize(&rows, buffer, size, maxSize, + streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + //serialize uses readonlyData, as it is always valid + if (readonlyData == NULL) { + return NOT_SET; + } + switch (type) { + case Type::UINT8_T: + result = serializeData(buffer, size, maxSize, + streamEndianness); + break; + case Type::INT8_T: + result = serializeData(buffer, size, maxSize, streamEndianness); + break; + case Type::UINT16_T: + result = serializeData(buffer, size, maxSize, + streamEndianness); + break; + case Type::INT16_T: + result = serializeData(buffer, size, maxSize, + streamEndianness); + break; + case Type::UINT32_T: + result = serializeData(buffer, size, maxSize, + streamEndianness); + break; + case Type::INT32_T: + result = serializeData(buffer, size, maxSize, + streamEndianness); + break; + case Type::FLOAT: + result = serializeData(buffer, size, maxSize, streamEndianness); + break; + case Type::DOUBLE: + result = serializeData(buffer, size, maxSize, streamEndianness); + break; + default: + result = UNKNOW_DATATYPE; + break; + } + return result; +} + +size_t ParameterWrapper::getSerializedSize() const { + uint32_t serializedSize = 0; + serializedSize += type.getSerializedSize(); + serializedSize += sizeof(rows); + serializedSize += sizeof(columns); + serializedSize += rows * columns * type.getSize(); + + return serializedSize; +} + +template +ReturnValue_t ParameterWrapper::serializeData(uint8_t **buffer, size_t *size, + size_t maxSize, Endianness streamEndianness) const { + const T *element = (const T*) readonlyData; + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + uint16_t dataSize = columns * rows; + while (dataSize != 0) { + result = SerializeAdapter::serialize(element, buffer, size, maxSize, + streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + element++; + dataSize--; + } + return result; +} + +template +ReturnValue_t ParameterWrapper::deSerializeData(uint8_t startingRow, + uint8_t startingColumn, const void *from, uint8_t fromRows, + uint8_t fromColumns) { + + //treat from as a continuous Stream as we copy all of it + const uint8_t *fromAsStream = (const uint8_t*) from; + size_t streamSize = fromRows * fromColumns * sizeof(T); + + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + + for (uint8_t fromRow = 0; fromRow < fromRows; fromRow++) { + + //get the start element of this row in data + T *dataWithDataType = ((T*) data) + + (((startingRow + fromRow) * columns) + startingColumn); + + for (uint8_t fromColumn = 0; fromColumn < fromColumns; fromColumn++) { + result = SerializeAdapter::deSerialize( + dataWithDataType + fromColumn, &fromAsStream, &streamSize, + SerializeIF::Endianness::BIG); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + } + + return result; + +} + + +ReturnValue_t ParameterWrapper::deSerialize(const uint8_t **buffer, + size_t *size, Endianness streamEndianness) { + return deSerialize(buffer, size, streamEndianness, 0); +} + +ReturnValue_t ParameterWrapper::deSerialize(const uint8_t **buffer, + size_t *size, Endianness streamEndianness, + uint16_t startWritingAtIndex) { + ParameterWrapper streamDescription; + + ReturnValue_t result = streamDescription.set(*buffer, *size, buffer, size); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + return copyFrom(&streamDescription, startWritingAtIndex); +} + +ReturnValue_t ParameterWrapper::set(const uint8_t *stream, size_t streamSize, + const uint8_t **remainingStream, size_t *remainingSize) { + ReturnValue_t result = SerializeAdapter::deSerialize(&type, &stream, + &streamSize, SerializeIF::Endianness::BIG); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + result = SerializeAdapter::deSerialize(&columns, &stream, &streamSize, + SerializeIF::Endianness::BIG); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = SerializeAdapter::deSerialize(&rows, &stream, &streamSize, + SerializeIF::Endianness::BIG); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + size_t dataSize = type.getSize() * rows * columns; + + if (streamSize < dataSize) { + return SerializeIF::STREAM_TOO_SHORT; + } + + data = nullptr; + readonlyData = stream; + pointsToStream = true; + + stream += dataSize; + if (remainingStream != nullptr) { + *remainingStream = stream; + } + streamSize -= dataSize; + if (remainingSize != nullptr) { + *remainingSize = streamSize; + } + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t ParameterWrapper::copyFrom(const ParameterWrapper *from, + uint16_t startWritingAtIndex) { + if (data == NULL) { + return READONLY; + } + + if (from->readonlyData == NULL) { + return SOURCE_NOT_SET; + } + + if (type != from->type) { + return DATATYPE_MISSMATCH; + } + + //check if from fits into this + uint8_t startingRow = startWritingAtIndex / columns; + uint8_t startingColumn = startWritingAtIndex % columns; + + if ((from->rows > (rows - startingRow)) + || (from->columns > (columns - startingColumn))) { + return TOO_BIG; + } + + uint8_t typeSize = type.getSize(); + + ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; + //copy data + if (from->pointsToStream) { + switch (type) { + case Type::UINT8_T: + result = deSerializeData(startingRow, startingColumn, + from->readonlyData, from->rows, from->columns); + break; + case Type::INT8_T: + result = deSerializeData(startingRow, startingColumn, + from->readonlyData, from->rows, from->columns); + break; + case Type::UINT16_T: + result = deSerializeData(startingRow, startingColumn, + from->readonlyData, from->rows, from->columns); + break; + case Type::INT16_T: + result = deSerializeData(startingRow, startingColumn, + from->readonlyData, from->rows, from->columns); + break; + case Type::UINT32_T: + result = deSerializeData(startingRow, startingColumn, + from->readonlyData, from->rows, from->columns); + break; + case Type::INT32_T: + result = deSerializeData(startingRow, startingColumn, + from->readonlyData, from->rows, from->columns); + break; + case Type::FLOAT: + result = deSerializeData(startingRow, startingColumn, + from->readonlyData, from->rows, from->columns); + break; + case Type::DOUBLE: + result = deSerializeData(startingRow, startingColumn, + from->readonlyData, from->rows, from->columns); + break; + default: + result = UNKNOW_DATATYPE; + break; + } + } + else { + //need a type to do arithmetic + uint8_t* typedData = static_cast(data); + for (uint8_t fromRow = 0; fromRow < from->rows; fromRow++) { + uint8_t offset = (((startingRow + fromRow) * columns) + startingColumn) * typeSize; + std::memcpy(typedData + offset, from->readonlyData, + typeSize * from->columns); + } + } + + return result; +} diff --git a/parameters/ParameterWrapper.h b/parameters/ParameterWrapper.h index eec101f2..1f38f691 100644 --- a/parameters/ParameterWrapper.h +++ b/parameters/ParameterWrapper.h @@ -1,162 +1,162 @@ -#ifndef FRAMEWORK_PARAMETERS_PARAMETERWRAPPER_H_ -#define FRAMEWORK_PARAMETERS_PARAMETERWRAPPER_H_ - -#include -#include -#include -#include -#include - -/** - * @brief - * @details - */ -class ParameterWrapper: public SerializeIF { - friend class DataPoolParameterWrapper; -public: - static const uint8_t INTERFACE_ID = CLASS_ID::PARAMETER_WRAPPER; - static const ReturnValue_t UNKNOW_DATATYPE = MAKE_RETURN_CODE(0x01); - static const ReturnValue_t DATATYPE_MISSMATCH = MAKE_RETURN_CODE(0x02); - static const ReturnValue_t READONLY = MAKE_RETURN_CODE(0x03); - static const ReturnValue_t TOO_BIG = MAKE_RETURN_CODE(0x04); - static const ReturnValue_t SOURCE_NOT_SET = MAKE_RETURN_CODE(0x05); - static const ReturnValue_t OUT_OF_BOUNDS = MAKE_RETURN_CODE(0x06); - static const ReturnValue_t NOT_SET = MAKE_RETURN_CODE(0x07); - - ParameterWrapper(); - ParameterWrapper(Type type, uint8_t rows, uint8_t columns, void *data); - ParameterWrapper(Type type, uint8_t rows, uint8_t columns, - const void *data); - virtual ~ParameterWrapper(); - - virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) const override; - - virtual size_t getSerializedSize() const override; - - virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - Endianness streamEndianness) override; - - virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - Endianness streamEndianness, uint16_t startWritingAtIndex = 0); - - /** - * Get a specific parameter value by supplying the row and the column. - * @tparam T Type of target data - * @param value [out] Pointer to storage location - * @param row - * @param column - * @return - * -@c RETURN_OK if element was retrieved successfully - * -@c NOT_SET data has not been set yet - * -@c DATATYPE_MISSMATCH Invalid supplied type - * -@c OUT_OF_BOUNDS Invalid row and/or column. - */ - template - ReturnValue_t getElement(T *value, uint8_t row = 0, - uint8_t column = 0) const; - - template - void set(T *data, uint8_t rows, uint8_t columns) { - this->data = data; - this->readonlyData = data; - this->type = PodTypeConversion::type; - this->rows = rows; - this->columns = columns; - this->pointsToStream = false; - } - - template - void set(const T *readonlyData, uint8_t rows, uint8_t columns) { - this->data = NULL; - this->readonlyData = readonlyData; - this->type = PodTypeConversion::type; - this->rows = rows; - this->columns = columns; - this->pointsToStream = false; - } - - template - void set(T& member) { - this->set(&member, 1, 1); - } - - template - void set(const T& readonlyMember) { - this->set(&readonlyMember, 1, 1); - } - - template - void setVector(T& member) { - this->set(member, sizeof(member)/sizeof(member[0]), 1); - } - - template - void setVector(const T& member) { - this->set(member, 1, sizeof(member)/sizeof(member[0])); - } - template - void setMatrix(T& member) { - this->set(member[0], sizeof(member)/sizeof(member[0]), sizeof(member[0])/sizeof(member[0][0])); - } - - template - void setMatrix(const T& member) { - this->set(member[0], sizeof(member)/sizeof(member[0]), sizeof(member[0])/sizeof(member[0][0])); - } - - ReturnValue_t set(const uint8_t *stream, size_t streamSize, - const uint8_t **remainingStream = nullptr, - size_t *remainingSize = nullptr); - - ReturnValue_t copyFrom(const ParameterWrapper *from, - uint16_t startWritingAtIndex); - -private: - bool pointsToStream = false; - - Type type; - uint8_t rows = 0; - uint8_t columns = 0; - void *data = nullptr; - const void *readonlyData = nullptr; - - template - ReturnValue_t serializeData(uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) const; - - template - ReturnValue_t deSerializeData(uint8_t startingRow, uint8_t startingColumn, - const void *from, uint8_t fromRows, uint8_t fromColumns); -}; - -template -inline ReturnValue_t ParameterWrapper::getElement(T *value, uint8_t row, - uint8_t column) const { - if (readonlyData == nullptr){ - return NOT_SET; - } - - if (PodTypeConversion::type != type) { - return DATATYPE_MISSMATCH; - } - - if ((row >= rows) or (column >= columns)) { - return OUT_OF_BOUNDS; - } - - if (pointsToStream) { - const uint8_t *streamWithType = static_cast(readonlyData); - streamWithType += (row * columns + column) * type.getSize(); - int32_t size = type.getSize(); - return SerializeAdapter::deSerialize(value, &streamWithType, - &size, true); - } - else { - const T *dataWithType = static_cast(readonlyData); - *value = dataWithType[row * columns + column]; - return HasReturnvaluesIF::RETURN_OK; - } -} - -#endif /* PARAMETERWRAPPER_H_ */ +#ifndef FRAMEWORK_PARAMETERS_PARAMETERWRAPPER_H_ +#define FRAMEWORK_PARAMETERS_PARAMETERWRAPPER_H_ + +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../serialize/SerializeAdapter.h" +#include "../serialize/SerializeIF.h" +#include +#include "../globalfunctions/Type.h" + +/** + * @brief + * @details + */ +class ParameterWrapper: public SerializeIF { + friend class DataPoolParameterWrapper; +public: + static const uint8_t INTERFACE_ID = CLASS_ID::PARAMETER_WRAPPER; + static const ReturnValue_t UNKNOW_DATATYPE = MAKE_RETURN_CODE(0x01); + static const ReturnValue_t DATATYPE_MISSMATCH = MAKE_RETURN_CODE(0x02); + static const ReturnValue_t READONLY = MAKE_RETURN_CODE(0x03); + static const ReturnValue_t TOO_BIG = MAKE_RETURN_CODE(0x04); + static const ReturnValue_t SOURCE_NOT_SET = MAKE_RETURN_CODE(0x05); + static const ReturnValue_t OUT_OF_BOUNDS = MAKE_RETURN_CODE(0x06); + static const ReturnValue_t NOT_SET = MAKE_RETURN_CODE(0x07); + + ParameterWrapper(); + ParameterWrapper(Type type, uint8_t rows, uint8_t columns, void *data); + ParameterWrapper(Type type, uint8_t rows, uint8_t columns, + const void *data); + virtual ~ParameterWrapper(); + + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + size_t maxSize, Endianness streamEndianness) const override; + + virtual size_t getSerializedSize() const override; + + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + Endianness streamEndianness) override; + + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + Endianness streamEndianness, uint16_t startWritingAtIndex = 0); + + /** + * Get a specific parameter value by supplying the row and the column. + * @tparam T Type of target data + * @param value [out] Pointer to storage location + * @param row + * @param column + * @return + * -@c RETURN_OK if element was retrieved successfully + * -@c NOT_SET data has not been set yet + * -@c DATATYPE_MISSMATCH Invalid supplied type + * -@c OUT_OF_BOUNDS Invalid row and/or column. + */ + template + ReturnValue_t getElement(T *value, uint8_t row = 0, + uint8_t column = 0) const; + + template + void set(T *data, uint8_t rows, uint8_t columns) { + this->data = data; + this->readonlyData = data; + this->type = PodTypeConversion::type; + this->rows = rows; + this->columns = columns; + this->pointsToStream = false; + } + + template + void set(const T *readonlyData, uint8_t rows, uint8_t columns) { + this->data = NULL; + this->readonlyData = readonlyData; + this->type = PodTypeConversion::type; + this->rows = rows; + this->columns = columns; + this->pointsToStream = false; + } + + template + void set(T& member) { + this->set(&member, 1, 1); + } + + template + void set(const T& readonlyMember) { + this->set(&readonlyMember, 1, 1); + } + + template + void setVector(T& member) { + this->set(member, sizeof(member)/sizeof(member[0]), 1); + } + + template + void setVector(const T& member) { + this->set(member, 1, sizeof(member)/sizeof(member[0])); + } + template + void setMatrix(T& member) { + this->set(member[0], sizeof(member)/sizeof(member[0]), sizeof(member[0])/sizeof(member[0][0])); + } + + template + void setMatrix(const T& member) { + this->set(member[0], sizeof(member)/sizeof(member[0]), sizeof(member[0])/sizeof(member[0][0])); + } + + ReturnValue_t set(const uint8_t *stream, size_t streamSize, + const uint8_t **remainingStream = nullptr, + size_t *remainingSize = nullptr); + + ReturnValue_t copyFrom(const ParameterWrapper *from, + uint16_t startWritingAtIndex); + +private: + bool pointsToStream = false; + + Type type; + uint8_t rows = 0; + uint8_t columns = 0; + void *data = nullptr; + const void *readonlyData = nullptr; + + template + ReturnValue_t serializeData(uint8_t** buffer, size_t* size, + size_t maxSize, Endianness streamEndianness) const; + + template + ReturnValue_t deSerializeData(uint8_t startingRow, uint8_t startingColumn, + const void *from, uint8_t fromRows, uint8_t fromColumns); +}; + +template +inline ReturnValue_t ParameterWrapper::getElement(T *value, uint8_t row, + uint8_t column) const { + if (readonlyData == nullptr){ + return NOT_SET; + } + + if (PodTypeConversion::type != type) { + return DATATYPE_MISSMATCH; + } + + if ((row >= rows) or (column >= columns)) { + return OUT_OF_BOUNDS; + } + + if (pointsToStream) { + const uint8_t *streamWithType = static_cast(readonlyData); + streamWithType += (row * columns + column) * type.getSize(); + int32_t size = type.getSize(); + return SerializeAdapter::deSerialize(value, &streamWithType, + &size, true); + } + else { + const T *dataWithType = static_cast(readonlyData); + *value = dataWithType[row * columns + column]; + return HasReturnvaluesIF::RETURN_OK; + } +} + +#endif /* PARAMETERWRAPPER_H_ */ diff --git a/parameters/ReceivesParameterMessagesIF.h b/parameters/ReceivesParameterMessagesIF.h index 9bcd226d..9a280b4f 100644 --- a/parameters/ReceivesParameterMessagesIF.h +++ b/parameters/ReceivesParameterMessagesIF.h @@ -1,19 +1,19 @@ -#ifndef RECEIVESPARAMETERMESSAGESIF_H_ -#define RECEIVESPARAMETERMESSAGESIF_H_ - - -#include -#include - -class ReceivesParameterMessagesIF : public HasParametersIF { -public: - - static const uint8_t DOMAIN_ID_BASE = 0; - virtual ~ReceivesParameterMessagesIF() { - } - - virtual MessageQueueId_t getCommandQueue() const = 0; -}; - - -#endif /* RECEIVESPARAMETERMESSAGESIF_H_ */ +#ifndef RECEIVESPARAMETERMESSAGESIF_H_ +#define RECEIVESPARAMETERMESSAGESIF_H_ + + +#include "../parameters/HasParametersIF.h" +#include "../ipc/MessageQueueSenderIF.h" + +class ReceivesParameterMessagesIF : public HasParametersIF { +public: + + static const uint8_t DOMAIN_ID_BASE = 0; + virtual ~ReceivesParameterMessagesIF() { + } + + virtual MessageQueueId_t getCommandQueue() const = 0; +}; + + +#endif /* RECEIVESPARAMETERMESSAGESIF_H_ */ diff --git a/power/Fuse.cpp b/power/Fuse.cpp index b18b5b1a..59d60491 100644 --- a/power/Fuse.cpp +++ b/power/Fuse.cpp @@ -1,260 +1,260 @@ -#include -#include -#include -#include -#include -#include - -object_id_t Fuse::powerSwitchId = 0; - -Fuse::Fuse(object_id_t fuseObjectId, uint8_t fuseId, VariableIds ids, - float maxCurrent, uint16_t confirmationCount) : - SystemObject(fuseObjectId), oldFuseState(0), fuseId(fuseId), powerIF( - NULL), currentLimit(fuseObjectId, 1, ids.pidCurrent, confirmationCount, - maxCurrent, FUSE_CURRENT_HIGH), powerMonitor(fuseObjectId, 2, - GlobalDataPool::poolIdAndPositionToPid(ids.poolIdPower, 0), - confirmationCount), set(), voltage(ids.pidVoltage, &set), current( - ids.pidCurrent, &set), state(ids.pidState, &set), power( - ids.poolIdPower, &set, PoolVariableIF::VAR_READ_WRITE), commandQueue( - NULL), parameterHelper(this), healthHelper(this, fuseObjectId) { - commandQueue = QueueFactory::instance()->createMessageQueue(); -} - -Fuse::~Fuse() { - QueueFactory::instance()->deleteMessageQueue(commandQueue); -} - -void Fuse::addDevice(PowerComponentIF* switchSet) { - devices.push_back(switchSet); -} - -ReturnValue_t Fuse::initialize() { - ReturnValue_t result = SystemObject::initialize(); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - result = parameterHelper.initialize(); - if (result != RETURN_OK) { - return result; - } - result = healthHelper.initialize(); - if (result != RETURN_OK) { - return result; - } - powerIF = objectManager->get(powerSwitchId); - if (powerIF == NULL) { - return RETURN_FAILED; - } - return RETURN_OK; -} - -void Fuse::calculatePowerLimits(float* low, float* high) { - for (DeviceList::iterator iter = devices.begin(); iter != devices.end(); - iter++) { - if (areSwitchesOfComponentOn(iter)) { - *low += (*iter)->getMin(); - *high += (*iter)->getMax(); - } - } -} - -ReturnValue_t Fuse::check() { - set.read(); - if (!healthHelper.healthTable->isHealthy(getObjectId())) { - setAllMonitorsToUnchecked(); - set.commit(PoolVariableIF::INVALID); - return RETURN_OK; - } - ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; - checkFuseState(); - calculateFusePower(); - //Check if power is valid and if fuse state is off or invalid. - if (!power.isValid() || (state == 0) || !state.isValid()) { - result = powerMonitor.setToInvalid(); - } else { - float lowLimit = 0.0; - float highLimit = RESIDUAL_POWER; - calculatePowerLimits(&lowLimit, &highLimit); - result = powerMonitor.checkPower(power, lowLimit, highLimit); - if (result == MonitoringIF::BELOW_LOW_LIMIT) { - reportEvents(POWER_BELOW_LOW_LIMIT); - } else if (result == MonitoringIF::ABOVE_HIGH_LIMIT) { - reportEvents(POWER_ABOVE_HIGH_LIMIT); - } - } - set.commit(); - return result; -} - -ReturnValue_t Fuse::serialize(uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) const { - ReturnValue_t result = RETURN_FAILED; - for (DeviceList::const_iterator iter = devices.begin(); - iter != devices.end(); iter++) { - result = (*iter)->serialize(buffer, size, maxSize, streamEndianness); - if (result != RETURN_OK) { - return result; - } - } - return RETURN_OK; -} - -size_t Fuse::getSerializedSize() const { - uint32_t size = 0; - for (DeviceList::const_iterator iter = devices.begin(); - iter != devices.end(); iter++) { - size += (*iter)->getSerializedSize(); - } - return size; -} - -ReturnValue_t Fuse::deSerialize(const uint8_t** buffer, size_t* size, - Endianness streamEndianness) { - ReturnValue_t result = RETURN_FAILED; - for (DeviceList::iterator iter = devices.begin(); iter != devices.end(); - iter++) { - result = (*iter)->deSerialize(buffer, size, streamEndianness); - if (result != RETURN_OK) { - return result; - } - } - return RETURN_OK; -} - -uint8_t Fuse::getFuseId() const { - return fuseId; -} - -void Fuse::calculateFusePower() { - ReturnValue_t result1 = currentLimit.check(); - if (result1 != HasReturnvaluesIF::RETURN_OK || !(voltage.isValid())) { - power.setValid(PoolVariableIF::INVALID); - return; - } - //Calculate fuse power. - power = current * voltage; - power.setValid(PoolVariableIF::VALID); -} - -ReturnValue_t Fuse::performOperation(uint8_t opCode) { - checkCommandQueue(); - return HasReturnvaluesIF::RETURN_OK; -} - -void Fuse::reportEvents(Event event) { - if (!powerMonitor.isEventEnabled()) { - return; - } - for (DeviceList::iterator iter = devices.begin(); iter != devices.end(); - iter++) { - if (areSwitchesOfComponentOn(iter)) { - EventManagerIF::triggerEvent((*iter)->getDeviceObjectId(), event); - } - } -} - -MessageQueueId_t Fuse::getCommandQueue() const { - return commandQueue->getId(); -} - -void Fuse::setAllMonitorsToUnchecked() { - currentLimit.setToUnchecked(); - powerMonitor.setToUnchecked(); -} - -void Fuse::checkCommandQueue() { - CommandMessage command; - ReturnValue_t result = commandQueue->receiveMessage(&command); - if (result != HasReturnvaluesIF::RETURN_OK) { - return; - } - result = healthHelper.handleHealthCommand(&command); - if (result == HasReturnvaluesIF::RETURN_OK) { - return; - } - result = parameterHelper.handleParameterMessage(&command); - if (result == HasReturnvaluesIF::RETURN_OK) { - return; - } - command.setToUnknownCommand(); - commandQueue->reply(&command); -} - -void Fuse::checkFuseState() { - if (!state.isValid()) { - oldFuseState = 0; - return; - } - if (state == 0) { - if (oldFuseState != 0) { - reportEvents(FUSE_WENT_OFF); - } - } - oldFuseState = state; -} - -float Fuse::getPower() { - if (power.isValid()) { - return power; - } else { - return 0.0; - } -} - -void Fuse::setDataPoolEntriesInvalid() { - set.read(); - set.commit(PoolVariableIF::INVALID); -} - -ReturnValue_t Fuse::getParameter(uint8_t domainId, uint16_t parameterId, - ParameterWrapper* parameterWrapper, const ParameterWrapper* newValues, - uint16_t startAtIndex) { - ReturnValue_t result = currentLimit.getParameter(domainId, parameterId, - parameterWrapper, newValues, startAtIndex); - if (result != INVALID_DOMAIN_ID) { - return result; - } - result = powerMonitor.getParameter(domainId, parameterId, parameterWrapper, - newValues, startAtIndex); - return result; -} - -bool Fuse::areSwitchesOfComponentOn(DeviceList::iterator iter) { - if (powerIF->getSwitchState((*iter)->getSwitchId1()) - != PowerSwitchIF::SWITCH_ON) { - return false; - } - if ((*iter)->hasTwoSwitches()) { - if ((powerIF->getSwitchState((*iter)->getSwitchId2()) - != PowerSwitchIF::SWITCH_ON)) { - return false; - } - } - return true; -} - -bool Fuse::isPowerValid() { - return power.isValid(); -} - -ReturnValue_t Fuse::setHealth(HealthState health) { - healthHelper.setHealth(health); - return RETURN_OK; -} - -HasHealthIF::HealthState Fuse::getHealth() { - return healthHelper.getHealth(); -} - -ReturnValue_t Fuse::PowerMonitor::checkPower(float sample, float lowerLimit, - float upperLimit) { - if (sample > upperLimit) { - return this->monitorStateIs(MonitoringIF::ABOVE_HIGH_LIMIT, sample, - upperLimit); - } else if (sample < lowerLimit) { - return this->monitorStateIs(MonitoringIF::BELOW_LOW_LIMIT, sample, - lowerLimit); - } else { - return this->monitorStateIs(RETURN_OK, sample, 0.0); //Within limits. - } -} +#include "../monitoring/LimitViolationReporter.h" +#include "../monitoring/MonitoringMessageContent.h" +#include "../objectmanager/ObjectManagerIF.h" +#include "../power/Fuse.h" +#include "../serialize/SerialFixedArrayListAdapter.h" +#include "../ipc/QueueFactory.h" + +object_id_t Fuse::powerSwitchId = 0; + +Fuse::Fuse(object_id_t fuseObjectId, uint8_t fuseId, VariableIds ids, + float maxCurrent, uint16_t confirmationCount) : + SystemObject(fuseObjectId), oldFuseState(0), fuseId(fuseId), powerIF( + NULL), currentLimit(fuseObjectId, 1, ids.pidCurrent, confirmationCount, + maxCurrent, FUSE_CURRENT_HIGH), powerMonitor(fuseObjectId, 2, + GlobalDataPool::poolIdAndPositionToPid(ids.poolIdPower, 0), + confirmationCount), set(), voltage(ids.pidVoltage, &set), current( + ids.pidCurrent, &set), state(ids.pidState, &set), power( + ids.poolIdPower, &set, PoolVariableIF::VAR_READ_WRITE), commandQueue( + NULL), parameterHelper(this), healthHelper(this, fuseObjectId) { + commandQueue = QueueFactory::instance()->createMessageQueue(); +} + +Fuse::~Fuse() { + QueueFactory::instance()->deleteMessageQueue(commandQueue); +} + +void Fuse::addDevice(PowerComponentIF* switchSet) { + devices.push_back(switchSet); +} + +ReturnValue_t Fuse::initialize() { + ReturnValue_t result = SystemObject::initialize(); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = parameterHelper.initialize(); + if (result != RETURN_OK) { + return result; + } + result = healthHelper.initialize(); + if (result != RETURN_OK) { + return result; + } + powerIF = objectManager->get(powerSwitchId); + if (powerIF == NULL) { + return RETURN_FAILED; + } + return RETURN_OK; +} + +void Fuse::calculatePowerLimits(float* low, float* high) { + for (DeviceList::iterator iter = devices.begin(); iter != devices.end(); + iter++) { + if (areSwitchesOfComponentOn(iter)) { + *low += (*iter)->getMin(); + *high += (*iter)->getMax(); + } + } +} + +ReturnValue_t Fuse::check() { + set.read(); + if (!healthHelper.healthTable->isHealthy(getObjectId())) { + setAllMonitorsToUnchecked(); + set.commit(PoolVariableIF::INVALID); + return RETURN_OK; + } + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + checkFuseState(); + calculateFusePower(); + //Check if power is valid and if fuse state is off or invalid. + if (!power.isValid() || (state == 0) || !state.isValid()) { + result = powerMonitor.setToInvalid(); + } else { + float lowLimit = 0.0; + float highLimit = RESIDUAL_POWER; + calculatePowerLimits(&lowLimit, &highLimit); + result = powerMonitor.checkPower(power, lowLimit, highLimit); + if (result == MonitoringIF::BELOW_LOW_LIMIT) { + reportEvents(POWER_BELOW_LOW_LIMIT); + } else if (result == MonitoringIF::ABOVE_HIGH_LIMIT) { + reportEvents(POWER_ABOVE_HIGH_LIMIT); + } + } + set.commit(); + return result; +} + +ReturnValue_t Fuse::serialize(uint8_t** buffer, size_t* size, + size_t maxSize, Endianness streamEndianness) const { + ReturnValue_t result = RETURN_FAILED; + for (DeviceList::const_iterator iter = devices.begin(); + iter != devices.end(); iter++) { + result = (*iter)->serialize(buffer, size, maxSize, streamEndianness); + if (result != RETURN_OK) { + return result; + } + } + return RETURN_OK; +} + +size_t Fuse::getSerializedSize() const { + uint32_t size = 0; + for (DeviceList::const_iterator iter = devices.begin(); + iter != devices.end(); iter++) { + size += (*iter)->getSerializedSize(); + } + return size; +} + +ReturnValue_t Fuse::deSerialize(const uint8_t** buffer, size_t* size, + Endianness streamEndianness) { + ReturnValue_t result = RETURN_FAILED; + for (DeviceList::iterator iter = devices.begin(); iter != devices.end(); + iter++) { + result = (*iter)->deSerialize(buffer, size, streamEndianness); + if (result != RETURN_OK) { + return result; + } + } + return RETURN_OK; +} + +uint8_t Fuse::getFuseId() const { + return fuseId; +} + +void Fuse::calculateFusePower() { + ReturnValue_t result1 = currentLimit.check(); + if (result1 != HasReturnvaluesIF::RETURN_OK || !(voltage.isValid())) { + power.setValid(PoolVariableIF::INVALID); + return; + } + //Calculate fuse power. + power = current * voltage; + power.setValid(PoolVariableIF::VALID); +} + +ReturnValue_t Fuse::performOperation(uint8_t opCode) { + checkCommandQueue(); + return HasReturnvaluesIF::RETURN_OK; +} + +void Fuse::reportEvents(Event event) { + if (!powerMonitor.isEventEnabled()) { + return; + } + for (DeviceList::iterator iter = devices.begin(); iter != devices.end(); + iter++) { + if (areSwitchesOfComponentOn(iter)) { + EventManagerIF::triggerEvent((*iter)->getDeviceObjectId(), event); + } + } +} + +MessageQueueId_t Fuse::getCommandQueue() const { + return commandQueue->getId(); +} + +void Fuse::setAllMonitorsToUnchecked() { + currentLimit.setToUnchecked(); + powerMonitor.setToUnchecked(); +} + +void Fuse::checkCommandQueue() { + CommandMessage command; + ReturnValue_t result = commandQueue->receiveMessage(&command); + if (result != HasReturnvaluesIF::RETURN_OK) { + return; + } + result = healthHelper.handleHealthCommand(&command); + if (result == HasReturnvaluesIF::RETURN_OK) { + return; + } + result = parameterHelper.handleParameterMessage(&command); + if (result == HasReturnvaluesIF::RETURN_OK) { + return; + } + command.setToUnknownCommand(); + commandQueue->reply(&command); +} + +void Fuse::checkFuseState() { + if (!state.isValid()) { + oldFuseState = 0; + return; + } + if (state == 0) { + if (oldFuseState != 0) { + reportEvents(FUSE_WENT_OFF); + } + } + oldFuseState = state; +} + +float Fuse::getPower() { + if (power.isValid()) { + return power; + } else { + return 0.0; + } +} + +void Fuse::setDataPoolEntriesInvalid() { + set.read(); + set.commit(PoolVariableIF::INVALID); +} + +ReturnValue_t Fuse::getParameter(uint8_t domainId, uint16_t parameterId, + ParameterWrapper* parameterWrapper, const ParameterWrapper* newValues, + uint16_t startAtIndex) { + ReturnValue_t result = currentLimit.getParameter(domainId, parameterId, + parameterWrapper, newValues, startAtIndex); + if (result != INVALID_DOMAIN_ID) { + return result; + } + result = powerMonitor.getParameter(domainId, parameterId, parameterWrapper, + newValues, startAtIndex); + return result; +} + +bool Fuse::areSwitchesOfComponentOn(DeviceList::iterator iter) { + if (powerIF->getSwitchState((*iter)->getSwitchId1()) + != PowerSwitchIF::SWITCH_ON) { + return false; + } + if ((*iter)->hasTwoSwitches()) { + if ((powerIF->getSwitchState((*iter)->getSwitchId2()) + != PowerSwitchIF::SWITCH_ON)) { + return false; + } + } + return true; +} + +bool Fuse::isPowerValid() { + return power.isValid(); +} + +ReturnValue_t Fuse::setHealth(HealthState health) { + healthHelper.setHealth(health); + return RETURN_OK; +} + +HasHealthIF::HealthState Fuse::getHealth() { + return healthHelper.getHealth(); +} + +ReturnValue_t Fuse::PowerMonitor::checkPower(float sample, float lowerLimit, + float upperLimit) { + if (sample > upperLimit) { + return this->monitorStateIs(MonitoringIF::ABOVE_HIGH_LIMIT, sample, + upperLimit); + } else if (sample < lowerLimit) { + return this->monitorStateIs(MonitoringIF::BELOW_LOW_LIMIT, sample, + lowerLimit); + } else { + return this->monitorStateIs(RETURN_OK, sample, 0.0); //Within limits. + } +} diff --git a/power/Fuse.h b/power/Fuse.h index 1608023c..e6d6929c 100644 --- a/power/Fuse.h +++ b/power/Fuse.h @@ -1,106 +1,106 @@ -#ifndef FUSE_H_ -#define FUSE_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Factory { -void setStaticFrameworkObjectIds(); -} - -class Fuse: public SystemObject, - public HasHealthIF, - public HasReturnvaluesIF, - public ReceivesParameterMessagesIF, - public SerializeIF { - friend void (Factory::setStaticFrameworkObjectIds)(); -private: - static constexpr float RESIDUAL_POWER = 0.005 * 28.5; //!< This is the upper limit of residual power lost by fuses and switches. Worst case is Fuse and one of two switches on. See PCDU ICD 1.9 p29 bottom -public: - struct VariableIds { - uint32_t pidVoltage; - uint32_t pidCurrent; - uint32_t pidState; - uint32_t poolIdPower; - }; - - static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PCDU_1; - static const Event FUSE_CURRENT_HIGH = MAKE_EVENT(1, SEVERITY::LOW); //!< PSS detected that current on a fuse is totally out of bounds. - static const Event FUSE_WENT_OFF = MAKE_EVENT(2, SEVERITY::LOW); //!< PSS detected a fuse that went off. - static const Event POWER_ABOVE_HIGH_LIMIT = MAKE_EVENT(4, SEVERITY::LOW); //!< PSS detected a fuse that violates its limits. - static const Event POWER_BELOW_LOW_LIMIT = MAKE_EVENT(5, SEVERITY::LOW); //!< PSS detected a fuse that violates its limits. - - typedef std::list DeviceList; - Fuse(object_id_t fuseObjectId, uint8_t fuseId, VariableIds ids, - float maxCurrent, uint16_t confirmationCount = 2); - virtual ~Fuse(); - void addDevice(PowerComponentIF *set); - float getPower(); - - bool isPowerValid(); - - ReturnValue_t check(); - uint8_t getFuseId() const; - ReturnValue_t initialize(); - DeviceList devices; - ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize, - SerializeIF::Endianness streamEndianness) const override; - size_t getSerializedSize() const override; - ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, - SerializeIF::Endianness streamEndianness) override; - void setAllMonitorsToUnchecked(); - ReturnValue_t performOperation(uint8_t opCode); - MessageQueueId_t getCommandQueue() const; - void setDataPoolEntriesInvalid(); - ReturnValue_t setHealth(HealthState health); - HasHealthIF::HealthState getHealth(); - - ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, - ParameterWrapper *parameterWrapper, - const ParameterWrapper *newValues, uint16_t startAtIndex); - -private: - uint8_t oldFuseState; - uint8_t fuseId; - PowerSwitchIF *powerIF; //could be static in our case. - AbsLimitMonitor currentLimit; - class PowerMonitor: public MonitorReporter { - public: - template - PowerMonitor(Args ... args) : - MonitorReporter(std::forward(args)...) { - } - ReturnValue_t checkPower(float sample, float lowerLimit, - float upperLimit); - void sendTransitionEvent(float currentValue, ReturnValue_t state) { - } - - }; - PowerMonitor powerMonitor; - GlobDataSet set; - PIDReader voltage; - PIDReader current; - PIDReader state; - gp_float_t power; - MessageQueueIF* commandQueue; - ParameterHelper parameterHelper; - HealthHelper healthHelper; - static object_id_t powerSwitchId; - void calculatePowerLimits(float *low, float *high); - void calculateFusePower(); - void checkFuseState(); - void reportEvents(Event event); - void checkCommandQueue(); - - bool areSwitchesOfComponentOn(DeviceList::iterator iter); -}; - -#endif /* FUSE_H_ */ +#ifndef FUSE_H_ +#define FUSE_H_ + +#include "../datapoolglob/GlobalDataSet.h" +#include "../datapoolglob/GlobalPoolVariable.h" +#include "../datapoolglob/PIDReader.h" +#include "../devicehandlers/HealthDevice.h" +#include "../monitoring/AbsLimitMonitor.h" +#include "../power/PowerComponentIF.h" +#include "../power/PowerSwitchIF.h" +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../parameters/ParameterHelper.h" +#include + +namespace Factory { +void setStaticFrameworkObjectIds(); +} + +class Fuse: public SystemObject, + public HasHealthIF, + public HasReturnvaluesIF, + public ReceivesParameterMessagesIF, + public SerializeIF { + friend void (Factory::setStaticFrameworkObjectIds)(); +private: + static constexpr float RESIDUAL_POWER = 0.005 * 28.5; //!< This is the upper limit of residual power lost by fuses and switches. Worst case is Fuse and one of two switches on. See PCDU ICD 1.9 p29 bottom +public: + struct VariableIds { + uint32_t pidVoltage; + uint32_t pidCurrent; + uint32_t pidState; + uint32_t poolIdPower; + }; + + static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PCDU_1; + static const Event FUSE_CURRENT_HIGH = MAKE_EVENT(1, SEVERITY::LOW); //!< PSS detected that current on a fuse is totally out of bounds. + static const Event FUSE_WENT_OFF = MAKE_EVENT(2, SEVERITY::LOW); //!< PSS detected a fuse that went off. + static const Event POWER_ABOVE_HIGH_LIMIT = MAKE_EVENT(4, SEVERITY::LOW); //!< PSS detected a fuse that violates its limits. + static const Event POWER_BELOW_LOW_LIMIT = MAKE_EVENT(5, SEVERITY::LOW); //!< PSS detected a fuse that violates its limits. + + typedef std::list DeviceList; + Fuse(object_id_t fuseObjectId, uint8_t fuseId, VariableIds ids, + float maxCurrent, uint16_t confirmationCount = 2); + virtual ~Fuse(); + void addDevice(PowerComponentIF *set); + float getPower(); + + bool isPowerValid(); + + ReturnValue_t check(); + uint8_t getFuseId() const; + ReturnValue_t initialize(); + DeviceList devices; + ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize, + SerializeIF::Endianness streamEndianness) const override; + size_t getSerializedSize() const override; + ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, + SerializeIF::Endianness streamEndianness) override; + void setAllMonitorsToUnchecked(); + ReturnValue_t performOperation(uint8_t opCode); + MessageQueueId_t getCommandQueue() const; + void setDataPoolEntriesInvalid(); + ReturnValue_t setHealth(HealthState health); + HasHealthIF::HealthState getHealth(); + + ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, + ParameterWrapper *parameterWrapper, + const ParameterWrapper *newValues, uint16_t startAtIndex); + +private: + uint8_t oldFuseState; + uint8_t fuseId; + PowerSwitchIF *powerIF; //could be static in our case. + AbsLimitMonitor currentLimit; + class PowerMonitor: public MonitorReporter { + public: + template + PowerMonitor(Args ... args) : + MonitorReporter(std::forward(args)...) { + } + ReturnValue_t checkPower(float sample, float lowerLimit, + float upperLimit); + void sendTransitionEvent(float currentValue, ReturnValue_t state) { + } + + }; + PowerMonitor powerMonitor; + GlobDataSet set; + PIDReader voltage; + PIDReader current; + PIDReader state; + gp_float_t power; + MessageQueueIF* commandQueue; + ParameterHelper parameterHelper; + HealthHelper healthHelper; + static object_id_t powerSwitchId; + void calculatePowerLimits(float *low, float *high); + void calculateFusePower(); + void checkFuseState(); + void reportEvents(Event event); + void checkCommandQueue(); + + bool areSwitchesOfComponentOn(DeviceList::iterator iter); +}; + +#endif /* FUSE_H_ */ diff --git a/power/PowerComponent.cpp b/power/PowerComponent.cpp index d1acffeb..ef852e64 100644 --- a/power/PowerComponent.cpp +++ b/power/PowerComponent.cpp @@ -1,86 +1,86 @@ -/** - * @file PowerComponent.cpp - * @brief This file defines the PowerComponent class. - * @date 28.08.2014 - * @author baetz - */ - -#include - -PowerComponent::PowerComponent() : - deviceObjectId(0), switchId1(0xFF), switchId2(0xFF), doIHaveTwoSwitches( - false), min(0.0), max(0.0), moduleId(0) { -} -PowerComponent::PowerComponent(object_id_t setId, uint8_t moduleId, float min, float max, - uint8_t switchId1, bool twoSwitches, uint8_t switchId2) : - deviceObjectId(setId), switchId1(switchId1), switchId2(switchId2), doIHaveTwoSwitches( - twoSwitches), min(min), max(max), moduleId(moduleId) { -} - -ReturnValue_t PowerComponent::serialize(uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) const { - ReturnValue_t result = SerializeAdapter::serialize(&min, buffer, - size, maxSize, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - return SerializeAdapter::serialize(&max, buffer, size, maxSize, - streamEndianness); -} - -size_t PowerComponent::getSerializedSize() const { - return sizeof(min) + sizeof(max); -} - -object_id_t PowerComponent::getDeviceObjectId() { - return deviceObjectId; -} - -uint8_t PowerComponent::getSwitchId1() { - return switchId1; -} - -uint8_t PowerComponent::getSwitchId2() { - return switchId2; -} - -bool PowerComponent::hasTwoSwitches() { - return doIHaveTwoSwitches; -} - -float PowerComponent::getMin() { - return min; -} - -float PowerComponent::getMax() { - return max; -} - -ReturnValue_t PowerComponent::deSerialize(const uint8_t** buffer, size_t* size, - Endianness streamEndianness) { - ReturnValue_t result = SerializeAdapter::deSerialize(&min, buffer, - size, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - return SerializeAdapter::deSerialize(&max, buffer, size, streamEndianness); -} - -ReturnValue_t PowerComponent::getParameter(uint8_t domainId, - uint16_t parameterId, ParameterWrapper* parameterWrapper, - const ParameterWrapper* newValues, uint16_t startAtIndex) { - if (domainId != moduleId) { - return INVALID_DOMAIN_ID; - } - switch (parameterId) { - case 0: - parameterWrapper->set<>(min); - break; - case 1: - parameterWrapper->set<>(max); - break; - default: - return INVALID_MATRIX_ID; - } - return HasReturnvaluesIF::RETURN_OK; -} +/** + * @file PowerComponent.cpp + * @brief This file defines the PowerComponent class. + * @date 28.08.2014 + * @author baetz + */ + +#include "../power/PowerComponent.h" + +PowerComponent::PowerComponent() : + deviceObjectId(0), switchId1(0xFF), switchId2(0xFF), doIHaveTwoSwitches( + false), min(0.0), max(0.0), moduleId(0) { +} +PowerComponent::PowerComponent(object_id_t setId, uint8_t moduleId, float min, float max, + uint8_t switchId1, bool twoSwitches, uint8_t switchId2) : + deviceObjectId(setId), switchId1(switchId1), switchId2(switchId2), doIHaveTwoSwitches( + twoSwitches), min(min), max(max), moduleId(moduleId) { +} + +ReturnValue_t PowerComponent::serialize(uint8_t** buffer, size_t* size, + size_t maxSize, Endianness streamEndianness) const { + ReturnValue_t result = SerializeAdapter::serialize(&min, buffer, + size, maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return SerializeAdapter::serialize(&max, buffer, size, maxSize, + streamEndianness); +} + +size_t PowerComponent::getSerializedSize() const { + return sizeof(min) + sizeof(max); +} + +object_id_t PowerComponent::getDeviceObjectId() { + return deviceObjectId; +} + +uint8_t PowerComponent::getSwitchId1() { + return switchId1; +} + +uint8_t PowerComponent::getSwitchId2() { + return switchId2; +} + +bool PowerComponent::hasTwoSwitches() { + return doIHaveTwoSwitches; +} + +float PowerComponent::getMin() { + return min; +} + +float PowerComponent::getMax() { + return max; +} + +ReturnValue_t PowerComponent::deSerialize(const uint8_t** buffer, size_t* size, + Endianness streamEndianness) { + ReturnValue_t result = SerializeAdapter::deSerialize(&min, buffer, + size, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return SerializeAdapter::deSerialize(&max, buffer, size, streamEndianness); +} + +ReturnValue_t PowerComponent::getParameter(uint8_t domainId, + uint16_t parameterId, ParameterWrapper* parameterWrapper, + const ParameterWrapper* newValues, uint16_t startAtIndex) { + if (domainId != moduleId) { + return INVALID_DOMAIN_ID; + } + switch (parameterId) { + case 0: + parameterWrapper->set<>(min); + break; + case 1: + parameterWrapper->set<>(max); + break; + default: + return INVALID_MATRIX_ID; + } + return HasReturnvaluesIF::RETURN_OK; +} diff --git a/power/PowerComponent.h b/power/PowerComponent.h index 61ab3674..2e11fa82 100644 --- a/power/PowerComponent.h +++ b/power/PowerComponent.h @@ -1,48 +1,48 @@ -#ifndef POWERCOMPONENT_H_ -#define POWERCOMPONENT_H_ - -#include -#include - -class PowerComponent: public PowerComponentIF { -public: - PowerComponent(object_id_t setId, uint8_t moduleId, float min, float max, uint8_t switchId1, - bool twoSwitches = false, uint8_t switchId2 = 0xFF); - - virtual object_id_t getDeviceObjectId(); - - virtual uint8_t getSwitchId1(); - virtual uint8_t getSwitchId2(); - - bool hasTwoSwitches(); - - float getMin(); - float getMax(); - - ReturnValue_t serialize(uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) const override; - - size_t getSerializedSize() const override; - - ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - Endianness streamEndianness) override; - - ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, - ParameterWrapper *parameterWrapper, - const ParameterWrapper *newValues, uint16_t startAtIndex); -private: - const object_id_t deviceObjectId; - const uint8_t switchId1; - const uint8_t switchId2; - - const bool doIHaveTwoSwitches; - - float min; - float max; - - uint8_t moduleId; - - PowerComponent(); -}; - -#endif /* POWERCOMPONENT_H_ */ +#ifndef POWERCOMPONENT_H_ +#define POWERCOMPONENT_H_ + +#include "../objectmanager/SystemObjectIF.h" +#include "../power/PowerComponentIF.h" + +class PowerComponent: public PowerComponentIF { +public: + PowerComponent(object_id_t setId, uint8_t moduleId, float min, float max, uint8_t switchId1, + bool twoSwitches = false, uint8_t switchId2 = 0xFF); + + virtual object_id_t getDeviceObjectId(); + + virtual uint8_t getSwitchId1(); + virtual uint8_t getSwitchId2(); + + bool hasTwoSwitches(); + + float getMin(); + float getMax(); + + ReturnValue_t serialize(uint8_t** buffer, size_t* size, + size_t maxSize, Endianness streamEndianness) const override; + + size_t getSerializedSize() const override; + + ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + Endianness streamEndianness) override; + + ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, + ParameterWrapper *parameterWrapper, + const ParameterWrapper *newValues, uint16_t startAtIndex); +private: + const object_id_t deviceObjectId; + const uint8_t switchId1; + const uint8_t switchId2; + + const bool doIHaveTwoSwitches; + + float min; + float max; + + uint8_t moduleId; + + PowerComponent(); +}; + +#endif /* POWERCOMPONENT_H_ */ diff --git a/power/PowerComponentIF.h b/power/PowerComponentIF.h index f2aa70ae..eeaa39fb 100644 --- a/power/PowerComponentIF.h +++ b/power/PowerComponentIF.h @@ -1,24 +1,24 @@ -#ifndef POWERCOMPONENTIF_H_ -#define POWERCOMPONENTIF_H_ - -#include -#include - -class PowerComponentIF : public SerializeIF, public HasParametersIF { -public: - virtual ~PowerComponentIF() { - - } - - virtual object_id_t getDeviceObjectId()=0; - - virtual uint8_t getSwitchId1()=0; - virtual uint8_t getSwitchId2()=0; - virtual bool hasTwoSwitches()=0; - - virtual float getMin() = 0; - virtual float getMax() = 0; - -}; - -#endif /* POWERCOMPONENTIF_H_ */ +#ifndef POWERCOMPONENTIF_H_ +#define POWERCOMPONENTIF_H_ + +#include "../serialize/SerializeIF.h" +#include "../parameters/HasParametersIF.h" + +class PowerComponentIF : public SerializeIF, public HasParametersIF { +public: + virtual ~PowerComponentIF() { + + } + + virtual object_id_t getDeviceObjectId()=0; + + virtual uint8_t getSwitchId1()=0; + virtual uint8_t getSwitchId2()=0; + virtual bool hasTwoSwitches()=0; + + virtual float getMin() = 0; + virtual float getMax() = 0; + +}; + +#endif /* POWERCOMPONENTIF_H_ */ diff --git a/power/PowerSensor.cpp b/power/PowerSensor.cpp index 5433acc9..51300db7 100644 --- a/power/PowerSensor.cpp +++ b/power/PowerSensor.cpp @@ -1,128 +1,128 @@ -#include -#include - -PowerSensor::PowerSensor(object_id_t setId, VariableIds ids, - DefaultLimits limits, SensorEvents events, uint16_t confirmationCount) : - SystemObject(setId), commandQueue(NULL), parameterHelper(this), healthHelper(this, setId), set(), current( - ids.pidCurrent, &set), voltage(ids.pidVoltage, &set), power( - ids.poolIdPower, &set, PoolVariableIF::VAR_WRITE), currentLimit( - setId, MODULE_ID_CURRENT, ids.pidCurrent, confirmationCount, - limits.currentMin, limits.currentMax, events.currentLow, - events.currentHigh), voltageLimit(setId, MODULE_ID_VOLTAGE, - ids.pidVoltage, confirmationCount, limits.voltageMin, - limits.voltageMax, events.voltageLow, events.voltageHigh) { - commandQueue = QueueFactory::instance()->createMessageQueue(); -} - -PowerSensor::~PowerSensor() { - QueueFactory::instance()->deleteMessageQueue(commandQueue); -} - -ReturnValue_t PowerSensor::calculatePower() { - set.read(); - ReturnValue_t result1 = HasReturnvaluesIF::RETURN_FAILED; - ReturnValue_t result2 = HasReturnvaluesIF::RETURN_FAILED; - if (healthHelper.healthTable->isHealthy(getObjectId()) && voltage.isValid() - && current.isValid()) { - result1 = voltageLimit.doCheck(voltage); - result2 = currentLimit.doCheck(current); - } else { - voltageLimit.setToInvalid(); - currentLimit.setToInvalid(); - result1 = OBJECT_NOT_HEALTHY; - } - if (result1 != HasReturnvaluesIF::RETURN_OK - || result2 != HasReturnvaluesIF::RETURN_OK) { - result1 = MonitoringIF::INVALID; - power.setValid(PoolVariableIF::INVALID); - } else { - power.setValid(PoolVariableIF::VALID); - power = current * voltage; - } - set.commit(); - return result1; -} - -ReturnValue_t PowerSensor::performOperation(uint8_t opCode) { - checkCommandQueue(); - return HasReturnvaluesIF::RETURN_OK; -} - -MessageQueueId_t PowerSensor::getCommandQueue() const { - return commandQueue->getId(); -} - -ReturnValue_t PowerSensor::initialize() { - ReturnValue_t result = SystemObject::initialize(); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - result = healthHelper.initialize(); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - result = parameterHelper.initialize(); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - return result; -} - -void PowerSensor::setAllMonitorsToUnchecked() { - currentLimit.setToUnchecked(); - voltageLimit.setToUnchecked(); -} - -void PowerSensor::checkCommandQueue() { - CommandMessage command; - ReturnValue_t result = commandQueue->receiveMessage(&command); - if (result != HasReturnvaluesIF::RETURN_OK) { - return; - } - result = healthHelper.handleHealthCommand(&command); - if (result == HasReturnvaluesIF::RETURN_OK) { - return; - } - result = parameterHelper.handleParameterMessage(&command); - if (result == HasReturnvaluesIF::RETURN_OK) { - return; - } - command.setToUnknownCommand(); - commandQueue->reply(&command); -} - -void PowerSensor::setDataPoolEntriesInvalid() { - set.read(); - set.commit(PoolVariableIF::INVALID); -} - -float PowerSensor::getPower() { - if (power.isValid()) { - return power.value; - } else { - return 0.0; - } - -} - -ReturnValue_t PowerSensor::setHealth(HealthState health) { - healthHelper.setHealth(health); - return HasReturnvaluesIF::RETURN_OK; -} - -HasHealthIF::HealthState PowerSensor::getHealth() { - return healthHelper.getHealth(); -} - -ReturnValue_t PowerSensor::getParameter(uint8_t domainId, uint16_t parameterId, - ParameterWrapper* parameterWrapper, const ParameterWrapper* newValues, - uint16_t startAtIndex) { - ReturnValue_t result = currentLimit.getParameter(domainId, parameterId, - parameterWrapper, newValues, startAtIndex); - if (result != INVALID_DOMAIN_ID) { - return result; - } - result = voltageLimit.getParameter(domainId, parameterId, parameterWrapper, - newValues, startAtIndex); - return result; -} +#include "../power/PowerSensor.h" +#include "../ipc/QueueFactory.h" + +PowerSensor::PowerSensor(object_id_t setId, VariableIds ids, + DefaultLimits limits, SensorEvents events, uint16_t confirmationCount) : + SystemObject(setId), commandQueue(NULL), parameterHelper(this), healthHelper(this, setId), set(), current( + ids.pidCurrent, &set), voltage(ids.pidVoltage, &set), power( + ids.poolIdPower, &set, PoolVariableIF::VAR_WRITE), currentLimit( + setId, MODULE_ID_CURRENT, ids.pidCurrent, confirmationCount, + limits.currentMin, limits.currentMax, events.currentLow, + events.currentHigh), voltageLimit(setId, MODULE_ID_VOLTAGE, + ids.pidVoltage, confirmationCount, limits.voltageMin, + limits.voltageMax, events.voltageLow, events.voltageHigh) { + commandQueue = QueueFactory::instance()->createMessageQueue(); +} + +PowerSensor::~PowerSensor() { + QueueFactory::instance()->deleteMessageQueue(commandQueue); +} + +ReturnValue_t PowerSensor::calculatePower() { + set.read(); + ReturnValue_t result1 = HasReturnvaluesIF::RETURN_FAILED; + ReturnValue_t result2 = HasReturnvaluesIF::RETURN_FAILED; + if (healthHelper.healthTable->isHealthy(getObjectId()) && voltage.isValid() + && current.isValid()) { + result1 = voltageLimit.doCheck(voltage); + result2 = currentLimit.doCheck(current); + } else { + voltageLimit.setToInvalid(); + currentLimit.setToInvalid(); + result1 = OBJECT_NOT_HEALTHY; + } + if (result1 != HasReturnvaluesIF::RETURN_OK + || result2 != HasReturnvaluesIF::RETURN_OK) { + result1 = MonitoringIF::INVALID; + power.setValid(PoolVariableIF::INVALID); + } else { + power.setValid(PoolVariableIF::VALID); + power = current * voltage; + } + set.commit(); + return result1; +} + +ReturnValue_t PowerSensor::performOperation(uint8_t opCode) { + checkCommandQueue(); + return HasReturnvaluesIF::RETURN_OK; +} + +MessageQueueId_t PowerSensor::getCommandQueue() const { + return commandQueue->getId(); +} + +ReturnValue_t PowerSensor::initialize() { + ReturnValue_t result = SystemObject::initialize(); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = healthHelper.initialize(); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = parameterHelper.initialize(); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return result; +} + +void PowerSensor::setAllMonitorsToUnchecked() { + currentLimit.setToUnchecked(); + voltageLimit.setToUnchecked(); +} + +void PowerSensor::checkCommandQueue() { + CommandMessage command; + ReturnValue_t result = commandQueue->receiveMessage(&command); + if (result != HasReturnvaluesIF::RETURN_OK) { + return; + } + result = healthHelper.handleHealthCommand(&command); + if (result == HasReturnvaluesIF::RETURN_OK) { + return; + } + result = parameterHelper.handleParameterMessage(&command); + if (result == HasReturnvaluesIF::RETURN_OK) { + return; + } + command.setToUnknownCommand(); + commandQueue->reply(&command); +} + +void PowerSensor::setDataPoolEntriesInvalid() { + set.read(); + set.commit(PoolVariableIF::INVALID); +} + +float PowerSensor::getPower() { + if (power.isValid()) { + return power.value; + } else { + return 0.0; + } + +} + +ReturnValue_t PowerSensor::setHealth(HealthState health) { + healthHelper.setHealth(health); + return HasReturnvaluesIF::RETURN_OK; +} + +HasHealthIF::HealthState PowerSensor::getHealth() { + return healthHelper.getHealth(); +} + +ReturnValue_t PowerSensor::getParameter(uint8_t domainId, uint16_t parameterId, + ParameterWrapper* parameterWrapper, const ParameterWrapper* newValues, + uint16_t startAtIndex) { + ReturnValue_t result = currentLimit.getParameter(domainId, parameterId, + parameterWrapper, newValues, startAtIndex); + if (result != INVALID_DOMAIN_ID) { + return result; + } + result = voltageLimit.getParameter(domainId, parameterId, parameterWrapper, + newValues, startAtIndex); + return result; +} diff --git a/power/PowerSensor.h b/power/PowerSensor.h index 0fb47506..dc859ab3 100644 --- a/power/PowerSensor.h +++ b/power/PowerSensor.h @@ -1,71 +1,71 @@ -#ifndef POWERSENSOR_H_ -#define POWERSENSOR_H_ - -#include -#include -#include -#include -#include -#include -#include -#include - -class PowerController; - -class PowerSensor: public SystemObject, - public ReceivesParameterMessagesIF, - public HasHealthIF { - friend class PowerController; -public: - struct VariableIds { - uint32_t pidCurrent; - uint32_t pidVoltage; - uint32_t poolIdPower; - }; - struct DefaultLimits { - float currentMin; - float currentMax; - float voltageMin; - float voltageMax; - }; - struct SensorEvents { - Event currentLow; - Event currentHigh; - Event voltageLow; - Event voltageHigh; - }; - PowerSensor(object_id_t setId, VariableIds setIds, DefaultLimits limits, - SensorEvents events, uint16_t confirmationCount = 0); - virtual ~PowerSensor(); - ReturnValue_t calculatePower(); - ReturnValue_t performOperation(uint8_t opCode); - void setAllMonitorsToUnchecked(); - MessageQueueId_t getCommandQueue() const; - ReturnValue_t initialize(); - void setDataPoolEntriesInvalid(); - float getPower(); - ReturnValue_t setHealth(HealthState health); - HasHealthIF::HealthState getHealth(); - ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, - ParameterWrapper *parameterWrapper, - const ParameterWrapper *newValues, uint16_t startAtIndex); -private: - MessageQueueIF* commandQueue; - ParameterHelper parameterHelper; - HealthHelper healthHelper; - GlobDataSet set; - //Variables in - PIDReader current; - PIDReader voltage; - //Variables out - gp_float_t power; - - static const uint8_t MODULE_ID_CURRENT = 1; - static const uint8_t MODULE_ID_VOLTAGE = 2; - void checkCommandQueue(); -protected: - LimitMonitor currentLimit; - LimitMonitor voltageLimit; -}; - -#endif /* POWERSENSOR_H_ */ +#ifndef POWERSENSOR_H_ +#define POWERSENSOR_H_ + +#include "../datapoolglob/GlobalDataSet.h" +#include "../datapoolglob/GlobalPoolVariable.h" +#include "../datapoolglob/PIDReader.h" +#include "../devicehandlers/HealthDevice.h" +#include "../monitoring/LimitMonitor.h" +#include "../parameters/ParameterHelper.h" +#include "../objectmanager/SystemObject.h" +#include "../ipc/MessageQueueIF.h" + +class PowerController; + +class PowerSensor: public SystemObject, + public ReceivesParameterMessagesIF, + public HasHealthIF { + friend class PowerController; +public: + struct VariableIds { + uint32_t pidCurrent; + uint32_t pidVoltage; + uint32_t poolIdPower; + }; + struct DefaultLimits { + float currentMin; + float currentMax; + float voltageMin; + float voltageMax; + }; + struct SensorEvents { + Event currentLow; + Event currentHigh; + Event voltageLow; + Event voltageHigh; + }; + PowerSensor(object_id_t setId, VariableIds setIds, DefaultLimits limits, + SensorEvents events, uint16_t confirmationCount = 0); + virtual ~PowerSensor(); + ReturnValue_t calculatePower(); + ReturnValue_t performOperation(uint8_t opCode); + void setAllMonitorsToUnchecked(); + MessageQueueId_t getCommandQueue() const; + ReturnValue_t initialize(); + void setDataPoolEntriesInvalid(); + float getPower(); + ReturnValue_t setHealth(HealthState health); + HasHealthIF::HealthState getHealth(); + ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, + ParameterWrapper *parameterWrapper, + const ParameterWrapper *newValues, uint16_t startAtIndex); +private: + MessageQueueIF* commandQueue; + ParameterHelper parameterHelper; + HealthHelper healthHelper; + GlobDataSet set; + //Variables in + PIDReader current; + PIDReader voltage; + //Variables out + gp_float_t power; + + static const uint8_t MODULE_ID_CURRENT = 1; + static const uint8_t MODULE_ID_VOLTAGE = 2; + void checkCommandQueue(); +protected: + LimitMonitor currentLimit; + LimitMonitor voltageLimit; +}; + +#endif /* POWERSENSOR_H_ */ diff --git a/power/PowerSwitchIF.h b/power/PowerSwitchIF.h index f25589c4..817c4ce1 100644 --- a/power/PowerSwitchIF.h +++ b/power/PowerSwitchIF.h @@ -1,80 +1,80 @@ -/** - * @file PowerSwitchIF.h - * @brief This file defines the PowerSwitchIF class. - * @date 20.03.2013 - * @author baetz - */ - -#ifndef POWERSWITCHIF_H_ -#define POWERSWITCHIF_H_ - -#include -#include -/** - * - * @brief This interface defines a connection to a device that is capable of turning on and off - * switches of devices identified by a switch ID. - * @details The virtual functions of this interface do not allow to make any assignments - * because they can be called asynchronosuly (const ending). - * - * @ingroup interfaces - */ -class PowerSwitchIF : public HasReturnvaluesIF { -public: - /** - * Empty dtor. - */ - virtual ~PowerSwitchIF() { - - } - /** - * The Returnvalues id of this class, required by HasReturnvaluesIF - */ - static const uint8_t INTERFACE_ID = CLASS_ID::POWER_SWITCH_IF; - static const ReturnValue_t SWITCH_ON = MAKE_RETURN_CODE(1); - static const ReturnValue_t SWITCH_OFF = MAKE_RETURN_CODE(0); - static const ReturnValue_t SWITCH_TIMEOUT = MAKE_RETURN_CODE(2); - static const ReturnValue_t FUSE_ON = MAKE_RETURN_CODE(3); - static const ReturnValue_t FUSE_OFF = MAKE_RETURN_CODE(4); - static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PCDU_2; - static const Event SWITCH_WENT_OFF = MAKE_EVENT(0, SEVERITY::LOW); //!< Someone detected that a switch went off which shouldn't. Severity: Low, Parameter1: switchId1, Parameter2: switchId2 - /** - * send a direct command to the Power Unit to enable/disable the specified switch. - * - * @param switchNr - * @param onOff on == @c SWITCH_ON; off != @c SWITCH_ON - */ - virtual void sendSwitchCommand(uint8_t switchNr, ReturnValue_t onOff) const = 0; - /** - * Sends a command to the Power Unit to enable a certain fuse. - */ - virtual void sendFuseOnCommand(uint8_t fuseNr) const = 0; - - /** - * get the state of the Switches. - * @param switchNr - * @return - * - @c SWITCH_ON if the specified switch is on. - * - @c SWITCH_OFF if the specified switch is off. - * - @c RETURN_FAILED if an error occured - */ - virtual ReturnValue_t getSwitchState( uint8_t switchNr ) const = 0; - /** - * get state of a fuse. - * @param fuseNr - * @return - * - @c FUSE_ON if the specified fuse is on. - * - @c FUSE_OFF if the specified fuse is off. - * - @c RETURN_FAILED if an error occured - */ - virtual ReturnValue_t getFuseState( uint8_t fuseNr ) const = 0; - /** - * The maximum delay that it will take to change a switch - * - * This may take into account the time to send a command, wait for it to be executed and see the switch changed. - */ - virtual uint32_t getSwitchDelayMs(void) const = 0; -}; - - -#endif /* POWERSWITCHIF_H_ */ +/** + * @file PowerSwitchIF.h + * @brief This file defines the PowerSwitchIF class. + * @date 20.03.2013 + * @author baetz + */ + +#ifndef POWERSWITCHIF_H_ +#define POWERSWITCHIF_H_ + +#include "../events/Event.h" +#include "../returnvalues/HasReturnvaluesIF.h" +/** + * + * @brief This interface defines a connection to a device that is capable of turning on and off + * switches of devices identified by a switch ID. + * @details The virtual functions of this interface do not allow to make any assignments + * because they can be called asynchronosuly (const ending). + * + * @ingroup interfaces + */ +class PowerSwitchIF : public HasReturnvaluesIF { +public: + /** + * Empty dtor. + */ + virtual ~PowerSwitchIF() { + + } + /** + * The Returnvalues id of this class, required by HasReturnvaluesIF + */ + static const uint8_t INTERFACE_ID = CLASS_ID::POWER_SWITCH_IF; + static const ReturnValue_t SWITCH_ON = MAKE_RETURN_CODE(1); + static const ReturnValue_t SWITCH_OFF = MAKE_RETURN_CODE(0); + static const ReturnValue_t SWITCH_TIMEOUT = MAKE_RETURN_CODE(2); + static const ReturnValue_t FUSE_ON = MAKE_RETURN_CODE(3); + static const ReturnValue_t FUSE_OFF = MAKE_RETURN_CODE(4); + static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PCDU_2; + static const Event SWITCH_WENT_OFF = MAKE_EVENT(0, SEVERITY::LOW); //!< Someone detected that a switch went off which shouldn't. Severity: Low, Parameter1: switchId1, Parameter2: switchId2 + /** + * send a direct command to the Power Unit to enable/disable the specified switch. + * + * @param switchNr + * @param onOff on == @c SWITCH_ON; off != @c SWITCH_ON + */ + virtual void sendSwitchCommand(uint8_t switchNr, ReturnValue_t onOff) const = 0; + /** + * Sends a command to the Power Unit to enable a certain fuse. + */ + virtual void sendFuseOnCommand(uint8_t fuseNr) const = 0; + + /** + * get the state of the Switches. + * @param switchNr + * @return + * - @c SWITCH_ON if the specified switch is on. + * - @c SWITCH_OFF if the specified switch is off. + * - @c RETURN_FAILED if an error occured + */ + virtual ReturnValue_t getSwitchState( uint8_t switchNr ) const = 0; + /** + * get state of a fuse. + * @param fuseNr + * @return + * - @c FUSE_ON if the specified fuse is on. + * - @c FUSE_OFF if the specified fuse is off. + * - @c RETURN_FAILED if an error occured + */ + virtual ReturnValue_t getFuseState( uint8_t fuseNr ) const = 0; + /** + * The maximum delay that it will take to change a switch + * + * This may take into account the time to send a command, wait for it to be executed and see the switch changed. + */ + virtual uint32_t getSwitchDelayMs(void) const = 0; +}; + + +#endif /* POWERSWITCHIF_H_ */ diff --git a/power/PowerSwitcher.cpp b/power/PowerSwitcher.cpp index 6b06bf73..73d9f89b 100644 --- a/power/PowerSwitcher.cpp +++ b/power/PowerSwitcher.cpp @@ -1,127 +1,127 @@ -#include -#include -#include - -PowerSwitcher::PowerSwitcher(uint8_t setSwitch1, uint8_t setSwitch2, - PowerSwitcher::State_t setStartState) : - state(setStartState), firstSwitch(setSwitch1), secondSwitch(setSwitch2), power(NULL) { -} - -ReturnValue_t PowerSwitcher::initialize(object_id_t powerSwitchId) { - power = objectManager->get(powerSwitchId); - if (power == NULL) { - return HasReturnvaluesIF::RETURN_FAILED; - } - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t PowerSwitcher::getStateOfSwitches() { - SwitchReturn_t result = howManySwitches(); - switch (result) { - case ONE_SWITCH: - return power->getSwitchState(firstSwitch); - case TWO_SWITCHES: - if ((power->getSwitchState(firstSwitch) == PowerSwitchIF::SWITCH_ON) - && (power->getSwitchState(secondSwitch) == PowerSwitchIF::SWITCH_ON)) { - return PowerSwitchIF::SWITCH_ON; - } else if ((power->getSwitchState(firstSwitch) == PowerSwitchIF::SWITCH_OFF) - && (power->getSwitchState(secondSwitch) == PowerSwitchIF::SWITCH_OFF)) { - return PowerSwitchIF::SWITCH_OFF; - } else { - return HasReturnvaluesIF::RETURN_FAILED; - } - default: - return HasReturnvaluesIF::RETURN_FAILED; - } -} - -void PowerSwitcher::commandSwitches(ReturnValue_t onOff) { - SwitchReturn_t result = howManySwitches(); - switch (result) { - case TWO_SWITCHES: - power->sendSwitchCommand(secondSwitch, onOff); - /* NO BREAK falls through*/ - case ONE_SWITCH: - power->sendSwitchCommand(firstSwitch, onOff); - break; - } - return; - -} - -void PowerSwitcher::turnOn() { - commandSwitches(PowerSwitchIF::SWITCH_ON); - state = WAIT_ON; -} - -void PowerSwitcher::turnOff() { - commandSwitches(PowerSwitchIF::SWITCH_OFF); - state = WAIT_OFF; -} - -PowerSwitcher::SwitchReturn_t PowerSwitcher::howManySwitches() { - if (secondSwitch == NO_SWITCH) { - return ONE_SWITCH; - } else { - return TWO_SWITCHES; - } -} - -void PowerSwitcher::doStateMachine() { - switch (state) { - case SWITCH_IS_OFF: - case SWITCH_IS_ON: - //Do nothing. - break; - case WAIT_OFF: - if (getStateOfSwitches() == PowerSwitchIF::SWITCH_OFF) { - state = SWITCH_IS_OFF; - } - break; - case WAIT_ON: - if (getStateOfSwitches() == PowerSwitchIF::SWITCH_ON) { - state = SWITCH_IS_ON; - } - break; - default: - //Should never happen. - break; - } -} - -ReturnValue_t PowerSwitcher::checkSwitchState() { - switch (state) { - case WAIT_OFF: - case WAIT_ON: - return IN_POWER_TRANSITION; - case SWITCH_IS_OFF: - if (getStateOfSwitches() == PowerSwitchIF::SWITCH_OFF) { - return RETURN_OK; - } else { - return SWITCH_STATE_MISMATCH; - } - case SWITCH_IS_ON: - if (getStateOfSwitches() == PowerSwitchIF::SWITCH_ON) { - return RETURN_OK; - } else { - return SWITCH_STATE_MISMATCH; - } - } - return RETURN_FAILED; -} - -PowerSwitcher::State_t PowerSwitcher::getState() { - return state; -} - -uint32_t PowerSwitcher::getSwitchDelay() { - return power->getSwitchDelayMs(); -} - -uint8_t PowerSwitcher::getFirstSwitch() const { - return firstSwitch; -} - -uint8_t PowerSwitcher::getSecondSwitch() const { - return secondSwitch; -} +#include "../objectmanager/ObjectManagerIF.h" +#include "../power/PowerSwitcher.h" +#include "../serviceinterface/ServiceInterfaceStream.h" + +PowerSwitcher::PowerSwitcher(uint8_t setSwitch1, uint8_t setSwitch2, + PowerSwitcher::State_t setStartState) : + state(setStartState), firstSwitch(setSwitch1), secondSwitch(setSwitch2), power(NULL) { +} + +ReturnValue_t PowerSwitcher::initialize(object_id_t powerSwitchId) { + power = objectManager->get(powerSwitchId); + if (power == NULL) { + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t PowerSwitcher::getStateOfSwitches() { + SwitchReturn_t result = howManySwitches(); + switch (result) { + case ONE_SWITCH: + return power->getSwitchState(firstSwitch); + case TWO_SWITCHES: + if ((power->getSwitchState(firstSwitch) == PowerSwitchIF::SWITCH_ON) + && (power->getSwitchState(secondSwitch) == PowerSwitchIF::SWITCH_ON)) { + return PowerSwitchIF::SWITCH_ON; + } else if ((power->getSwitchState(firstSwitch) == PowerSwitchIF::SWITCH_OFF) + && (power->getSwitchState(secondSwitch) == PowerSwitchIF::SWITCH_OFF)) { + return PowerSwitchIF::SWITCH_OFF; + } else { + return HasReturnvaluesIF::RETURN_FAILED; + } + default: + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +void PowerSwitcher::commandSwitches(ReturnValue_t onOff) { + SwitchReturn_t result = howManySwitches(); + switch (result) { + case TWO_SWITCHES: + power->sendSwitchCommand(secondSwitch, onOff); + /* NO BREAK falls through*/ + case ONE_SWITCH: + power->sendSwitchCommand(firstSwitch, onOff); + break; + } + return; + +} + +void PowerSwitcher::turnOn() { + commandSwitches(PowerSwitchIF::SWITCH_ON); + state = WAIT_ON; +} + +void PowerSwitcher::turnOff() { + commandSwitches(PowerSwitchIF::SWITCH_OFF); + state = WAIT_OFF; +} + +PowerSwitcher::SwitchReturn_t PowerSwitcher::howManySwitches() { + if (secondSwitch == NO_SWITCH) { + return ONE_SWITCH; + } else { + return TWO_SWITCHES; + } +} + +void PowerSwitcher::doStateMachine() { + switch (state) { + case SWITCH_IS_OFF: + case SWITCH_IS_ON: + //Do nothing. + break; + case WAIT_OFF: + if (getStateOfSwitches() == PowerSwitchIF::SWITCH_OFF) { + state = SWITCH_IS_OFF; + } + break; + case WAIT_ON: + if (getStateOfSwitches() == PowerSwitchIF::SWITCH_ON) { + state = SWITCH_IS_ON; + } + break; + default: + //Should never happen. + break; + } +} + +ReturnValue_t PowerSwitcher::checkSwitchState() { + switch (state) { + case WAIT_OFF: + case WAIT_ON: + return IN_POWER_TRANSITION; + case SWITCH_IS_OFF: + if (getStateOfSwitches() == PowerSwitchIF::SWITCH_OFF) { + return RETURN_OK; + } else { + return SWITCH_STATE_MISMATCH; + } + case SWITCH_IS_ON: + if (getStateOfSwitches() == PowerSwitchIF::SWITCH_ON) { + return RETURN_OK; + } else { + return SWITCH_STATE_MISMATCH; + } + } + return RETURN_FAILED; +} + +PowerSwitcher::State_t PowerSwitcher::getState() { + return state; +} + +uint32_t PowerSwitcher::getSwitchDelay() { + return power->getSwitchDelayMs(); +} + +uint8_t PowerSwitcher::getFirstSwitch() const { + return firstSwitch; +} + +uint8_t PowerSwitcher::getSecondSwitch() const { + return secondSwitch; +} diff --git a/power/PowerSwitcher.h b/power/PowerSwitcher.h index 5b2789e9..39f44f50 100644 --- a/power/PowerSwitcher.h +++ b/power/PowerSwitcher.h @@ -1,45 +1,45 @@ -#ifndef POWERSWITCHER_H_ -#define POWERSWITCHER_H_ -#include -#include -#include - -class PowerSwitcher : public HasReturnvaluesIF { -public: - enum State_t { - WAIT_OFF, - WAIT_ON, - SWITCH_IS_OFF, - SWITCH_IS_ON, - }; - State_t state; - static const uint8_t INTERFACE_ID = CLASS_ID::POWER_SWITCHER; - static const ReturnValue_t IN_POWER_TRANSITION = MAKE_RETURN_CODE(1); - static const ReturnValue_t SWITCH_STATE_MISMATCH = MAKE_RETURN_CODE(2); - PowerSwitcher( uint8_t setSwitch1, uint8_t setSwitch2 = NO_SWITCH, State_t setStartState = SWITCH_IS_OFF ); - ReturnValue_t initialize(object_id_t powerSwitchId); - void turnOn(); - void turnOff(); - void doStateMachine(); - State_t getState(); - ReturnValue_t checkSwitchState(); - uint32_t getSwitchDelay(); - uint8_t getFirstSwitch() const; - uint8_t getSecondSwitch() const; -private: - uint8_t firstSwitch; - uint8_t secondSwitch; - PowerSwitchIF* power; - static const uint8_t NO_SWITCH = 0xFF; - enum SwitchReturn_t { - ONE_SWITCH = 1, - TWO_SWITCHES = 2 - }; - ReturnValue_t getStateOfSwitches(); - void commandSwitches( ReturnValue_t onOff ); - SwitchReturn_t howManySwitches(); -}; - - - -#endif /* POWERSWITCHER_H_ */ +#ifndef POWERSWITCHER_H_ +#define POWERSWITCHER_H_ +#include "../power/PowerSwitchIF.h" +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../timemanager/Countdown.h" + +class PowerSwitcher : public HasReturnvaluesIF { +public: + enum State_t { + WAIT_OFF, + WAIT_ON, + SWITCH_IS_OFF, + SWITCH_IS_ON, + }; + State_t state; + static const uint8_t INTERFACE_ID = CLASS_ID::POWER_SWITCHER; + static const ReturnValue_t IN_POWER_TRANSITION = MAKE_RETURN_CODE(1); + static const ReturnValue_t SWITCH_STATE_MISMATCH = MAKE_RETURN_CODE(2); + PowerSwitcher( uint8_t setSwitch1, uint8_t setSwitch2 = NO_SWITCH, State_t setStartState = SWITCH_IS_OFF ); + ReturnValue_t initialize(object_id_t powerSwitchId); + void turnOn(); + void turnOff(); + void doStateMachine(); + State_t getState(); + ReturnValue_t checkSwitchState(); + uint32_t getSwitchDelay(); + uint8_t getFirstSwitch() const; + uint8_t getSecondSwitch() const; +private: + uint8_t firstSwitch; + uint8_t secondSwitch; + PowerSwitchIF* power; + static const uint8_t NO_SWITCH = 0xFF; + enum SwitchReturn_t { + ONE_SWITCH = 1, + TWO_SWITCHES = 2 + }; + ReturnValue_t getStateOfSwitches(); + void commandSwitches( ReturnValue_t onOff ); + SwitchReturn_t howManySwitches(); +}; + + + +#endif /* POWERSWITCHER_H_ */ diff --git a/pus/CService200ModeCommanding.cpp b/pus/CService200ModeCommanding.cpp index fd6da67e..8a51469f 100644 --- a/pus/CService200ModeCommanding.cpp +++ b/pus/CService200ModeCommanding.cpp @@ -1,10 +1,10 @@ -#include -#include +#include "../pus/CService200ModeCommanding.h" +#include "../pus/servicepackets/Service200Packets.h" -#include -#include -#include -#include +#include "../modes/HasModesIF.h" +#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../serialize/SerialLinkedListAdapter.h" +#include "../modes/ModeMessage.h" CService200ModeCommanding::CService200ModeCommanding(object_id_t objectId, uint16_t apid, uint8_t serviceId): diff --git a/pus/CService200ModeCommanding.h b/pus/CService200ModeCommanding.h index ede61a84..dfb4dfa6 100644 --- a/pus/CService200ModeCommanding.h +++ b/pus/CService200ModeCommanding.h @@ -1,7 +1,7 @@ #ifndef FRAMEWORK_PUS_CSERVICE200MODECOMMANDING_H_ #define FRAMEWORK_PUS_CSERVICE200MODECOMMANDING_H_ -#include +#include "../tmtcservices/CommandingServiceBase.h" /** * @brief Custom PUS service to set mode of all objects implementing HasModesIF diff --git a/pus/Service1TelecommandVerification.cpp b/pus/Service1TelecommandVerification.cpp index 4ce2ce54..f6cbf6bf 100644 --- a/pus/Service1TelecommandVerification.cpp +++ b/pus/Service1TelecommandVerification.cpp @@ -1,100 +1,100 @@ -#include -#include - -#include -#include -#include -#include -#include -#include - - -Service1TelecommandVerification::Service1TelecommandVerification( - object_id_t objectId, uint16_t apid, uint8_t serviceId, - object_id_t targetDestination): - SystemObject(objectId), apid(apid), serviceId(serviceId), - targetDestination(targetDestination) { - tmQueue = QueueFactory::instance()->createMessageQueue(); -} - -Service1TelecommandVerification::~Service1TelecommandVerification() {} - -MessageQueueId_t Service1TelecommandVerification::getVerificationQueue(){ - return tmQueue->getId(); -} - - -ReturnValue_t Service1TelecommandVerification::performOperation( - uint8_t operationCode){ - PusVerificationMessage message; - ReturnValue_t status = tmQueue->receiveMessage(&message); - while(status == HasReturnvaluesIF::RETURN_OK) { - status = sendVerificationReport(&message); - if(status != HasReturnvaluesIF::RETURN_OK) { - return status; - } - status = tmQueue->receiveMessage(&message); - } - if (status == MessageQueueIF::EMPTY) { - return HasReturnvaluesIF::RETURN_OK; - } - else { - return status; - } -} - - -ReturnValue_t Service1TelecommandVerification::sendVerificationReport( - PusVerificationMessage* message) { - ReturnValue_t result; - if(message->getReportId() % 2 == 0) { - result = generateFailureReport(message); - } else { - result = generateSuccessReport(message); - } - if(result != HasReturnvaluesIF::RETURN_OK){ - sif::error << "Service1TelecommandVerification::initialize: " - "Sending verification packet failed !" << std::endl; - } - return result; -} - -ReturnValue_t Service1TelecommandVerification::generateFailureReport( - PusVerificationMessage *message) { - FailureReport report( - message->getReportId(), message->getTcPacketId(), - message->getTcSequenceControl(), message->getStep(), - message->getErrorCode(), message->getParameter1(), - message->getParameter2()); - TmPacketStored tmPacket(apid, serviceId, message->getReportId(), - packetSubCounter++, &report); - ReturnValue_t result = tmPacket.sendPacket(tmQueue->getDefaultDestination(), - tmQueue->getId()); - return result; -} - -ReturnValue_t Service1TelecommandVerification::generateSuccessReport( - PusVerificationMessage *message) { - SuccessReport report(message->getReportId(),message->getTcPacketId(), - message->getTcSequenceControl(),message->getStep()); - TmPacketStored tmPacket(apid, serviceId, message->getReportId(), - packetSubCounter++, &report); - ReturnValue_t result = tmPacket.sendPacket(tmQueue->getDefaultDestination(), - tmQueue->getId()); - return result; -} - - -ReturnValue_t Service1TelecommandVerification::initialize() { - // Get target object for TC verification messages - AcceptsTelemetryIF* funnel = objectManager-> - get(targetDestination); - if(funnel == nullptr){ - sif::error << "Service1TelecommandVerification::initialize: Specified" - " TM funnel invalid. Make sure it is set up and implements" - " AcceptsTelemetryIF." << std::endl; - return ObjectManagerIF::CHILD_INIT_FAILED; - } - tmQueue->setDefaultDestination(funnel->getReportReceptionQueue()); - return SystemObject::initialize(); -} +#include "../pus/Service1TelecommandVerification.h" +#include "../pus/servicepackets/Service1Packets.h" + +#include "../ipc/QueueFactory.h" +#include "../tmtcservices/PusVerificationReport.h" +#include "../tmtcpacket/pus/TmPacketStored.h" +#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../tmtcservices/AcceptsTelemetryIF.h" +#include "../serviceinterface/ServiceInterfaceStream.h" + + +Service1TelecommandVerification::Service1TelecommandVerification( + object_id_t objectId, uint16_t apid, uint8_t serviceId, + object_id_t targetDestination): + SystemObject(objectId), apid(apid), serviceId(serviceId), + targetDestination(targetDestination) { + tmQueue = QueueFactory::instance()->createMessageQueue(); +} + +Service1TelecommandVerification::~Service1TelecommandVerification() {} + +MessageQueueId_t Service1TelecommandVerification::getVerificationQueue(){ + return tmQueue->getId(); +} + + +ReturnValue_t Service1TelecommandVerification::performOperation( + uint8_t operationCode){ + PusVerificationMessage message; + ReturnValue_t status = tmQueue->receiveMessage(&message); + while(status == HasReturnvaluesIF::RETURN_OK) { + status = sendVerificationReport(&message); + if(status != HasReturnvaluesIF::RETURN_OK) { + return status; + } + status = tmQueue->receiveMessage(&message); + } + if (status == MessageQueueIF::EMPTY) { + return HasReturnvaluesIF::RETURN_OK; + } + else { + return status; + } +} + + +ReturnValue_t Service1TelecommandVerification::sendVerificationReport( + PusVerificationMessage* message) { + ReturnValue_t result; + if(message->getReportId() % 2 == 0) { + result = generateFailureReport(message); + } else { + result = generateSuccessReport(message); + } + if(result != HasReturnvaluesIF::RETURN_OK){ + sif::error << "Service1TelecommandVerification::initialize: " + "Sending verification packet failed !" << std::endl; + } + return result; +} + +ReturnValue_t Service1TelecommandVerification::generateFailureReport( + PusVerificationMessage *message) { + FailureReport report( + message->getReportId(), message->getTcPacketId(), + message->getTcSequenceControl(), message->getStep(), + message->getErrorCode(), message->getParameter1(), + message->getParameter2()); + TmPacketStored tmPacket(apid, serviceId, message->getReportId(), + packetSubCounter++, &report); + ReturnValue_t result = tmPacket.sendPacket(tmQueue->getDefaultDestination(), + tmQueue->getId()); + return result; +} + +ReturnValue_t Service1TelecommandVerification::generateSuccessReport( + PusVerificationMessage *message) { + SuccessReport report(message->getReportId(),message->getTcPacketId(), + message->getTcSequenceControl(),message->getStep()); + TmPacketStored tmPacket(apid, serviceId, message->getReportId(), + packetSubCounter++, &report); + ReturnValue_t result = tmPacket.sendPacket(tmQueue->getDefaultDestination(), + tmQueue->getId()); + return result; +} + + +ReturnValue_t Service1TelecommandVerification::initialize() { + // Get target object for TC verification messages + AcceptsTelemetryIF* funnel = objectManager-> + get(targetDestination); + if(funnel == nullptr){ + sif::error << "Service1TelecommandVerification::initialize: Specified" + " TM funnel invalid. Make sure it is set up and implements" + " AcceptsTelemetryIF." << std::endl; + return ObjectManagerIF::CHILD_INIT_FAILED; + } + tmQueue->setDefaultDestination(funnel->getReportReceptionQueue()); + return SystemObject::initialize(); +} diff --git a/pus/Service1TelecommandVerification.h b/pus/Service1TelecommandVerification.h index 1d4b6719..91275cfb 100644 --- a/pus/Service1TelecommandVerification.h +++ b/pus/Service1TelecommandVerification.h @@ -1,94 +1,94 @@ -#ifndef MISSION_PUS_SERVICE1TELECOMMANDVERIFICATION_H_ -#define MISSION_PUS_SERVICE1TELECOMMANDVERIFICATION_H_ - -#include -#include -#include -#include -#include -#include - -/** - * @brief Verify TC acceptance, start, progress and execution. - * - * Full Documentation: ECSS-E70-41A p.51 - * - * The telecommand verification service provides the capability for - * explicit verification of each distinct stage of execution of a telecommand - * packet, from on-board acceptance through to completion of execution. - * - * Minimum capabilities of this service: - * - * - TM[1,1]: Telecommand Acceptance Report - Success. - * - TM[1,2]: Telecommand Acceptance Report - Failure. - * - * Additional capabilities of this service: - * - * - TM[1,3]: Telecommand Execution Started Report - Success (Req. 4). - * - TM[1,4]: Telecommand Execution Started Report - Failure (Req. 3). - * - TM[1,5]: Telecommand Execution Progress Report - Success (Req. 6). - * - TM[1,6]: Telecommand Execution Progress Report - Failure (Req. 5). - * - TM[1,7]: Telecommand Execution Completed Report - Success (Req. 8). - * - TM[1,8]: Telecommand Execution Completed Report - Failure (Req. 7). - * - * This Service is not inherited from PUSServiceBase unlike other PUS Services - * because all services implementing PUSServiceBase use this service to - * generate verification reports. - * @ingroup pus_services - */ -class Service1TelecommandVerification: public AcceptsVerifyMessageIF, - public SystemObject, - public ExecutableObjectIF, - public HasReturnvaluesIF { -public: - static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PUS_SERVICE_1; - - Service1TelecommandVerification(object_id_t objectId, - uint16_t apid, uint8_t serviceId, object_id_t targetDestination); - virtual ~Service1TelecommandVerification(); - - /** - * - * @return ID of Verification Queue - */ - virtual MessageQueueId_t getVerificationQueue(); - - /** - * Performs the service periodically as specified in init_mission(). - * Triggers the handlePacket function to send TC verification messages - * @param operationCode - * @return - */ - ReturnValue_t performOperation(uint8_t operationCode = 0) override; - - /** - * Initializes the destination for TC verification messages and initializes - * Service 1 as a system object - * @return - */ - ReturnValue_t initialize() override; -private: - uint16_t apid = 0; - uint8_t serviceId = 0; - - object_id_t targetDestination = objects::NO_OBJECT; - - ReturnValue_t sendVerificationReport(PusVerificationMessage* message); - ReturnValue_t generateFailureReport(PusVerificationMessage* message); - ReturnValue_t generateSuccessReport(PusVerificationMessage* message); - - uint16_t packetSubCounter = 0; - - MessageQueueIF* tmQueue = nullptr; - - enum class Subservice: uint8_t { - VERIFY_ACCEPTANCE_SUCCESS = 1, //!< [EXPORT] : [TM] - VERIFY_ACCEPTANCE_FAILED = 2, //!< [EXPORT] : [TM] - VERIFY_START_SUCCESS = 3, //!< [EXPORT] : [TM] - VERIFY_START_FAILED = 4, //!< [EXPORT] : [TM] - VERIFY_STEP_SUCCESS = 5, //!< [EXPORT] : [TM] - VERIFY_STEP_FAILED = 6 //!< [EXPORT] : [TM] - }; -}; - -#endif /* MISSION_PUS_SERVICE1TELECOMMANDVERIFICATION_H_ */ +#ifndef MISSION_PUS_SERVICE1TELECOMMANDVERIFICATION_H_ +#define MISSION_PUS_SERVICE1TELECOMMANDVERIFICATION_H_ + +#include "../objectmanager/SystemObject.h" +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../tasks/ExecutableObjectIF.h" +#include "../tmtcservices/AcceptsVerifyMessageIF.h" +#include "../tmtcservices/PusVerificationReport.h" +#include "../ipc/MessageQueueIF.h" + +/** + * @brief Verify TC acceptance, start, progress and execution. + * + * Full Documentation: ECSS-E70-41A p.51 + * + * The telecommand verification service provides the capability for + * explicit verification of each distinct stage of execution of a telecommand + * packet, from on-board acceptance through to completion of execution. + * + * Minimum capabilities of this service: + * + * - TM[1,1]: Telecommand Acceptance Report - Success. + * - TM[1,2]: Telecommand Acceptance Report - Failure. + * + * Additional capabilities of this service: + * + * - TM[1,3]: Telecommand Execution Started Report - Success (Req. 4). + * - TM[1,4]: Telecommand Execution Started Report - Failure (Req. 3). + * - TM[1,5]: Telecommand Execution Progress Report - Success (Req. 6). + * - TM[1,6]: Telecommand Execution Progress Report - Failure (Req. 5). + * - TM[1,7]: Telecommand Execution Completed Report - Success (Req. 8). + * - TM[1,8]: Telecommand Execution Completed Report - Failure (Req. 7). + * + * This Service is not inherited from PUSServiceBase unlike other PUS Services + * because all services implementing PUSServiceBase use this service to + * generate verification reports. + * @ingroup pus_services + */ +class Service1TelecommandVerification: public AcceptsVerifyMessageIF, + public SystemObject, + public ExecutableObjectIF, + public HasReturnvaluesIF { +public: + static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PUS_SERVICE_1; + + Service1TelecommandVerification(object_id_t objectId, + uint16_t apid, uint8_t serviceId, object_id_t targetDestination); + virtual ~Service1TelecommandVerification(); + + /** + * + * @return ID of Verification Queue + */ + virtual MessageQueueId_t getVerificationQueue(); + + /** + * Performs the service periodically as specified in init_mission(). + * Triggers the handlePacket function to send TC verification messages + * @param operationCode + * @return + */ + ReturnValue_t performOperation(uint8_t operationCode = 0) override; + + /** + * Initializes the destination for TC verification messages and initializes + * Service 1 as a system object + * @return + */ + ReturnValue_t initialize() override; +private: + uint16_t apid = 0; + uint8_t serviceId = 0; + + object_id_t targetDestination = objects::NO_OBJECT; + + ReturnValue_t sendVerificationReport(PusVerificationMessage* message); + ReturnValue_t generateFailureReport(PusVerificationMessage* message); + ReturnValue_t generateSuccessReport(PusVerificationMessage* message); + + uint16_t packetSubCounter = 0; + + MessageQueueIF* tmQueue = nullptr; + + enum class Subservice: uint8_t { + VERIFY_ACCEPTANCE_SUCCESS = 1, //!< [EXPORT] : [TM] + VERIFY_ACCEPTANCE_FAILED = 2, //!< [EXPORT] : [TM] + VERIFY_START_SUCCESS = 3, //!< [EXPORT] : [TM] + VERIFY_START_FAILED = 4, //!< [EXPORT] : [TM] + VERIFY_STEP_SUCCESS = 5, //!< [EXPORT] : [TM] + VERIFY_STEP_FAILED = 6 //!< [EXPORT] : [TM] + }; +}; + +#endif /* MISSION_PUS_SERVICE1TELECOMMANDVERIFICATION_H_ */ diff --git a/pus/Service2DeviceAccess.cpp b/pus/Service2DeviceAccess.cpp index 84d6693d..26639de6 100644 --- a/pus/Service2DeviceAccess.cpp +++ b/pus/Service2DeviceAccess.cpp @@ -1,14 +1,14 @@ -#include -#include +#include "../pus/Service2DeviceAccess.h" +#include "../pus/servicepackets/Service2Packets.h" -#include -#include -#include -#include -#include -#include -#include -#include +#include "../devicehandlers/DeviceHandlerIF.h" +#include "../storagemanager/StorageManagerIF.h" +#include "../devicehandlers/DeviceHandlerMessage.h" +#include "../serialize/EndianConverter.h" +#include "../action/ActionMessage.h" +#include "../serialize/SerializeAdapter.h" +#include "../serialize/SerialLinkedListAdapter.h" +#include "../serviceinterface/ServiceInterfaceStream.h" Service2DeviceAccess::Service2DeviceAccess(object_id_t objectId, uint16_t apid, uint8_t serviceId, uint8_t numberOfParallelCommands, diff --git a/pus/Service2DeviceAccess.h b/pus/Service2DeviceAccess.h index 1a0bede0..3fb9e830 100644 --- a/pus/Service2DeviceAccess.h +++ b/pus/Service2DeviceAccess.h @@ -1,9 +1,9 @@ #ifndef FRAMEWORK_PUS_SERVICE2DEVICEACCESS_H_ #define FRAMEWORK_PUS_SERVICE2DEVICEACCESS_H_ -#include -#include -#include +#include "../objectmanager/SystemObjectIF.h" +#include "../devicehandlers/AcceptsDeviceResponsesIF.h" +#include "../tmtcservices/CommandingServiceBase.h" /** * @brief Raw Commanding and Wiretapping of devices. diff --git a/pus/Service5EventReporting.cpp b/pus/Service5EventReporting.cpp index 1dfbe229..5343b318 100644 --- a/pus/Service5EventReporting.cpp +++ b/pus/Service5EventReporting.cpp @@ -1,91 +1,91 @@ -#include -#include - -#include -#include -#include -#include - - -Service5EventReporting::Service5EventReporting(object_id_t objectId, - uint16_t apid, uint8_t serviceId, size_t maxNumberReportsPerCycle): - PusServiceBase(objectId, apid, serviceId), - maxNumberReportsPerCycle(maxNumberReportsPerCycle) { - eventQueue = QueueFactory::instance()->createMessageQueue(); -} - -Service5EventReporting::~Service5EventReporting(){} - -ReturnValue_t Service5EventReporting::performService() { - EventMessage message; - ReturnValue_t status = RETURN_OK; - for(uint8_t counter = 0; - counter < maxNumberReportsPerCycle; - counter++) - { - // Receive messages even if reporting is disabled for now. - status = eventQueue->receiveMessage(&message); - if(status == MessageQueueIF::EMPTY) { - return HasReturnvaluesIF::RETURN_OK; - } - - if(enableEventReport) { - status = generateEventReport(message); - if(status != HasReturnvaluesIF::RETURN_OK) { - return status; - } - } - } - sif::debug << "Service5EventReporting::generateEventReport:" - " Too many events" << std::endl; - return HasReturnvaluesIF::RETURN_OK; -} - - -ReturnValue_t Service5EventReporting::generateEventReport( - EventMessage message) -{ - EventReport report(message.getEventId(),message.getReporter(), - message.getParameter1(),message.getParameter2()); - TmPacketStored tmPacket(PusServiceBase::apid, PusServiceBase::serviceId, - message.getSeverity(), packetSubCounter++, &report); - ReturnValue_t result = tmPacket.sendPacket( - requestQueue->getDefaultDestination(),requestQueue->getId()); - if(result != HasReturnvaluesIF::RETURN_OK) { - sif::debug << "Service5EventReporting::generateEventReport:" - " Could not send TM packet" << std::endl; - } - return result; -} - -ReturnValue_t Service5EventReporting::handleRequest(uint8_t subservice) { - switch(subservice) { - case Subservice::ENABLE: { - enableEventReport = true; - return HasReturnvaluesIF::RETURN_OK; - } - case Subservice::DISABLE: { - enableEventReport = false; - return HasReturnvaluesIF::RETURN_OK; - } - default: - return AcceptsTelecommandsIF::INVALID_SUBSERVICE; - } -} - - -// In addition to the default PUSServiceBase initialization, this service needs -// to be registered to the event manager to listen for events. -ReturnValue_t Service5EventReporting::initialize() { - EventManagerIF* manager = objectManager->get( - objects::EVENT_MANAGER); - if (manager == NULL) { - return RETURN_FAILED; - } - // register Service 5 as listener for events - ReturnValue_t result = manager->registerListener(eventQueue->getId(),true); - if(result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - return PusServiceBase::initialize(); -} +#include "../pus/Service5EventReporting.h" +#include "../pus/servicepackets/Service5Packets.h" + +#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../events/EventManagerIF.h" +#include "../ipc/QueueFactory.h" +#include "../tmtcpacket/pus/TmPacketStored.h" + + +Service5EventReporting::Service5EventReporting(object_id_t objectId, + uint16_t apid, uint8_t serviceId, size_t maxNumberReportsPerCycle): + PusServiceBase(objectId, apid, serviceId), + maxNumberReportsPerCycle(maxNumberReportsPerCycle) { + eventQueue = QueueFactory::instance()->createMessageQueue(); +} + +Service5EventReporting::~Service5EventReporting(){} + +ReturnValue_t Service5EventReporting::performService() { + EventMessage message; + ReturnValue_t status = RETURN_OK; + for(uint8_t counter = 0; + counter < maxNumberReportsPerCycle; + counter++) + { + // Receive messages even if reporting is disabled for now. + status = eventQueue->receiveMessage(&message); + if(status == MessageQueueIF::EMPTY) { + return HasReturnvaluesIF::RETURN_OK; + } + + if(enableEventReport) { + status = generateEventReport(message); + if(status != HasReturnvaluesIF::RETURN_OK) { + return status; + } + } + } + sif::debug << "Service5EventReporting::generateEventReport:" + " Too many events" << std::endl; + return HasReturnvaluesIF::RETURN_OK; +} + + +ReturnValue_t Service5EventReporting::generateEventReport( + EventMessage message) +{ + EventReport report(message.getEventId(),message.getReporter(), + message.getParameter1(),message.getParameter2()); + TmPacketStored tmPacket(PusServiceBase::apid, PusServiceBase::serviceId, + message.getSeverity(), packetSubCounter++, &report); + ReturnValue_t result = tmPacket.sendPacket( + requestQueue->getDefaultDestination(),requestQueue->getId()); + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::debug << "Service5EventReporting::generateEventReport:" + " Could not send TM packet" << std::endl; + } + return result; +} + +ReturnValue_t Service5EventReporting::handleRequest(uint8_t subservice) { + switch(subservice) { + case Subservice::ENABLE: { + enableEventReport = true; + return HasReturnvaluesIF::RETURN_OK; + } + case Subservice::DISABLE: { + enableEventReport = false; + return HasReturnvaluesIF::RETURN_OK; + } + default: + return AcceptsTelecommandsIF::INVALID_SUBSERVICE; + } +} + + +// In addition to the default PUSServiceBase initialization, this service needs +// to be registered to the event manager to listen for events. +ReturnValue_t Service5EventReporting::initialize() { + EventManagerIF* manager = objectManager->get( + objects::EVENT_MANAGER); + if (manager == NULL) { + return RETURN_FAILED; + } + // register Service 5 as listener for events + ReturnValue_t result = manager->registerListener(eventQueue->getId(),true); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return PusServiceBase::initialize(); +} diff --git a/pus/Service5EventReporting.h b/pus/Service5EventReporting.h index 79b7c5e7..3f0c8cdf 100644 --- a/pus/Service5EventReporting.h +++ b/pus/Service5EventReporting.h @@ -1,86 +1,86 @@ -#ifndef FRAMEWORK_PUS_SERVICE5EVENTREPORTING_H_ -#define FRAMEWORK_PUS_SERVICE5EVENTREPORTING_H_ - -#include -#include - -/** - * @brief Report on-board events like information or errors - * @details - * Full Documentation: ECSS-E70-41A p.79 - * Implements the PusServiceBase template class. - * Documentation: Dissertation Baetz p.135,136 - * - * This service provides for the reporting to the service user of information of - * operational significance. - * 1. reporting of failures or anomalies detected on-board; - * 2. reporting of autonomous on-board actions; - * 3. reporting of normal progress of operations and activities, e.g. - * detection of events which are not anomalous (such as payload events), - * reaching of predefined steps in an operation. Some reports can combine - * more than one of these events. - * - * Minimum capabilities of this service: - * - * - TM[5,1]: Normal/Progress Report - * - TM[5,2]: Error/Anomaly Report - Low Severity - * - TM[5,3]: Error/Anomaly Report - Medium Severity - * - TM[5,4]: Error/Anomaly Report - High Severity - * - * Events can be translated by using translator files located in - * /config/objects/ and /config/events/. Description to events can be added by - * adding a comment behind the event definition with [//!<] as leading string - * - * Additional capabilities of this service: - * - * - TC[5,5]: Enable Event Report Generation (Req. 6) - * - TC[5,6]: Disable Event Report Generation (Req. 5) - * @author R. Mueller - * @ingroup pus_services - */ -class Service5EventReporting: public PusServiceBase { -public: - - Service5EventReporting(object_id_t objectId, uint16_t apid, - uint8_t serviceId, size_t maxNumberReportsPerCycle = 10); - virtual ~Service5EventReporting(); - - /*** - * Check for events and generate event reports if required. - * @return - */ - ReturnValue_t performService() override; - - /*** - * Turn event generation on or off. - * @return - */ - ReturnValue_t handleRequest(uint8_t subservice) override; - - /** - * The default PusServiceBase initialize has been overridden but is still - * executed. Registers this service as a listener for events at the - * EventManager. - * @return - */ - ReturnValue_t initialize() override; - - enum Subservice: uint8_t { - NORMAL_REPORT = 1, //!< [EXPORT] : [REPLY] Generate normal report - ERROR_LOW_SEVERITY = 2, //!< [EXPORT] : [REPLY] Generate error report with low severity - ERROR_MED_SEVERITY = 3, //!< [EXPORT] : [REPLY] Generate error report with medium severity - ERROR_HIGH_SEVERITY = 4, //!< [EXPORT] : [REPLY] Generate error report with high severity - ENABLE = 5, //!< [EXPORT] : [COMMAND] Enable report generation - DISABLE = 6 //!< [EXPORT] : [COMMAND] Disable report generation - }; - -private: - uint16_t packetSubCounter = 0; - MessageQueueIF* eventQueue = nullptr; - bool enableEventReport = true; - const uint8_t maxNumberReportsPerCycle; - - ReturnValue_t generateEventReport(EventMessage message); -}; - -#endif /* MISSION_PUS_SERVICE5EVENTREPORTING_H_ */ +#ifndef FRAMEWORK_PUS_SERVICE5EVENTREPORTING_H_ +#define FRAMEWORK_PUS_SERVICE5EVENTREPORTING_H_ + +#include "../tmtcservices/PusServiceBase.h" +#include "../events/EventMessage.h" + +/** + * @brief Report on-board events like information or errors + * @details + * Full Documentation: ECSS-E70-41A p.79 + * Implements the PusServiceBase template class. + * Documentation: Dissertation Baetz p.135,136 + * + * This service provides for the reporting to the service user of information of + * operational significance. + * 1. reporting of failures or anomalies detected on-board; + * 2. reporting of autonomous on-board actions; + * 3. reporting of normal progress of operations and activities, e.g. + * detection of events which are not anomalous (such as payload events), + * reaching of predefined steps in an operation. Some reports can combine + * more than one of these events. + * + * Minimum capabilities of this service: + * + * - TM[5,1]: Normal/Progress Report + * - TM[5,2]: Error/Anomaly Report - Low Severity + * - TM[5,3]: Error/Anomaly Report - Medium Severity + * - TM[5,4]: Error/Anomaly Report - High Severity + * + * Events can be translated by using translator files located in + * /config/objects/ and /config/events/. Description to events can be added by + * adding a comment behind the event definition with [//!<] as leading string + * + * Additional capabilities of this service: + * + * - TC[5,5]: Enable Event Report Generation (Req. 6) + * - TC[5,6]: Disable Event Report Generation (Req. 5) + * @author R. Mueller + * @ingroup pus_services + */ +class Service5EventReporting: public PusServiceBase { +public: + + Service5EventReporting(object_id_t objectId, uint16_t apid, + uint8_t serviceId, size_t maxNumberReportsPerCycle = 10); + virtual ~Service5EventReporting(); + + /*** + * Check for events and generate event reports if required. + * @return + */ + ReturnValue_t performService() override; + + /*** + * Turn event generation on or off. + * @return + */ + ReturnValue_t handleRequest(uint8_t subservice) override; + + /** + * The default PusServiceBase initialize has been overridden but is still + * executed. Registers this service as a listener for events at the + * EventManager. + * @return + */ + ReturnValue_t initialize() override; + + enum Subservice: uint8_t { + NORMAL_REPORT = 1, //!< [EXPORT] : [REPLY] Generate normal report + ERROR_LOW_SEVERITY = 2, //!< [EXPORT] : [REPLY] Generate error report with low severity + ERROR_MED_SEVERITY = 3, //!< [EXPORT] : [REPLY] Generate error report with medium severity + ERROR_HIGH_SEVERITY = 4, //!< [EXPORT] : [REPLY] Generate error report with high severity + ENABLE = 5, //!< [EXPORT] : [COMMAND] Enable report generation + DISABLE = 6 //!< [EXPORT] : [COMMAND] Disable report generation + }; + +private: + uint16_t packetSubCounter = 0; + MessageQueueIF* eventQueue = nullptr; + bool enableEventReport = true; + const uint8_t maxNumberReportsPerCycle; + + ReturnValue_t generateEventReport(EventMessage message); +}; + +#endif /* MISSION_PUS_SERVICE5EVENTREPORTING_H_ */ diff --git a/pus/Service8FunctionManagement.cpp b/pus/Service8FunctionManagement.cpp index 50102b04..7174566a 100644 --- a/pus/Service8FunctionManagement.cpp +++ b/pus/Service8FunctionManagement.cpp @@ -1,11 +1,11 @@ -#include -#include +#include "../pus/Service8FunctionManagement.h" +#include "../pus/servicepackets/Service8Packets.h" -#include -#include -#include -#include -#include +#include "../objectmanager/SystemObjectIF.h" +#include "../action/HasActionsIF.h" +#include "../devicehandlers/DeviceHandlerIF.h" +#include "../serialize/SerializeAdapter.h" +#include "../serviceinterface/ServiceInterfaceStream.h" Service8FunctionManagement::Service8FunctionManagement(object_id_t object_id, uint16_t apid, uint8_t serviceId, uint8_t numParallelCommands, diff --git a/pus/Service8FunctionManagement.h b/pus/Service8FunctionManagement.h index e2c7a84f..16523533 100644 --- a/pus/Service8FunctionManagement.h +++ b/pus/Service8FunctionManagement.h @@ -1,8 +1,8 @@ #ifndef FRAMEWORK_PUS_SERVICE8FUNCTIONMANAGEMENT_H_ #define FRAMEWORK_PUS_SERVICE8FUNCTIONMANAGEMENT_H_ -#include -#include +#include "../action/ActionMessage.h" +#include "../tmtcservices/CommandingServiceBase.h" /** * @brief Functional commanding. diff --git a/pus/servicepackets/Service1Packets.h b/pus/servicepackets/Service1Packets.h index 4ba493d0..f4acbb61 100644 --- a/pus/servicepackets/Service1Packets.h +++ b/pus/servicepackets/Service1Packets.h @@ -1,166 +1,166 @@ -#ifndef MISSION_PUS_SERVICEPACKETS_SERVICE1PACKETS_H_ -#define MISSION_PUS_SERVICEPACKETS_SERVICE1PACKETS_H_ - -#include -#include - -/** - * @defgroup spacepackets PUS Packet Definitions - * This group contains all implemented TM or TM packages that are sent to - * or sent by the OBC.They are exported later to display - * packet structures in Mission Information Base (MIB). - */ - -/** - * @brief FailureReport class to serialize a failure report - * @brief Subservice 1, 3, 5, 7 - * @ingroup spacepackets - */ -class FailureReport: public SerializeIF { //!< [EXPORT] : [SUBSERVICE] 2, 4, 6, 8 -public: - FailureReport(uint8_t failureSubtype_, uint16_t packetId_, - uint16_t packetSequenceControl_, uint8_t stepNumber_, - ReturnValue_t errorCode_, uint32_t errorParameter1_, - uint32_t errorParameter2_) : - packetId(packetId_), packetSequenceControl(packetSequenceControl_), - stepNumber(stepNumber_), errorCode(errorCode_), - errorParameter1(errorParameter1_), errorParameter2(errorParameter2_), - failureSubtype(failureSubtype_) {} - - /** - * This function is called by the FSFW when calling the tm packet send - * function and supplying the SerializeIF* as parameter - * @param buffer Object content is serialized into the buffer - * @param size - * @param max_size - * @param bigEndian - * @return - */ - virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, - size_t maxSize, SerializeIF::Endianness streamEndianness - ) const override { - ReturnValue_t result = SerializeAdapter::serialize(&packetId, buffer, - size, maxSize, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - result = SerializeAdapter::serialize(&packetSequenceControl, buffer, - size, maxSize, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - if (failureSubtype == TC_VERIFY::PROGRESS_FAILURE) { - result = SerializeAdapter::serialize(&stepNumber, buffer, size, - maxSize, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - } - result = SerializeAdapter::serialize(&errorCode, buffer, size, - maxSize, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - result = SerializeAdapter::serialize(&errorParameter1, buffer, size, - maxSize, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - result = SerializeAdapter::serialize(&errorParameter2, buffer, size, - maxSize, streamEndianness); - return result; - } - - - virtual size_t getSerializedSize() const { - size_t size = 0; - size += SerializeAdapter::getSerializedSize(&packetId); - size += sizeof(packetSequenceControl); - if(failureSubtype==TC_VERIFY::PROGRESS_FAILURE){ - size += SerializeAdapter::getSerializedSize(&stepNumber); - } - size += SerializeAdapter::getSerializedSize(&errorCode); - size += SerializeAdapter::getSerializedSize(&errorParameter1); - size += SerializeAdapter::getSerializedSize(&errorParameter2); - return size; - } - - /** - * Deserialization is not allowed for a report. - * @param buffer - * @param size - * @param bigEndian - * @return - */ - ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - SerializeIF::Endianness streamEndianness) override { - return HasReturnvaluesIF::RETURN_FAILED; - } -private: - uint16_t packetId; //!< [EXPORT] : [COMMENT] Packet ID of respective Telecommand - uint16_t packetSequenceControl; //!< [EXPORT] : [COMMENT] Packet SSC of respective Telecommand - uint8_t stepNumber; //!< [EXPORT] : [OPTIONAL][SUBSERVICE] 6 - ReturnValue_t errorCode; //!< [EXPORT] : [COMMENT] Error code which can be looked up in generated error code file - uint32_t errorParameter1; - uint32_t errorParameter2; - const uint8_t failureSubtype; //!< [EXPORT] : [IGNORE] -}; - -/** - * @brief Subservices 2, 4, 6, 8 - * @ingroup spacepackets - */ -class SuccessReport: public SerializeIF { //!< [EXPORT] : [SUBSERVICE] 1, 3, 5, 7 -public: - SuccessReport(uint8_t subtype_, uint16_t packetId_, - uint16_t packetSequenceControl_,uint8_t stepNumber_) : - packetId(packetId_), packetSequenceControl(packetSequenceControl_), - stepNumber(stepNumber_), subtype(subtype_) {} - - virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, - size_t maxSize, SerializeIF::Endianness streamEndianness - ) const override { - ReturnValue_t result = SerializeAdapter::serialize(&packetId, buffer, - size, maxSize, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - result = SerializeAdapter::serialize(&packetSequenceControl, buffer, - size, maxSize, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - if (subtype == TC_VERIFY::PROGRESS_SUCCESS) { - result = SerializeAdapter::serialize(&stepNumber, buffer, size, - maxSize, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - } - return result; - } - - virtual size_t getSerializedSize() const override { - size_t size = 0; - size += SerializeAdapter::getSerializedSize(&packetId); - size += sizeof(packetSequenceControl); - if(subtype == TC_VERIFY::PROGRESS_SUCCESS){ - size += SerializeAdapter::getSerializedSize(&stepNumber); - } - return size; - - } - - ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - SerializeIF::Endianness streamEndianness) override { - return HasReturnvaluesIF::RETURN_FAILED; - } -private: - uint16_t packetId; //!< [EXPORT] : [COMMENT] Packet ID of respective Telecommand - uint16_t packetSequenceControl; //!< [EXPORT] : [COMMENT] Packet SSC of respective Telecommand - uint8_t stepNumber; //!< [EXPORT] : [OPTIONAL][SUBSERVICE] 6 - const uint8_t subtype; //!< [EXPORT] : [IGNORE] -}; - -#endif /* MISSION_PUS_SERVICEPACKETS_SERVICE1PACKETS_H_ */ +#ifndef MISSION_PUS_SERVICEPACKETS_SERVICE1PACKETS_H_ +#define MISSION_PUS_SERVICEPACKETS_SERVICE1PACKETS_H_ + +#include "../../serialize/SerializeAdapter.h" +#include "../../tmtcservices/VerificationCodes.h" + +/** + * @defgroup spacepackets PUS Packet Definitions + * This group contains all implemented TM or TM packages that are sent to + * or sent by the OBC.They are exported later to display + * packet structures in Mission Information Base (MIB). + */ + +/** + * @brief FailureReport class to serialize a failure report + * @brief Subservice 1, 3, 5, 7 + * @ingroup spacepackets + */ +class FailureReport: public SerializeIF { //!< [EXPORT] : [SUBSERVICE] 2, 4, 6, 8 +public: + FailureReport(uint8_t failureSubtype_, uint16_t packetId_, + uint16_t packetSequenceControl_, uint8_t stepNumber_, + ReturnValue_t errorCode_, uint32_t errorParameter1_, + uint32_t errorParameter2_) : + packetId(packetId_), packetSequenceControl(packetSequenceControl_), + stepNumber(stepNumber_), errorCode(errorCode_), + errorParameter1(errorParameter1_), errorParameter2(errorParameter2_), + failureSubtype(failureSubtype_) {} + + /** + * This function is called by the FSFW when calling the tm packet send + * function and supplying the SerializeIF* as parameter + * @param buffer Object content is serialized into the buffer + * @param size + * @param max_size + * @param bigEndian + * @return + */ + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + size_t maxSize, SerializeIF::Endianness streamEndianness + ) const override { + ReturnValue_t result = SerializeAdapter::serialize(&packetId, buffer, + size, maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = SerializeAdapter::serialize(&packetSequenceControl, buffer, + size, maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if (failureSubtype == TC_VERIFY::PROGRESS_FAILURE) { + result = SerializeAdapter::serialize(&stepNumber, buffer, size, + maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + result = SerializeAdapter::serialize(&errorCode, buffer, size, + maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = SerializeAdapter::serialize(&errorParameter1, buffer, size, + maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + result = SerializeAdapter::serialize(&errorParameter2, buffer, size, + maxSize, streamEndianness); + return result; + } + + + virtual size_t getSerializedSize() const { + size_t size = 0; + size += SerializeAdapter::getSerializedSize(&packetId); + size += sizeof(packetSequenceControl); + if(failureSubtype==TC_VERIFY::PROGRESS_FAILURE){ + size += SerializeAdapter::getSerializedSize(&stepNumber); + } + size += SerializeAdapter::getSerializedSize(&errorCode); + size += SerializeAdapter::getSerializedSize(&errorParameter1); + size += SerializeAdapter::getSerializedSize(&errorParameter2); + return size; + } + + /** + * Deserialization is not allowed for a report. + * @param buffer + * @param size + * @param bigEndian + * @return + */ + ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + SerializeIF::Endianness streamEndianness) override { + return HasReturnvaluesIF::RETURN_FAILED; + } +private: + uint16_t packetId; //!< [EXPORT] : [COMMENT] Packet ID of respective Telecommand + uint16_t packetSequenceControl; //!< [EXPORT] : [COMMENT] Packet SSC of respective Telecommand + uint8_t stepNumber; //!< [EXPORT] : [OPTIONAL][SUBSERVICE] 6 + ReturnValue_t errorCode; //!< [EXPORT] : [COMMENT] Error code which can be looked up in generated error code file + uint32_t errorParameter1; + uint32_t errorParameter2; + const uint8_t failureSubtype; //!< [EXPORT] : [IGNORE] +}; + +/** + * @brief Subservices 2, 4, 6, 8 + * @ingroup spacepackets + */ +class SuccessReport: public SerializeIF { //!< [EXPORT] : [SUBSERVICE] 1, 3, 5, 7 +public: + SuccessReport(uint8_t subtype_, uint16_t packetId_, + uint16_t packetSequenceControl_,uint8_t stepNumber_) : + packetId(packetId_), packetSequenceControl(packetSequenceControl_), + stepNumber(stepNumber_), subtype(subtype_) {} + + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + size_t maxSize, SerializeIF::Endianness streamEndianness + ) const override { + ReturnValue_t result = SerializeAdapter::serialize(&packetId, buffer, + size, maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = SerializeAdapter::serialize(&packetSequenceControl, buffer, + size, maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if (subtype == TC_VERIFY::PROGRESS_SUCCESS) { + result = SerializeAdapter::serialize(&stepNumber, buffer, size, + maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + return result; + } + + virtual size_t getSerializedSize() const override { + size_t size = 0; + size += SerializeAdapter::getSerializedSize(&packetId); + size += sizeof(packetSequenceControl); + if(subtype == TC_VERIFY::PROGRESS_SUCCESS){ + size += SerializeAdapter::getSerializedSize(&stepNumber); + } + return size; + + } + + ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + SerializeIF::Endianness streamEndianness) override { + return HasReturnvaluesIF::RETURN_FAILED; + } +private: + uint16_t packetId; //!< [EXPORT] : [COMMENT] Packet ID of respective Telecommand + uint16_t packetSequenceControl; //!< [EXPORT] : [COMMENT] Packet SSC of respective Telecommand + uint8_t stepNumber; //!< [EXPORT] : [OPTIONAL][SUBSERVICE] 6 + const uint8_t subtype; //!< [EXPORT] : [IGNORE] +}; + +#endif /* MISSION_PUS_SERVICEPACKETS_SERVICE1PACKETS_H_ */ diff --git a/pus/servicepackets/Service200Packets.h b/pus/servicepackets/Service200Packets.h index 1b5bf236..6a700b50 100644 --- a/pus/servicepackets/Service200Packets.h +++ b/pus/servicepackets/Service200Packets.h @@ -1,9 +1,9 @@ #ifndef FRAMEWORK_PUS_SERVICEPACKETS_SERVICE200PACKETS_H_ #define FRAMEWORK_PUS_SERVICEPACKETS_SERVICE200PACKETS_H_ -#include -#include -#include +#include "../../serialize/SerialLinkedListAdapter.h" +#include "../../modes/ModeMessage.h" +#include "../../serialize/SerializeIF.h" /** * @brief Subservice 1, 2, 3, 4, 5 diff --git a/pus/servicepackets/Service2Packets.h b/pus/servicepackets/Service2Packets.h index f292611e..a0b1305d 100644 --- a/pus/servicepackets/Service2Packets.h +++ b/pus/servicepackets/Service2Packets.h @@ -1,10 +1,10 @@ #ifndef FRAMEWORK_PUS_SERVICEPACKETS_SERVICE2PACKETS_H_ #define FRAMEWORK_PUS_SERVICEPACKETS_SERVICE2PACKETS_H_ -#include -#include -#include -#include +#include "../../action/ActionMessage.h" +#include "../../objectmanager/SystemObjectIF.h" +#include "../../serialize/SerialLinkedListAdapter.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" /** * @brief Subservice 128 diff --git a/pus/servicepackets/Service5Packets.h b/pus/servicepackets/Service5Packets.h index 14219c93..0b52be3c 100644 --- a/pus/servicepackets/Service5Packets.h +++ b/pus/servicepackets/Service5Packets.h @@ -1,76 +1,76 @@ -#ifndef MISSION_PUS_SERVICEPACKETS_SERVICE5PACKETS_H_ -#define MISSION_PUS_SERVICEPACKETS_SERVICE5PACKETS_H_ - -#include -#include - - -/** - * @brief Subservice 1, 2, 3, 4 - * Structure of Event Report. - * It consists of: - * 1. Report ID(RID). This is the Event ID in the FSFW - * 2. Object ID of the reporter (e.g. subsystem) - * 2. Parameter 1 - * 3. Parameter 2 - * - * @ingroup spacepackets - */ -class EventReport: public SerializeIF { //!< [EXPORT] : [SUBSERVICE] 1, 2, 3, 4 -public: - - EventReport(EventId_t reportId_, object_id_t objectId_, uint32_t parameter1_, - uint32_t parameter2_): - reportId(reportId_),objectId(objectId_), parameter1(parameter1_), - parameter2(parameter2_) {} - - virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, - size_t maxSize, - SerializeIF::Endianness streamEndianness) const override - { - ReturnValue_t result = SerializeAdapter::serialize(&reportId, buffer, - size, maxSize, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - result = SerializeAdapter::serialize(&objectId, buffer, size, - maxSize, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - result = SerializeAdapter::serialize(¶meter1, buffer, size, - maxSize, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - result = SerializeAdapter::serialize(¶meter2, buffer, size, - maxSize, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - return result; - } - - virtual size_t getSerializedSize() const override { - uint32_t size = 0; - size += SerializeAdapter::getSerializedSize(&reportId); - size += SerializeAdapter::getSerializedSize(&objectId); - size += SerializeAdapter::getSerializedSize(¶meter1); - size += SerializeAdapter::getSerializedSize(¶meter2); - return size; - - } - - virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - SerializeIF::Endianness streamEndianness) override { - return HasReturnvaluesIF::RETURN_FAILED; - } -private: - EventId_t reportId; - object_id_t objectId; - uint32_t parameter1; - uint32_t parameter2; -}; - - -#endif /* MISSION_PUS_SERVICEPACKETS_SERVICE5PACKETS_H_ */ +#ifndef MISSION_PUS_SERVICEPACKETS_SERVICE5PACKETS_H_ +#define MISSION_PUS_SERVICEPACKETS_SERVICE5PACKETS_H_ + +#include "../../serialize/SerializeAdapter.h" +#include "../../tmtcservices/VerificationCodes.h" + + +/** + * @brief Subservice 1, 2, 3, 4 + * Structure of Event Report. + * It consists of: + * 1. Report ID(RID). This is the Event ID in the FSFW + * 2. Object ID of the reporter (e.g. subsystem) + * 2. Parameter 1 + * 3. Parameter 2 + * + * @ingroup spacepackets + */ +class EventReport: public SerializeIF { //!< [EXPORT] : [SUBSERVICE] 1, 2, 3, 4 +public: + + EventReport(EventId_t reportId_, object_id_t objectId_, uint32_t parameter1_, + uint32_t parameter2_): + reportId(reportId_),objectId(objectId_), parameter1(parameter1_), + parameter2(parameter2_) {} + + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + size_t maxSize, + SerializeIF::Endianness streamEndianness) const override + { + ReturnValue_t result = SerializeAdapter::serialize(&reportId, buffer, + size, maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = SerializeAdapter::serialize(&objectId, buffer, size, + maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = SerializeAdapter::serialize(¶meter1, buffer, size, + maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = SerializeAdapter::serialize(¶meter2, buffer, size, + maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return result; + } + + virtual size_t getSerializedSize() const override { + uint32_t size = 0; + size += SerializeAdapter::getSerializedSize(&reportId); + size += SerializeAdapter::getSerializedSize(&objectId); + size += SerializeAdapter::getSerializedSize(¶meter1); + size += SerializeAdapter::getSerializedSize(¶meter2); + return size; + + } + + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + SerializeIF::Endianness streamEndianness) override { + return HasReturnvaluesIF::RETURN_FAILED; + } +private: + EventId_t reportId; + object_id_t objectId; + uint32_t parameter1; + uint32_t parameter2; +}; + + +#endif /* MISSION_PUS_SERVICEPACKETS_SERVICE5PACKETS_H_ */ diff --git a/pus/servicepackets/Service8Packets.h b/pus/servicepackets/Service8Packets.h index 8ea0d108..d16309ec 100644 --- a/pus/servicepackets/Service8Packets.h +++ b/pus/servicepackets/Service8Packets.h @@ -1,12 +1,12 @@ #ifndef FRAMEWORK_PUS_SERVICEPACKETS_SERVICE8PACKETS_H_ #define FRAMEWORK_PUS_SERVICEPACKETS_SERVICE8PACKETS_H_ -#include -#include -#include -#include -#include -#include +#include "../../action/ActionMessage.h" +#include "../../objectmanager/SystemObjectIF.h" +#include "../../serialize/SerialBufferAdapter.h" +#include "../../serialize/SerializeElement.h" +#include "../../serialize/SerialLinkedListAdapter.h" +#include "../../serialize/SerialFixedArrayListAdapter.h" /** diff --git a/returnvalues/HasReturnvaluesIF.h b/returnvalues/HasReturnvaluesIF.h index 9b9086d9..893ad1db 100644 --- a/returnvalues/HasReturnvaluesIF.h +++ b/returnvalues/HasReturnvaluesIF.h @@ -1,31 +1,31 @@ -#ifndef FRAMEWORK_RETURNVALUES_HASRETURNVALUESIF_H_ -#define FRAMEWORK_RETURNVALUES_HASRETURNVALUESIF_H_ - -#include -#include -#include - -#define MAKE_RETURN_CODE( number ) ((INTERFACE_ID << 8) + (number)) -typedef uint16_t ReturnValue_t; - - -class HasReturnvaluesIF { -public: - static const ReturnValue_t RETURN_OK = 0; - static const ReturnValue_t RETURN_FAILED = 1; - virtual ~HasReturnvaluesIF() {} - - /** - * It is discouraged to use the input parameters 0,0 and 0,1 as this - * will generate the RETURN_OK and RETURN_FAILED returnvalues. - * @param interfaceId - * @param number - * @return - */ - static constexpr ReturnValue_t makeReturnCode(uint8_t interfaceId, - uint8_t number) { - return (interfaceId << 8) + number; - } -}; - -#endif /* FRAMEWORK_RETURNVALUES_HASRETURNVALUESIF_H_ */ +#ifndef FRAMEWORK_RETURNVALUES_HASRETURNVALUESIF_H_ +#define FRAMEWORK_RETURNVALUES_HASRETURNVALUESIF_H_ + +#include "../returnvalues/FwClassIds.h" +#include +#include + +#define MAKE_RETURN_CODE( number ) ((INTERFACE_ID << 8) + (number)) +typedef uint16_t ReturnValue_t; + + +class HasReturnvaluesIF { +public: + static const ReturnValue_t RETURN_OK = 0; + static const ReturnValue_t RETURN_FAILED = 1; + virtual ~HasReturnvaluesIF() {} + + /** + * It is discouraged to use the input parameters 0,0 and 0,1 as this + * will generate the RETURN_OK and RETURN_FAILED returnvalues. + * @param interfaceId + * @param number + * @return + */ + static constexpr ReturnValue_t makeReturnCode(uint8_t interfaceId, + uint8_t number) { + return (interfaceId << 8) + number; + } +}; + +#endif /* FRAMEWORK_RETURNVALUES_HASRETURNVALUESIF_H_ */ diff --git a/rmap/RMAP.cpp b/rmap/RMAP.cpp index 927fe746..8bc91bb5 100644 --- a/rmap/RMAP.cpp +++ b/rmap/RMAP.cpp @@ -1,89 +1,89 @@ -#include -#include -#include -#include -#include - -ReturnValue_t RMAP::reset(RMAPCookie* cookie) { - return cookie->getChannel()->reset(); -} - -RMAP::RMAP(){ - -} - -ReturnValue_t RMAP::sendWriteCommand(RMAPCookie *cookie, const uint8_t* buffer, - size_t length) { - uint8_t instruction; - - if ((buffer == NULL) && (length != 0)) { - return DeviceCommunicationIF::NULLPOINTER; - } - if (cookie->getChannel() == NULL) { - return COMMAND_NO_CHANNEL; - } - instruction = RMAPIds::RMAP_COMMAND_WRITE | cookie->getCommandMask(); - return cookie->getChannel()->sendCommand(cookie, instruction, buffer, - length); - -} - -ReturnValue_t RMAP::getWriteReply(RMAPCookie *cookie) { - if (cookie->getChannel() == NULL) { - return COMMAND_NO_CHANNEL; - } - if (cookie->getHeader()->instruction & (1 << RMAPIds::RMAP_COMMAND_BIT_WRITE)) { - return cookie->getChannel()->getReply(cookie, NULL, NULL); - } else { - return REPLY_MISSMATCH; - } -} - -ReturnValue_t RMAP::writeBlocking(RMAPCookie *cookie, uint8_t* buffer, - uint32_t length, uint32_t timeout_us) { - if (cookie->getChannel() == NULL) { - return COMMAND_NO_CHANNEL; - } - return cookie->getChannel()->sendCommandBlocking(cookie, buffer, length, - NULL, NULL, timeout_us); - -} -ReturnValue_t RMAP::sendReadCommand(RMAPCookie *cookie, uint32_t expLength) { - uint8_t command; - if (cookie->getChannel() == NULL) { - return COMMAND_NO_CHANNEL; - } - command = RMAPIds::RMAP_COMMAND_READ - | (cookie->getCommandMask() & ~(1 << RMAPIds::RMAP_COMMAND_BIT_VERIFY)); - - return cookie->getChannel()->sendCommand(cookie, command, NULL, expLength); - -} - -ReturnValue_t RMAP::getReadReply(RMAPCookie *cookie, uint8_t **buffer, - size_t *size) { - if (cookie->getChannel() == NULL) { - return COMMAND_NO_CHANNEL; - } - if (buffer == NULL || size == NULL) { - return DeviceCommunicationIF::NULLPOINTER; - } - if (cookie->getHeader()->instruction & (1 << RMAPIds::RMAP_COMMAND_BIT_WRITE)) { - return REPLY_MISSMATCH; - } else { - return cookie->getChannel()->getReply(cookie, buffer, size); - } - -} - -ReturnValue_t RMAP::readBlocking(RMAPCookie *cookie, uint32_t expLength, - uint8_t** buffer, uint32_t *size, uint32_t timeout_us) { - if (cookie->getChannel() == NULL) { - return COMMAND_NO_CHANNEL; - } - if (buffer == NULL || size == NULL) { - return DeviceCommunicationIF::NULLPOINTER; - } - return cookie->getChannel()->sendCommandBlocking(cookie, NULL, expLength, - buffer, size, timeout_us); -} +#include "../devicehandlers/DeviceCommunicationIF.h" +#include "../rmap/rmapStructs.h" +#include "../rmap/RMAP.h" +#include "../rmap/RMAPChannelIF.h" +#include + +ReturnValue_t RMAP::reset(RMAPCookie* cookie) { + return cookie->getChannel()->reset(); +} + +RMAP::RMAP(){ + +} + +ReturnValue_t RMAP::sendWriteCommand(RMAPCookie *cookie, const uint8_t* buffer, + size_t length) { + uint8_t instruction; + + if ((buffer == NULL) && (length != 0)) { + return DeviceCommunicationIF::NULLPOINTER; + } + if (cookie->getChannel() == NULL) { + return COMMAND_NO_CHANNEL; + } + instruction = RMAPIds::RMAP_COMMAND_WRITE | cookie->getCommandMask(); + return cookie->getChannel()->sendCommand(cookie, instruction, buffer, + length); + +} + +ReturnValue_t RMAP::getWriteReply(RMAPCookie *cookie) { + if (cookie->getChannel() == NULL) { + return COMMAND_NO_CHANNEL; + } + if (cookie->getHeader()->instruction & (1 << RMAPIds::RMAP_COMMAND_BIT_WRITE)) { + return cookie->getChannel()->getReply(cookie, NULL, NULL); + } else { + return REPLY_MISSMATCH; + } +} + +ReturnValue_t RMAP::writeBlocking(RMAPCookie *cookie, uint8_t* buffer, + uint32_t length, uint32_t timeout_us) { + if (cookie->getChannel() == NULL) { + return COMMAND_NO_CHANNEL; + } + return cookie->getChannel()->sendCommandBlocking(cookie, buffer, length, + NULL, NULL, timeout_us); + +} +ReturnValue_t RMAP::sendReadCommand(RMAPCookie *cookie, uint32_t expLength) { + uint8_t command; + if (cookie->getChannel() == NULL) { + return COMMAND_NO_CHANNEL; + } + command = RMAPIds::RMAP_COMMAND_READ + | (cookie->getCommandMask() & ~(1 << RMAPIds::RMAP_COMMAND_BIT_VERIFY)); + + return cookie->getChannel()->sendCommand(cookie, command, NULL, expLength); + +} + +ReturnValue_t RMAP::getReadReply(RMAPCookie *cookie, uint8_t **buffer, + size_t *size) { + if (cookie->getChannel() == NULL) { + return COMMAND_NO_CHANNEL; + } + if (buffer == NULL || size == NULL) { + return DeviceCommunicationIF::NULLPOINTER; + } + if (cookie->getHeader()->instruction & (1 << RMAPIds::RMAP_COMMAND_BIT_WRITE)) { + return REPLY_MISSMATCH; + } else { + return cookie->getChannel()->getReply(cookie, buffer, size); + } + +} + +ReturnValue_t RMAP::readBlocking(RMAPCookie *cookie, uint32_t expLength, + uint8_t** buffer, uint32_t *size, uint32_t timeout_us) { + if (cookie->getChannel() == NULL) { + return COMMAND_NO_CHANNEL; + } + if (buffer == NULL || size == NULL) { + return DeviceCommunicationIF::NULLPOINTER; + } + return cookie->getChannel()->sendCommandBlocking(cookie, NULL, expLength, + buffer, size, timeout_us); +} diff --git a/rmap/RMAP.h b/rmap/RMAP.h index 91aa123e..9ab6b87d 100644 --- a/rmap/RMAP.h +++ b/rmap/RMAP.h @@ -1,227 +1,227 @@ -#ifndef RMAPpp_H_ -#define RMAPpp_H_ - -#include -#include - -//SHOULDTODO: clean up includes for RMAP, should be enough to include RMAP.h but right now it's quite chaotic... - -/** - * API for a Cookie/Channel based RMAP implementation. - * - * The API offers the four basic RMAP actions: sending a Read or Write command and getting the reply to each. - * As RMAP is an asynchronous protocol, these are implemented as four seperate calls. There are blocking - * calls which combine a send and get call using a timeout, but these are "real" blocking, looping in between - * the calls. - * - * Cookies are used to contain Information between a send[Read,Write]Command and a get[Read,Write]Reply call, - * one can think of them like *nix file descriptors. A cookie is valid from a sendX call until the related getX - * call. That means if a cookie is used in a getX call, the reply to the sendX call the cookie was used with - * previously is returned. - * Depending on the underlying RMAPChannel implementation, a cookie can also be valid for more than one getX - * call, but this should not be assumed generally. - * A cookie encapsulates information like the RMAP Channel to use, as well as the RMAP Address - * and a Command Mask used for specifying which RMAP capabilities are used. - * Cookies are created without interaction with this API, there is no open() call. The RMAP implementation - * will initialize all fields which are not set by the cookie's constructor. - * - * The RMAP implementation relies on Channels. A channel is used to construct the RMAP Headers and handle the - * protocol. It is access via the RMAPChannelIF. Thus it is possible to use different Implementations which only - * need to implement the RMAPChannelIF. A channel is also responsible for accessing the lower layers, for example - * a SPaceWire transport layer. - * - * There is one RMAP Channel per physical device. The cookie-channel as well as the device-channel assignment - * can be changed at runtime to allow for example redundancy switching. This API is static as the information which - * channel to use is contained within the cookie. - */ -class RMAP: public HasReturnvaluesIF { -public: - static const uint8_t INTERFACE_ID = CLASS_ID::RMAP_CHANNEL; - - //static const ReturnValue_t COMMAND_OK = MAKE_RETURN_CODE(0x00); - static const ReturnValue_t COMMAND_NO_DESCRIPTORS_AVAILABLE = - MAKE_RETURN_CODE(0xE1); //no descriptors available for sending command; command was not sent - static const ReturnValue_t COMMAND_BUFFER_FULL = MAKE_RETURN_CODE(0xE2); //no receiver buffer available for expected len; command was not sent - static const ReturnValue_t COMMAND_CHANNEL_OUT_OF_RANGE = MAKE_RETURN_CODE( - 0xE3); //The cookie points to an invalid channel; command was not sent -//Replaced by DeviceCommunicationIF::TOO_MUCH_DATA static const ReturnValue_t COMMAND_TOO_BIG = MAKE_RETURN_CODE(0xE4); //the data that was to be sent was too long for the hw to handle (write command) or the expected len was bigger than maximal expected len (read command) - //command was not sent -//replaced by DeviceCommunicationIF::NULLPOINTER static const ReturnValue_t COMMAND_NULLPOINTER = MAKE_RETURN_CODE(0xE5); //datalen was != 0 but data was == NULL in write command, or nullpointer in read command - static const ReturnValue_t COMMAND_CHANNEL_DEACTIVATED = MAKE_RETURN_CODE( - 0xE6); //the channel has no port set - static const ReturnValue_t COMMAND_PORT_OUT_OF_RANGE = MAKE_RETURN_CODE( - 0xE7); //The specified port is not valid - static const ReturnValue_t COMMAND_PORT_IN_USE = MAKE_RETURN_CODE(0xE8);//The specified port is already in use - static const ReturnValue_t COMMAND_NO_CHANNEL = MAKE_RETURN_CODE(0xE9);//The cookie to work with has no channel assigned. - static const ReturnValue_t NO_HW_CRC = MAKE_RETURN_CODE(0xEA);//The SpW port does not support HW CRC generation, which is unsupported - //return values for both get_write_reply and get_read_reply - static const ReturnValue_t REPLY_NO_REPLY = MAKE_RETURN_CODE(0xD0); //no reply was received - static const ReturnValue_t REPLY_NOT_SENT = MAKE_RETURN_CODE(0xD1); //command was not sent, implies no reply - static const ReturnValue_t REPLY_NOT_YET_SENT = MAKE_RETURN_CODE(0xD2); //command is still waiting to be sent - static const ReturnValue_t REPLY_MISSMATCH = MAKE_RETURN_CODE(0xD3);//a read command was issued, but get_write_rply called, or other way round - static const ReturnValue_t REPLY_TIMEOUT = MAKE_RETURN_CODE(0xD4);//timeout -//replaced by DeviceCommunicationIF::NULLPOINTER static const ReturnValue_t REPLY_NULLPOINTER = MAKE_RETURN_CODE(0xD5);//one of the arguments in a read reply was NULL - //return values for get_reply - static const ReturnValue_t REPLY_INTERFACE_BUSY = MAKE_RETURN_CODE( - 0xC0);//Interface is busy (transmission buffer still being processed) - static const ReturnValue_t REPLY_TRANSMISSION_ERROR = - MAKE_RETURN_CODE(0xC1); //Interface encountered errors during last operation, data could not be processed. (transmission error) - static const ReturnValue_t REPLY_INVALID_DATA = MAKE_RETURN_CODE( - 0xC2); //Invalid data (amount / value) - static const ReturnValue_t REPLY_NOT_SUPPORTED = MAKE_RETURN_CODE( - 0xC3); - - //return values for reset - static const ReturnValue_t LINK_DOWN = MAKE_RETURN_CODE(0xF0);//The spw link is down - //Other SpW codes: - static const ReturnValue_t SPW_CREDIT = MAKE_RETURN_CODE(0xF1); - static const ReturnValue_t SPW_ESCAPE = MAKE_RETURN_CODE(0xF2); - static const ReturnValue_t SPW_DISCONNECT = MAKE_RETURN_CODE(0xF3); - static const ReturnValue_t SPW_PARITY = MAKE_RETURN_CODE(0xF4); - static const ReturnValue_t SPW_WRITE_SYNC = MAKE_RETURN_CODE(0xF5); - static const ReturnValue_t SPW_INVALID_ADDRESS = MAKE_RETURN_CODE(0xF6); - static const ReturnValue_t SPW_EARLY_EOP = MAKE_RETURN_CODE(0xF7); - static const ReturnValue_t SPW_DMA = MAKE_RETURN_CODE(0xF8); - static const ReturnValue_t SPW_LINK_ERROR = MAKE_RETURN_CODE(0xF9); - - - //RMAP standard replies - static const ReturnValue_t REPLY_OK = MAKE_RETURN_CODE(0); - static const ReturnValue_t REPLY_GENERAL_ERROR_CODE = MAKE_RETURN_CODE(1);// The detected error does not fit into the other - // error cases or the node does not support - // further distinction between the errors - static const ReturnValue_t REPLY_UNUSED_PACKET_TYPE_OR_COMMAND_CODE = - MAKE_RETURN_CODE(2); // The Header CRC was decoded correctly but - // the packet type is reserved or the command - // is not used by the RMAP protocol. - static const ReturnValue_t REPLY_INVALID_KEY = MAKE_RETURN_CODE(3); // The Header CRC was decoded correctly but - // the device key did not match that expected - // by the target user application - static const ReturnValue_t REPLY_INVALID_DATA_CRC = MAKE_RETURN_CODE(4);// Error in the CRC of the data field - static const ReturnValue_t REPLY_EARLY_EOP = MAKE_RETURN_CODE(5);// EOP marker detected before the end of the data - static const ReturnValue_t REPLY_TOO_MUCH_DATA = MAKE_RETURN_CODE(6);// More than the expected amount of data in a - // command has been received - static const ReturnValue_t REPLY_EEP = MAKE_RETURN_CODE(7); // EEP marker detected immediately after the - // header CRC or during the transfer of data - // and Data CRC or immediately thereafter. - // Indicates that there was a communication - // failure of some sort on the network - static const ReturnValue_t REPLY_RESERVED = MAKE_RETURN_CODE(8);// Reserved - static const ReturnValue_t REPLY_VERIFY_BUFFER_OVERRUN = MAKE_RETURN_CODE( - 9); // The verify before write bit of the command - // was set so that the data field was buffered in - // order to verify the Data CRC before - // transferring the data to target memory. The - // data field was longer than able to fit inside - // the verify buffer resulting in a buffer overrun - // Note that the command is not executed in - // this case - static const ReturnValue_t REPLY_COMMAND_NOT_IMPLEMENTED_OR_NOT_AUTHORISED = - MAKE_RETURN_CODE(10);// The target user application did not authorise - // the requested operation. This may be because - // the command requested has not been - // implemented - static const ReturnValue_t REPLY_RMW_DATA_LENGTH_ERROR = MAKE_RETURN_CODE( - 11); // The amount of data in a RMW command is - // invalid (0x01 0x03 0x05 0x07 or greater - // than 0x08) - static const ReturnValue_t REPLY_INVALID_TARGET_LOGICAL_ADDRESS = - MAKE_RETURN_CODE(12); // The Header CRC was decoded correctly but - // the Target Logical Address was not the value - // expected by the target - - /** - * Resets the underlying channel. - * - * @param cookie The cookie which points to the channel to reset - * @return - */ - static ReturnValue_t reset(RMAPCookie *cookie); - - /** - * send an RMAP write command - * - * datalen is only 24bit wide, rest will be ignored - * IMPORTANT: the data buffer must be datalen+1 large, as the driver might - * write a CRC sum at data[datalen] - * if you want to send an empty packet, just do datalen = 0 and data = NULL - * - * @param cookie The cookie to write to - * @param buffer the data to write - * @param length length of data - * @return - * - @c COMMAND_NULLPOINTER datalen was != 0 but data was == NULL in write command - * - return codes of RMAPChannelIF::sendCommand() - */ - static ReturnValue_t sendWriteCommand(RMAPCookie *cookie, const uint8_t* buffer, - size_t length); - - /** - * get the reply to a write command - * - * @param cookie the cookie the command was sent with - * @return - * - @c REPLY_MISSMATCH a read command was issued, but getWriteReply called - * - return codes of RMAPChannelIF::getReply() - */ - static ReturnValue_t getWriteReply(RMAPCookie *cookie); - - /** - * @see sendWriteCommand() - * @see getWriteReply() - * - * @param timeout_us the time after the function returns, if no reply was received - * - * @return - * - All of sendWriteCommand() - * - All of getWriteReply() - * - @c REPLY_TIMEOUT timeout - */ - static ReturnValue_t writeBlocking(RMAPCookie *cookie, uint8_t* buffer, - uint32_t length, uint32_t timeout_us); - - /** - * send an RMAP read command - * - * @param cookie to cookie to read from - * @param expLength the expected maximum length of the reply - * @return - * - @c COMMAND_NULLPOINTER datalen was != 0 but data was == NULL in write command, or nullpointer in read command - * - return codes of RMAPChannelIF::sendCommand() - */ - static ReturnValue_t sendReadCommand(RMAPCookie *cookie, - uint32_t expLength); - - /** - * get a reply to an RMAP read command - * - * @param cookie the cookie that was read from - * @param[out] buffer the location of the data - * @param[out] size size of the data - * @return - * - @c COMMAND_NULLPOINTER buffer or size was NULL - * - @c REPLY_MISSMATCH a write command was issued, but getReadReply called - * - return codes of RMAPChannelIF::getReply() - */ - static ReturnValue_t getReadReply(RMAPCookie *cookie, uint8_t **buffer, - size_t *size); - - /** - * @see sendReadCommand() - * @see getReadReply() - * - * @param timeout_us the time after the function returns, if no reply was received - * - * @return - * - All of sendReadCommand() - * - All of getReadReply() - * - @c REPLY_TIMEOUT timeout - */ - static ReturnValue_t readBlocking(RMAPCookie *cookie, uint32_t expLength, - uint8_t** buffer, uint32_t *size, uint32_t timeout_us); - -protected: - RMAP(); -}; - -#endif /* RMAPpp_H_ */ +#ifndef RMAPpp_H_ +#define RMAPpp_H_ + +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../rmap/RMAPCookie.h" + +//SHOULDTODO: clean up includes for RMAP, should be enough to include RMAP.h but right now it's quite chaotic... + +/** + * API for a Cookie/Channel based RMAP implementation. + * + * The API offers the four basic RMAP actions: sending a Read or Write command and getting the reply to each. + * As RMAP is an asynchronous protocol, these are implemented as four seperate calls. There are blocking + * calls which combine a send and get call using a timeout, but these are "real" blocking, looping in between + * the calls. + * + * Cookies are used to contain Information between a send[Read,Write]Command and a get[Read,Write]Reply call, + * one can think of them like *nix file descriptors. A cookie is valid from a sendX call until the related getX + * call. That means if a cookie is used in a getX call, the reply to the sendX call the cookie was used with + * previously is returned. + * Depending on the underlying RMAPChannel implementation, a cookie can also be valid for more than one getX + * call, but this should not be assumed generally. + * A cookie encapsulates information like the RMAP Channel to use, as well as the RMAP Address + * and a Command Mask used for specifying which RMAP capabilities are used. + * Cookies are created without interaction with this API, there is no open() call. The RMAP implementation + * will initialize all fields which are not set by the cookie's constructor. + * + * The RMAP implementation relies on Channels. A channel is used to construct the RMAP Headers and handle the + * protocol. It is access via the RMAPChannelIF. Thus it is possible to use different Implementations which only + * need to implement the RMAPChannelIF. A channel is also responsible for accessing the lower layers, for example + * a SPaceWire transport layer. + * + * There is one RMAP Channel per physical device. The cookie-channel as well as the device-channel assignment + * can be changed at runtime to allow for example redundancy switching. This API is static as the information which + * channel to use is contained within the cookie. + */ +class RMAP: public HasReturnvaluesIF { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::RMAP_CHANNEL; + + //static const ReturnValue_t COMMAND_OK = MAKE_RETURN_CODE(0x00); + static const ReturnValue_t COMMAND_NO_DESCRIPTORS_AVAILABLE = + MAKE_RETURN_CODE(0xE1); //no descriptors available for sending command; command was not sent + static const ReturnValue_t COMMAND_BUFFER_FULL = MAKE_RETURN_CODE(0xE2); //no receiver buffer available for expected len; command was not sent + static const ReturnValue_t COMMAND_CHANNEL_OUT_OF_RANGE = MAKE_RETURN_CODE( + 0xE3); //The cookie points to an invalid channel; command was not sent +//Replaced by DeviceCommunicationIF::TOO_MUCH_DATA static const ReturnValue_t COMMAND_TOO_BIG = MAKE_RETURN_CODE(0xE4); //the data that was to be sent was too long for the hw to handle (write command) or the expected len was bigger than maximal expected len (read command) + //command was not sent +//replaced by DeviceCommunicationIF::NULLPOINTER static const ReturnValue_t COMMAND_NULLPOINTER = MAKE_RETURN_CODE(0xE5); //datalen was != 0 but data was == NULL in write command, or nullpointer in read command + static const ReturnValue_t COMMAND_CHANNEL_DEACTIVATED = MAKE_RETURN_CODE( + 0xE6); //the channel has no port set + static const ReturnValue_t COMMAND_PORT_OUT_OF_RANGE = MAKE_RETURN_CODE( + 0xE7); //The specified port is not valid + static const ReturnValue_t COMMAND_PORT_IN_USE = MAKE_RETURN_CODE(0xE8);//The specified port is already in use + static const ReturnValue_t COMMAND_NO_CHANNEL = MAKE_RETURN_CODE(0xE9);//The cookie to work with has no channel assigned. + static const ReturnValue_t NO_HW_CRC = MAKE_RETURN_CODE(0xEA);//The SpW port does not support HW CRC generation, which is unsupported + //return values for both get_write_reply and get_read_reply + static const ReturnValue_t REPLY_NO_REPLY = MAKE_RETURN_CODE(0xD0); //no reply was received + static const ReturnValue_t REPLY_NOT_SENT = MAKE_RETURN_CODE(0xD1); //command was not sent, implies no reply + static const ReturnValue_t REPLY_NOT_YET_SENT = MAKE_RETURN_CODE(0xD2); //command is still waiting to be sent + static const ReturnValue_t REPLY_MISSMATCH = MAKE_RETURN_CODE(0xD3);//a read command was issued, but get_write_rply called, or other way round + static const ReturnValue_t REPLY_TIMEOUT = MAKE_RETURN_CODE(0xD4);//timeout +//replaced by DeviceCommunicationIF::NULLPOINTER static const ReturnValue_t REPLY_NULLPOINTER = MAKE_RETURN_CODE(0xD5);//one of the arguments in a read reply was NULL + //return values for get_reply + static const ReturnValue_t REPLY_INTERFACE_BUSY = MAKE_RETURN_CODE( + 0xC0);//Interface is busy (transmission buffer still being processed) + static const ReturnValue_t REPLY_TRANSMISSION_ERROR = + MAKE_RETURN_CODE(0xC1); //Interface encountered errors during last operation, data could not be processed. (transmission error) + static const ReturnValue_t REPLY_INVALID_DATA = MAKE_RETURN_CODE( + 0xC2); //Invalid data (amount / value) + static const ReturnValue_t REPLY_NOT_SUPPORTED = MAKE_RETURN_CODE( + 0xC3); + + //return values for reset + static const ReturnValue_t LINK_DOWN = MAKE_RETURN_CODE(0xF0);//The spw link is down + //Other SpW codes: + static const ReturnValue_t SPW_CREDIT = MAKE_RETURN_CODE(0xF1); + static const ReturnValue_t SPW_ESCAPE = MAKE_RETURN_CODE(0xF2); + static const ReturnValue_t SPW_DISCONNECT = MAKE_RETURN_CODE(0xF3); + static const ReturnValue_t SPW_PARITY = MAKE_RETURN_CODE(0xF4); + static const ReturnValue_t SPW_WRITE_SYNC = MAKE_RETURN_CODE(0xF5); + static const ReturnValue_t SPW_INVALID_ADDRESS = MAKE_RETURN_CODE(0xF6); + static const ReturnValue_t SPW_EARLY_EOP = MAKE_RETURN_CODE(0xF7); + static const ReturnValue_t SPW_DMA = MAKE_RETURN_CODE(0xF8); + static const ReturnValue_t SPW_LINK_ERROR = MAKE_RETURN_CODE(0xF9); + + + //RMAP standard replies + static const ReturnValue_t REPLY_OK = MAKE_RETURN_CODE(0); + static const ReturnValue_t REPLY_GENERAL_ERROR_CODE = MAKE_RETURN_CODE(1);// The detected error does not fit into the other + // error cases or the node does not support + // further distinction between the errors + static const ReturnValue_t REPLY_UNUSED_PACKET_TYPE_OR_COMMAND_CODE = + MAKE_RETURN_CODE(2); // The Header CRC was decoded correctly but + // the packet type is reserved or the command + // is not used by the RMAP protocol. + static const ReturnValue_t REPLY_INVALID_KEY = MAKE_RETURN_CODE(3); // The Header CRC was decoded correctly but + // the device key did not match that expected + // by the target user application + static const ReturnValue_t REPLY_INVALID_DATA_CRC = MAKE_RETURN_CODE(4);// Error in the CRC of the data field + static const ReturnValue_t REPLY_EARLY_EOP = MAKE_RETURN_CODE(5);// EOP marker detected before the end of the data + static const ReturnValue_t REPLY_TOO_MUCH_DATA = MAKE_RETURN_CODE(6);// More than the expected amount of data in a + // command has been received + static const ReturnValue_t REPLY_EEP = MAKE_RETURN_CODE(7); // EEP marker detected immediately after the + // header CRC or during the transfer of data + // and Data CRC or immediately thereafter. + // Indicates that there was a communication + // failure of some sort on the network + static const ReturnValue_t REPLY_RESERVED = MAKE_RETURN_CODE(8);// Reserved + static const ReturnValue_t REPLY_VERIFY_BUFFER_OVERRUN = MAKE_RETURN_CODE( + 9); // The verify before write bit of the command + // was set so that the data field was buffered in + // order to verify the Data CRC before + // transferring the data to target memory. The + // data field was longer than able to fit inside + // the verify buffer resulting in a buffer overrun + // Note that the command is not executed in + // this case + static const ReturnValue_t REPLY_COMMAND_NOT_IMPLEMENTED_OR_NOT_AUTHORISED = + MAKE_RETURN_CODE(10);// The target user application did not authorise + // the requested operation. This may be because + // the command requested has not been + // implemented + static const ReturnValue_t REPLY_RMW_DATA_LENGTH_ERROR = MAKE_RETURN_CODE( + 11); // The amount of data in a RMW command is + // invalid (0x01 0x03 0x05 0x07 or greater + // than 0x08) + static const ReturnValue_t REPLY_INVALID_TARGET_LOGICAL_ADDRESS = + MAKE_RETURN_CODE(12); // The Header CRC was decoded correctly but + // the Target Logical Address was not the value + // expected by the target + + /** + * Resets the underlying channel. + * + * @param cookie The cookie which points to the channel to reset + * @return + */ + static ReturnValue_t reset(RMAPCookie *cookie); + + /** + * send an RMAP write command + * + * datalen is only 24bit wide, rest will be ignored + * IMPORTANT: the data buffer must be datalen+1 large, as the driver might + * write a CRC sum at data[datalen] + * if you want to send an empty packet, just do datalen = 0 and data = NULL + * + * @param cookie The cookie to write to + * @param buffer the data to write + * @param length length of data + * @return + * - @c COMMAND_NULLPOINTER datalen was != 0 but data was == NULL in write command + * - return codes of RMAPChannelIF::sendCommand() + */ + static ReturnValue_t sendWriteCommand(RMAPCookie *cookie, const uint8_t* buffer, + size_t length); + + /** + * get the reply to a write command + * + * @param cookie the cookie the command was sent with + * @return + * - @c REPLY_MISSMATCH a read command was issued, but getWriteReply called + * - return codes of RMAPChannelIF::getReply() + */ + static ReturnValue_t getWriteReply(RMAPCookie *cookie); + + /** + * @see sendWriteCommand() + * @see getWriteReply() + * + * @param timeout_us the time after the function returns, if no reply was received + * + * @return + * - All of sendWriteCommand() + * - All of getWriteReply() + * - @c REPLY_TIMEOUT timeout + */ + static ReturnValue_t writeBlocking(RMAPCookie *cookie, uint8_t* buffer, + uint32_t length, uint32_t timeout_us); + + /** + * send an RMAP read command + * + * @param cookie to cookie to read from + * @param expLength the expected maximum length of the reply + * @return + * - @c COMMAND_NULLPOINTER datalen was != 0 but data was == NULL in write command, or nullpointer in read command + * - return codes of RMAPChannelIF::sendCommand() + */ + static ReturnValue_t sendReadCommand(RMAPCookie *cookie, + uint32_t expLength); + + /** + * get a reply to an RMAP read command + * + * @param cookie the cookie that was read from + * @param[out] buffer the location of the data + * @param[out] size size of the data + * @return + * - @c COMMAND_NULLPOINTER buffer or size was NULL + * - @c REPLY_MISSMATCH a write command was issued, but getReadReply called + * - return codes of RMAPChannelIF::getReply() + */ + static ReturnValue_t getReadReply(RMAPCookie *cookie, uint8_t **buffer, + size_t *size); + + /** + * @see sendReadCommand() + * @see getReadReply() + * + * @param timeout_us the time after the function returns, if no reply was received + * + * @return + * - All of sendReadCommand() + * - All of getReadReply() + * - @c REPLY_TIMEOUT timeout + */ + static ReturnValue_t readBlocking(RMAPCookie *cookie, uint32_t expLength, + uint8_t** buffer, uint32_t *size, uint32_t timeout_us); + +protected: + RMAP(); +}; + +#endif /* RMAPpp_H_ */ diff --git a/rmap/RMAPChannelIF.h b/rmap/RMAPChannelIF.h index 34623bb3..037d6d27 100644 --- a/rmap/RMAPChannelIF.h +++ b/rmap/RMAPChannelIF.h @@ -1,116 +1,116 @@ -#ifndef RMAPCHANNELIF_H_ -#define RMAPCHANNELIF_H_ - -#include -#include -#include - -class RMAPChannelIF { -public: - virtual ~RMAPChannelIF(){}; - /** - * Reset an RMAP channel - * - * Clears the receive buffer (all received messages are deleted) and resets the descriptor table. - * Also checks for errors in the descriptors and submits them to FDIR (aka stdout) - * - * @param channel to reset - * - * @return - * - @c LINK_DOWN when the link is down and all replies were missed - * - @c COMMAND_CHANNEL_DEACTIVATED if the channel's port is NULL - * - @c RETURN_OK else - */ - virtual ReturnValue_t reset()=0; - - /** - * Check if a channel is active (ie has a port) - * - * @param channel_nr - * @return - * - @c COMMAND_OK if channel is active - * - @c COMMAND_CHANNEL_DEACTIVATED if channel is deactivated - */ - virtual ReturnValue_t isActive()=0; - - /** - * Assign a SpaceWire port to the Channel - * - * @param port Number of the port. SpaceWire devices are mapped to port numbers to allow checking of the validity - * @param dest_addr the destination address used by all packets sent from this channel - * @param src_addr the source address used by all packets sent from this channel and used when checking incoming packets - * @return - * - @c COMMAND_OK if port was changed - * - @c COMMAND_PORT_OUT_OF_RANGE if the port is invalid - */ - virtual ReturnValue_t setPort(int8_t port, uint8_t dest_addr, - uint8_t src_addr)=0; - - /** - * Assign a SpaceWire port to the Channel - * - * same as setPort(int8_t port, uint8_t dest_addr, uint8_t src_addr), only the addresses are left unchanged - * - * @param port Number of the port. SpaceWire devices are mapped to port numbers to allow checking of the validity - * @return - * - @c COMMAND_OK if port was changed - * - @c COMMAND_PORT_OUT_OF_RANGE if the port is invalid - */ - virtual ReturnValue_t setPort(int8_t port)=0; - - /** - * Send an RMAP command - * - * @param cookie the cookie used with this call - * @param instruction the instruction byte that will be sent (this defines if it is a read or write command) - * @param data data to be sent - * @param datalen length of data - * @return - * - @c RETURN_OK - * - @c COMMAND_NO_DESCRIPTORS_AVAILABLE no descriptors available for sending command; command was not sent - * - @c COMMAND_BUFFER_FULL no receiver buffer available for expected len; command was not sent - * - @c COMMAND_TOO_BIG the data that was to be sent was too long for the hw to handle (write command) or the expected len was bigger than maximal expected len (read command) command was not sent - * - @c COMMAND_CHANNEL_DEACTIVATED the channel has no port set - * - @c NOT_SUPPORTED if you dont feel like implementing something... - */ - virtual ReturnValue_t sendCommand(RMAPCookie *cookie, uint8_t instruction, - const uint8_t *data, size_t datalen)=0; - - /** - * get the reply to an rmap command - * - * @param cookie the cookie the command was sent with - * @param databuffer a pointer to a pointer the location of the reply will be written to - * @param len a pointer to the variable the length of the reply will be written to - * @return - * - @c REPLY_NO_REPLY no reply was received - * - @c REPLY_NOT_SENT command was not sent, implies no reply - * - @c REPLY_NOT_YET_SENT command is still waiting to be sent - * - @c WRITE_REPLY_INTERFACE_BUSY Interface is busy (transmission buffer still being processed) - * - @c WRITE_REPLY_TRANSMISSION_ERROR Interface encountered errors during last operation, data could not be processed. (transmission error) - * - @c WRITE_REPLY_INVALID_DATA Invalid data (amount / value) - * - @c WRITE_REPLY_NOT_SUPPORTED - * - all RMAP standard replies - */ - virtual ReturnValue_t getReply(RMAPCookie *cookie, uint8_t **databuffer, - size_t *len)=0; - - /** - * - * @param cookie - * @param data - * @param datalen - * @param databuffer - * @param len - * @param timeout_us - * @return - * - all replies of sendCommand() and getReply() - * - @c REPLY_TIMEOUT timeout - */ - virtual ReturnValue_t sendCommandBlocking(RMAPCookie *cookie, uint8_t *data, - uint32_t datalen, uint8_t **databuffer, uint32_t *len, - uint32_t timeout_us)=0; - -}; - -#endif /* RMAPCHANNELIF_H_ */ +#ifndef RMAPCHANNELIF_H_ +#define RMAPCHANNELIF_H_ + +#include "../rmap/RMAPCookie.h" +#include "../returnvalues/HasReturnvaluesIF.h" +#include + +class RMAPChannelIF { +public: + virtual ~RMAPChannelIF(){}; + /** + * Reset an RMAP channel + * + * Clears the receive buffer (all received messages are deleted) and resets the descriptor table. + * Also checks for errors in the descriptors and submits them to FDIR (aka stdout) + * + * @param channel to reset + * + * @return + * - @c LINK_DOWN when the link is down and all replies were missed + * - @c COMMAND_CHANNEL_DEACTIVATED if the channel's port is NULL + * - @c RETURN_OK else + */ + virtual ReturnValue_t reset()=0; + + /** + * Check if a channel is active (ie has a port) + * + * @param channel_nr + * @return + * - @c COMMAND_OK if channel is active + * - @c COMMAND_CHANNEL_DEACTIVATED if channel is deactivated + */ + virtual ReturnValue_t isActive()=0; + + /** + * Assign a SpaceWire port to the Channel + * + * @param port Number of the port. SpaceWire devices are mapped to port numbers to allow checking of the validity + * @param dest_addr the destination address used by all packets sent from this channel + * @param src_addr the source address used by all packets sent from this channel and used when checking incoming packets + * @return + * - @c COMMAND_OK if port was changed + * - @c COMMAND_PORT_OUT_OF_RANGE if the port is invalid + */ + virtual ReturnValue_t setPort(int8_t port, uint8_t dest_addr, + uint8_t src_addr)=0; + + /** + * Assign a SpaceWire port to the Channel + * + * same as setPort(int8_t port, uint8_t dest_addr, uint8_t src_addr), only the addresses are left unchanged + * + * @param port Number of the port. SpaceWire devices are mapped to port numbers to allow checking of the validity + * @return + * - @c COMMAND_OK if port was changed + * - @c COMMAND_PORT_OUT_OF_RANGE if the port is invalid + */ + virtual ReturnValue_t setPort(int8_t port)=0; + + /** + * Send an RMAP command + * + * @param cookie the cookie used with this call + * @param instruction the instruction byte that will be sent (this defines if it is a read or write command) + * @param data data to be sent + * @param datalen length of data + * @return + * - @c RETURN_OK + * - @c COMMAND_NO_DESCRIPTORS_AVAILABLE no descriptors available for sending command; command was not sent + * - @c COMMAND_BUFFER_FULL no receiver buffer available for expected len; command was not sent + * - @c COMMAND_TOO_BIG the data that was to be sent was too long for the hw to handle (write command) or the expected len was bigger than maximal expected len (read command) command was not sent + * - @c COMMAND_CHANNEL_DEACTIVATED the channel has no port set + * - @c NOT_SUPPORTED if you dont feel like implementing something... + */ + virtual ReturnValue_t sendCommand(RMAPCookie *cookie, uint8_t instruction, + const uint8_t *data, size_t datalen)=0; + + /** + * get the reply to an rmap command + * + * @param cookie the cookie the command was sent with + * @param databuffer a pointer to a pointer the location of the reply will be written to + * @param len a pointer to the variable the length of the reply will be written to + * @return + * - @c REPLY_NO_REPLY no reply was received + * - @c REPLY_NOT_SENT command was not sent, implies no reply + * - @c REPLY_NOT_YET_SENT command is still waiting to be sent + * - @c WRITE_REPLY_INTERFACE_BUSY Interface is busy (transmission buffer still being processed) + * - @c WRITE_REPLY_TRANSMISSION_ERROR Interface encountered errors during last operation, data could not be processed. (transmission error) + * - @c WRITE_REPLY_INVALID_DATA Invalid data (amount / value) + * - @c WRITE_REPLY_NOT_SUPPORTED + * - all RMAP standard replies + */ + virtual ReturnValue_t getReply(RMAPCookie *cookie, uint8_t **databuffer, + size_t *len)=0; + + /** + * + * @param cookie + * @param data + * @param datalen + * @param databuffer + * @param len + * @param timeout_us + * @return + * - all replies of sendCommand() and getReply() + * - @c REPLY_TIMEOUT timeout + */ + virtual ReturnValue_t sendCommandBlocking(RMAPCookie *cookie, uint8_t *data, + uint32_t datalen, uint8_t **databuffer, uint32_t *len, + uint32_t timeout_us)=0; + +}; + +#endif /* RMAPCHANNELIF_H_ */ diff --git a/rmap/RMAPCookie.cpp b/rmap/RMAPCookie.cpp index 223b5165..74101ffa 100644 --- a/rmap/RMAPCookie.cpp +++ b/rmap/RMAPCookie.cpp @@ -1,124 +1,124 @@ -#include -#include -#include - - -RMAPCookie::RMAPCookie() { - this->header.dest_address = 0; - this->header.protocol = 0x01; - this->header.instruction = 0; - this->header.dest_key = 0; - this->header.source_address = 0; - this->header.tid_h = 0; - this->header.tid_l = 0; - this->header.extended_address = 0; - this->header.address_hh = 0; - this->header.address_h = 0; - this->header.address_l = 0; - this->header.address_ll = 0; - this->header.datalen_h = 0; - this->header.datalen_m = 0; - this->header.datalen_l = 0; - this->header.header_crc = 0; - this->channel = NULL; - this->command_mask = 0; - - this->dataCRC = 0; - - this->maxReplyLen = 0; -} - - - -RMAPCookie::RMAPCookie(uint32_t set_address, uint8_t set_extended_address, - RMAPChannelIF *set_channel, uint8_t set_command_mask, uint32_t maxReplyLen) { - this->header.dest_address = 0; - this->header.protocol = 0x01; - this->header.instruction = 0; - this->header.dest_key = 0; - this->header.source_address = 0; - this->header.tid_h = 0; - this->header.tid_l = 0; - this->header.extended_address = set_extended_address; - setAddress(set_address); - this->header.datalen_h = 0; - this->header.datalen_m = 0; - this->header.datalen_l = 0; - this->header.header_crc = 0; - this->channel = set_channel; - this->command_mask = set_command_mask; - this->dataCRC = 0; - - this->maxReplyLen = maxReplyLen; -} - - -void RMAPCookie::setAddress(uint32_t address) { - this->header.address_hh = (address & 0xFF000000) >> 24; - this->header.address_h = (address & 0x00FF0000) >> 16; - this->header.address_l = (address & 0x0000FF00) >> 8; - this->header.address_ll = address & 0x000000FF; -} - -void RMAPCookie::setExtendedAddress(uint8_t extendedAddress) { - this->header.extended_address = extendedAddress; -} - -void RMAPCookie::setChannel(RMAPChannelIF *channel) { - this->channel = channel; -} - -void RMAPCookie::setCommandMask(uint8_t commandMask) { - this->command_mask = commandMask; -} - -uint32_t RMAPCookie::getAddress() { - return (header.address_hh << 24) + (header.address_h << 16) - + (header.address_l << 8) + (header.address_ll); -} - -uint8_t RMAPCookie::getExtendedAddress() { - return header.extended_address; -} - -RMAPChannelIF *RMAPCookie::getChannel() { - return channel; -} - -uint8_t RMAPCookie::getCommandMask() { - return command_mask; -} - -RMAPCookie::~RMAPCookie() { - -} - -size_t RMAPCookie::getMaxReplyLen() const { - return maxReplyLen; -} - -void RMAPCookie::setMaxReplyLen(size_t maxReplyLen) { - this->maxReplyLen = maxReplyLen; -} - -RMAPStructs::rmap_cmd_header* RMAPCookie::getHeader(){ - return &this->header; -} - -uint16_t RMAPCookie::getTransactionIdentifier() const { - return static_cast((header.tid_h << 8) | (header.tid_l)); -} - -void RMAPCookie::setTransactionIdentifier(uint16_t id_) { - header.tid_l = id_ & 0xFF; - header.tid_h = (id_ >> 8 ) & 0xFF; -} - -uint32_t RMAPCookie::getDataLength() const { - return static_cast(header.datalen_h << 16 | header.datalen_m << 8 | header.datalen_l); -} -void RMAPCookie::setDataLength(uint32_t length_) { - header.datalen_l = length_ & 0xff; - header.datalen_m = (length_ >> 8) & 0xff; - header.datalen_h = (length_ >> 16) & 0xff; -} +#include "../rmap/RMAPChannelIF.h" +#include "../rmap/RMAPCookie.h" +#include + + +RMAPCookie::RMAPCookie() { + this->header.dest_address = 0; + this->header.protocol = 0x01; + this->header.instruction = 0; + this->header.dest_key = 0; + this->header.source_address = 0; + this->header.tid_h = 0; + this->header.tid_l = 0; + this->header.extended_address = 0; + this->header.address_hh = 0; + this->header.address_h = 0; + this->header.address_l = 0; + this->header.address_ll = 0; + this->header.datalen_h = 0; + this->header.datalen_m = 0; + this->header.datalen_l = 0; + this->header.header_crc = 0; + this->channel = NULL; + this->command_mask = 0; + + this->dataCRC = 0; + + this->maxReplyLen = 0; +} + + + +RMAPCookie::RMAPCookie(uint32_t set_address, uint8_t set_extended_address, + RMAPChannelIF *set_channel, uint8_t set_command_mask, uint32_t maxReplyLen) { + this->header.dest_address = 0; + this->header.protocol = 0x01; + this->header.instruction = 0; + this->header.dest_key = 0; + this->header.source_address = 0; + this->header.tid_h = 0; + this->header.tid_l = 0; + this->header.extended_address = set_extended_address; + setAddress(set_address); + this->header.datalen_h = 0; + this->header.datalen_m = 0; + this->header.datalen_l = 0; + this->header.header_crc = 0; + this->channel = set_channel; + this->command_mask = set_command_mask; + this->dataCRC = 0; + + this->maxReplyLen = maxReplyLen; +} + + +void RMAPCookie::setAddress(uint32_t address) { + this->header.address_hh = (address & 0xFF000000) >> 24; + this->header.address_h = (address & 0x00FF0000) >> 16; + this->header.address_l = (address & 0x0000FF00) >> 8; + this->header.address_ll = address & 0x000000FF; +} + +void RMAPCookie::setExtendedAddress(uint8_t extendedAddress) { + this->header.extended_address = extendedAddress; +} + +void RMAPCookie::setChannel(RMAPChannelIF *channel) { + this->channel = channel; +} + +void RMAPCookie::setCommandMask(uint8_t commandMask) { + this->command_mask = commandMask; +} + +uint32_t RMAPCookie::getAddress() { + return (header.address_hh << 24) + (header.address_h << 16) + + (header.address_l << 8) + (header.address_ll); +} + +uint8_t RMAPCookie::getExtendedAddress() { + return header.extended_address; +} + +RMAPChannelIF *RMAPCookie::getChannel() { + return channel; +} + +uint8_t RMAPCookie::getCommandMask() { + return command_mask; +} + +RMAPCookie::~RMAPCookie() { + +} + +size_t RMAPCookie::getMaxReplyLen() const { + return maxReplyLen; +} + +void RMAPCookie::setMaxReplyLen(size_t maxReplyLen) { + this->maxReplyLen = maxReplyLen; +} + +RMAPStructs::rmap_cmd_header* RMAPCookie::getHeader(){ + return &this->header; +} + +uint16_t RMAPCookie::getTransactionIdentifier() const { + return static_cast((header.tid_h << 8) | (header.tid_l)); +} + +void RMAPCookie::setTransactionIdentifier(uint16_t id_) { + header.tid_l = id_ & 0xFF; + header.tid_h = (id_ >> 8 ) & 0xFF; +} + +uint32_t RMAPCookie::getDataLength() const { + return static_cast(header.datalen_h << 16 | header.datalen_m << 8 | header.datalen_l); +} +void RMAPCookie::setDataLength(uint32_t length_) { + header.datalen_l = length_ & 0xff; + header.datalen_m = (length_ >> 8) & 0xff; + header.datalen_h = (length_ >> 16) & 0xff; +} diff --git a/rmap/RMAPCookie.h b/rmap/RMAPCookie.h index 99ebd6a2..0da03e30 100644 --- a/rmap/RMAPCookie.h +++ b/rmap/RMAPCookie.h @@ -1,59 +1,59 @@ -#ifndef RMAPCOOKIE_H_ -#define RMAPCOOKIE_H_ - -#include -#include -#include - -class RMAPChannelIF; - -class RMAPCookie : public CookieIF { -public: - //To Uli: Sorry, I need an empty ctor to initialize an array of cookies. - RMAPCookie(); - - RMAPCookie(uint32_t set_address, uint8_t set_extended_address, - RMAPChannelIF *set_channel, uint8_t set_command_mask, uint32_t maxReplyLen = 0); - virtual ~RMAPCookie(); - - - void setAddress(uint32_t address); - uint32_t getAddress(); - - void setExtendedAddress(uint8_t); - uint8_t getExtendedAddress(); - - void setChannel(RMAPChannelIF *channel); - RMAPChannelIF *getChannel(); - - void setCommandMask(uint8_t commandMask); - uint8_t getCommandMask(); - - size_t getMaxReplyLen() const; - void setMaxReplyLen(size_t maxReplyLen); - - uint16_t getTransactionIdentifier() const; - void setTransactionIdentifier(uint16_t id_); - - RMAPStructs::rmap_cmd_header* getHeader(); - - uint32_t getDataLength() const; - void setDataLength(uint32_t lenght_); - - uint8_t getDataCrc() const { - return dataCRC; - } - - void setDataCrc(uint8_t dataCrc) { - dataCRC = dataCrc; - } - -protected: - RMAPStructs::rmap_cmd_header header; - RMAPChannelIF *channel; - uint8_t command_mask; - uint32_t maxReplyLen; - uint8_t dataCRC; -}; - -#endif /* RMAPCOOKIE_H_ */ +#ifndef RMAPCOOKIE_H_ +#define RMAPCOOKIE_H_ + +#include "../devicehandlers/CookieIF.h" +#include "../rmap/rmapStructs.h" +#include + +class RMAPChannelIF; + +class RMAPCookie : public CookieIF { +public: + //To Uli: Sorry, I need an empty ctor to initialize an array of cookies. + RMAPCookie(); + + RMAPCookie(uint32_t set_address, uint8_t set_extended_address, + RMAPChannelIF *set_channel, uint8_t set_command_mask, uint32_t maxReplyLen = 0); + virtual ~RMAPCookie(); + + + void setAddress(uint32_t address); + uint32_t getAddress(); + + void setExtendedAddress(uint8_t); + uint8_t getExtendedAddress(); + + void setChannel(RMAPChannelIF *channel); + RMAPChannelIF *getChannel(); + + void setCommandMask(uint8_t commandMask); + uint8_t getCommandMask(); + + size_t getMaxReplyLen() const; + void setMaxReplyLen(size_t maxReplyLen); + + uint16_t getTransactionIdentifier() const; + void setTransactionIdentifier(uint16_t id_); + + RMAPStructs::rmap_cmd_header* getHeader(); + + uint32_t getDataLength() const; + void setDataLength(uint32_t lenght_); + + uint8_t getDataCrc() const { + return dataCRC; + } + + void setDataCrc(uint8_t dataCrc) { + dataCRC = dataCrc; + } + +protected: + RMAPStructs::rmap_cmd_header header; + RMAPChannelIF *channel; + uint8_t command_mask; + uint32_t maxReplyLen; + uint8_t dataCRC; +}; + +#endif /* RMAPCOOKIE_H_ */ diff --git a/rmap/RmapDeviceCommunicationIF.cpp b/rmap/RmapDeviceCommunicationIF.cpp index 6dc91339..36247ce6 100644 --- a/rmap/RmapDeviceCommunicationIF.cpp +++ b/rmap/RmapDeviceCommunicationIF.cpp @@ -1,47 +1,47 @@ -#include -#include - -//TODO Cast here are all potential bugs -RmapDeviceCommunicationIF::~RmapDeviceCommunicationIF() { -} - -ReturnValue_t RmapDeviceCommunicationIF::sendMessage(CookieIF *cookie, - const uint8_t * sendData, size_t sendLen) { - return RMAP::sendWriteCommand((RMAPCookie *) cookie, sendData, sendLen); -} - -ReturnValue_t RmapDeviceCommunicationIF::getSendSuccess(CookieIF* cookie) { - return RMAP::getWriteReply((RMAPCookie *) cookie); -} - -ReturnValue_t RmapDeviceCommunicationIF::requestReceiveMessage( - CookieIF *cookie, size_t requestLen) { - return RMAP::sendReadCommand((RMAPCookie *) cookie, - ((RMAPCookie *) cookie)->getMaxReplyLen()); -} - -ReturnValue_t RmapDeviceCommunicationIF::readReceivedMessage(CookieIF* cookie, - uint8_t** buffer, size_t * size) { - return RMAP::getReadReply((RMAPCookie *) cookie, buffer, size); -} - -ReturnValue_t RmapDeviceCommunicationIF::setAddress(CookieIF* cookie, - uint32_t address) { - - ((RMAPCookie *) cookie)->setAddress(address); - return HasReturnvaluesIF::RETURN_OK; -} - -uint32_t RmapDeviceCommunicationIF::getAddress(CookieIF* cookie) { - return ((RMAPCookie *) cookie)->getAddress(); -} - -ReturnValue_t RmapDeviceCommunicationIF::setParameter(CookieIF* cookie, - uint32_t parameter) { - //TODO Empty? - return HasReturnvaluesIF::RETURN_FAILED; -} - -uint32_t RmapDeviceCommunicationIF::getParameter(CookieIF* cookie) { - return 0; -} +#include "../rmap/RmapDeviceCommunicationIF.h" +#include "../rmap/RMAP.h" + +//TODO Cast here are all potential bugs +RmapDeviceCommunicationIF::~RmapDeviceCommunicationIF() { +} + +ReturnValue_t RmapDeviceCommunicationIF::sendMessage(CookieIF *cookie, + const uint8_t * sendData, size_t sendLen) { + return RMAP::sendWriteCommand((RMAPCookie *) cookie, sendData, sendLen); +} + +ReturnValue_t RmapDeviceCommunicationIF::getSendSuccess(CookieIF* cookie) { + return RMAP::getWriteReply((RMAPCookie *) cookie); +} + +ReturnValue_t RmapDeviceCommunicationIF::requestReceiveMessage( + CookieIF *cookie, size_t requestLen) { + return RMAP::sendReadCommand((RMAPCookie *) cookie, + ((RMAPCookie *) cookie)->getMaxReplyLen()); +} + +ReturnValue_t RmapDeviceCommunicationIF::readReceivedMessage(CookieIF* cookie, + uint8_t** buffer, size_t * size) { + return RMAP::getReadReply((RMAPCookie *) cookie, buffer, size); +} + +ReturnValue_t RmapDeviceCommunicationIF::setAddress(CookieIF* cookie, + uint32_t address) { + + ((RMAPCookie *) cookie)->setAddress(address); + return HasReturnvaluesIF::RETURN_OK; +} + +uint32_t RmapDeviceCommunicationIF::getAddress(CookieIF* cookie) { + return ((RMAPCookie *) cookie)->getAddress(); +} + +ReturnValue_t RmapDeviceCommunicationIF::setParameter(CookieIF* cookie, + uint32_t parameter) { + //TODO Empty? + return HasReturnvaluesIF::RETURN_FAILED; +} + +uint32_t RmapDeviceCommunicationIF::getParameter(CookieIF* cookie) { + return 0; +} diff --git a/rmap/RmapDeviceCommunicationIF.h b/rmap/RmapDeviceCommunicationIF.h index 12bac57a..b0564193 100644 --- a/rmap/RmapDeviceCommunicationIF.h +++ b/rmap/RmapDeviceCommunicationIF.h @@ -1,89 +1,89 @@ -#ifndef MISSION_RMAP_RMAPDEVICECOMMUNICATIONINTERFACE_H_ -#define MISSION_RMAP_RMAPDEVICECOMMUNICATIONINTERFACE_H_ - -#include - -/** - * @brief This class is a implementation of a DeviceCommunicationIF for RMAP calls. - * It expects RMAPCookies or a derived class of RMAPCookies - * - * @details The open, close and reOpen calls are mission specific - * The open call might return any child of RMAPCookies - * - * \ingroup rmap - */ -class RmapDeviceCommunicationIF: public DeviceCommunicationIF { - -public: - virtual ~RmapDeviceCommunicationIF(); - - /** - * @brief Device specific initialization, using the cookie. - * @details - * The cookie is already prepared in the factory. If the communication - * interface needs to be set up in some way and requires cookie information, - * this can be performed in this function, which is called on device handler - * initialization. - * @param cookie - * @return -@c RETURN_OK if initialization was successfull - * - Everything else triggers failure event with returnvalue as parameter 1 - */ - virtual ReturnValue_t initializeInterface(CookieIF * cookie) = 0; - - /** - * Called by DHB in the SEND_WRITE doSendWrite(). - * This function is used to send data to the physical device - * by implementing and calling related drivers or wrapper functions. - * @param cookie - * @param data - * @param len - * @return -@c RETURN_OK for successfull send - * - Everything else triggers failure event with returnvalue as parameter 1 - */ - virtual ReturnValue_t sendMessage(CookieIF *cookie, const uint8_t * sendData, - size_t sendLen); - - /** - * Called by DHB in the GET_WRITE doGetWrite(). - * Get send confirmation that the data in sendMessage() was sent successfully. - * @param cookie - * @return -@c RETURN_OK if data was sent successfull - * - Everything else triggers falure event with returnvalue as parameter 1 - */ - virtual ReturnValue_t getSendSuccess(CookieIF *cookie); - - /** - * Called by DHB in the SEND_WRITE doSendRead(). - * It is assumed that it is always possible to request a reply - * from a device. - * - * @param cookie - * @return -@c RETURN_OK to confirm the request for data has been sent. - * -@c NO_READ_REQUEST if no request shall be made. readReceivedMessage() - * will not be called in the respective communication cycle. - * - Everything else triggers failure event with returnvalue as parameter 1 - */ - virtual ReturnValue_t requestReceiveMessage(CookieIF *cookie, size_t requestLen); - - /** - * Called by DHB in the GET_WRITE doGetRead(). - * This function is used to receive data from the physical device - * by implementing and calling related drivers or wrapper functions. - * @param cookie - * @param data - * @param len - * @return @c RETURN_OK for successfull receive - * - Everything else triggers failure event with returnvalue as parameter 1 - */ - virtual ReturnValue_t readReceivedMessage(CookieIF *cookie, uint8_t **buffer, - size_t *size); - - ReturnValue_t setAddress(CookieIF* cookie, - uint32_t address); - uint32_t getAddress(CookieIF* cookie); - ReturnValue_t setParameter(CookieIF* cookie, - uint32_t parameter); - uint32_t getParameter(CookieIF* cookie); -}; - -#endif /* MISSION_RMAP_RMAPDEVICECOMMUNICATIONINTERFACE_H_ */ +#ifndef MISSION_RMAP_RMAPDEVICECOMMUNICATIONINTERFACE_H_ +#define MISSION_RMAP_RMAPDEVICECOMMUNICATIONINTERFACE_H_ + +#include "../devicehandlers/DeviceCommunicationIF.h" + +/** + * @brief This class is a implementation of a DeviceCommunicationIF for RMAP calls. + * It expects RMAPCookies or a derived class of RMAPCookies + * + * @details The open, close and reOpen calls are mission specific + * The open call might return any child of RMAPCookies + * + * \ingroup rmap + */ +class RmapDeviceCommunicationIF: public DeviceCommunicationIF { + +public: + virtual ~RmapDeviceCommunicationIF(); + + /** + * @brief Device specific initialization, using the cookie. + * @details + * The cookie is already prepared in the factory. If the communication + * interface needs to be set up in some way and requires cookie information, + * this can be performed in this function, which is called on device handler + * initialization. + * @param cookie + * @return -@c RETURN_OK if initialization was successfull + * - Everything else triggers failure event with returnvalue as parameter 1 + */ + virtual ReturnValue_t initializeInterface(CookieIF * cookie) = 0; + + /** + * Called by DHB in the SEND_WRITE doSendWrite(). + * This function is used to send data to the physical device + * by implementing and calling related drivers or wrapper functions. + * @param cookie + * @param data + * @param len + * @return -@c RETURN_OK for successfull send + * - Everything else triggers failure event with returnvalue as parameter 1 + */ + virtual ReturnValue_t sendMessage(CookieIF *cookie, const uint8_t * sendData, + size_t sendLen); + + /** + * Called by DHB in the GET_WRITE doGetWrite(). + * Get send confirmation that the data in sendMessage() was sent successfully. + * @param cookie + * @return -@c RETURN_OK if data was sent successfull + * - Everything else triggers falure event with returnvalue as parameter 1 + */ + virtual ReturnValue_t getSendSuccess(CookieIF *cookie); + + /** + * Called by DHB in the SEND_WRITE doSendRead(). + * It is assumed that it is always possible to request a reply + * from a device. + * + * @param cookie + * @return -@c RETURN_OK to confirm the request for data has been sent. + * -@c NO_READ_REQUEST if no request shall be made. readReceivedMessage() + * will not be called in the respective communication cycle. + * - Everything else triggers failure event with returnvalue as parameter 1 + */ + virtual ReturnValue_t requestReceiveMessage(CookieIF *cookie, size_t requestLen); + + /** + * Called by DHB in the GET_WRITE doGetRead(). + * This function is used to receive data from the physical device + * by implementing and calling related drivers or wrapper functions. + * @param cookie + * @param data + * @param len + * @return @c RETURN_OK for successfull receive + * - Everything else triggers failure event with returnvalue as parameter 1 + */ + virtual ReturnValue_t readReceivedMessage(CookieIF *cookie, uint8_t **buffer, + size_t *size); + + ReturnValue_t setAddress(CookieIF* cookie, + uint32_t address); + uint32_t getAddress(CookieIF* cookie); + ReturnValue_t setParameter(CookieIF* cookie, + uint32_t parameter); + uint32_t getParameter(CookieIF* cookie); +}; + +#endif /* MISSION_RMAP_RMAPDEVICECOMMUNICATIONINTERFACE_H_ */ diff --git a/serialize/EndianConverter.h b/serialize/EndianConverter.h index 81117a5e..fae10bca 100644 --- a/serialize/EndianConverter.h +++ b/serialize/EndianConverter.h @@ -1,124 +1,124 @@ -#ifndef ENDIANSWAPPER_H_ -#define ENDIANSWAPPER_H_ - -#include -#include -#include - -/** - * Helper class to convert variables or bitstreams between machine - * endian and either big or little endian. - * Machine endian is the endianness used by the machine running the - * program and is one of big or little endian. As this is portable - * code, it is not known at coding time which it is. At compile time - * it is however, which is why this is implemented using compiler - * macros and translates to a copy operation at runtime. - * - * This changes the layout of multi-byte variables in the machine's - * memory. In most cases, you should not need to use this class. - * Probably what you are looking for is the SerializeAdapter. - * If you still decide you need this class, please read and understand - * the code first. - * - * The order of the individual bytes of the multi-byte variable is - * reversed, the byte at the highest address is moved to the lowest - * address and vice versa, same for the bytes in between. - * - * Note that the conversion is also its inversion, that is converting - * from machine to a specified endianness is the same operation as - * converting from specified to machine (I looked it up, mathematicians - * would call it an involution): - * - * X == convertBigEndian(convertBigEndian(X)) - * - * Thus, there is only one function supplied to do the conversion. - */ -class EndianConverter { -private: - EndianConverter() {}; -public: - /** - * Convert a typed variable between big endian and machine endian. - * Intended for plain old datatypes. - */ - template - static T convertBigEndian(T in) { -#ifndef BYTE_ORDER_SYSTEM -#error BYTE_ORDER_SYSTEM not defined -#elif BYTE_ORDER_SYSTEM == LITTLE_ENDIAN - T tmp; - uint8_t *pointerOut = (uint8_t*) &tmp; - uint8_t *pointerIn = (uint8_t*) ∈ - for (size_t count = 0; count < sizeof(T); count++) { - pointerOut[sizeof(T) - count - 1] = pointerIn[count]; - } - return tmp; -#elif BYTE_ORDER_SYSTEM == BIG_ENDIAN - return in; -#else -#error Unknown Byte Order -#endif - } - - /** - * convert a bytestream representing a single variable between big endian - * and machine endian. - */ - static void convertBigEndian(uint8_t *out, const uint8_t *in, - size_t size) { -#ifndef BYTE_ORDER_SYSTEM -#error BYTE_ORDER_SYSTEM not defined -#elif BYTE_ORDER_SYSTEM == LITTLE_ENDIAN - for (size_t count = 0; count < size; count++) { - out[size - count - 1] = in[count]; - } - return; -#elif BYTE_ORDER_SYSTEM == BIG_ENDIAN - memcpy(out, in, size); - return; -#endif - } - - /** - * Convert a typed variable between little endian and machine endian. - * Intended for plain old datatypes. - */ - template - static T convertLittleEndian(T in) { -#ifndef BYTE_ORDER_SYSTEM - #error BYTE_ORDER_SYSTEM not defined - #elif BYTE_ORDER_SYSTEM == BIG_ENDIAN - T tmp; - uint8_t *pointerOut = (uint8_t *) &tmp; - uint8_t *pointerIn = (uint8_t *) ∈ - for (size_t count = 0; count < sizeof(T); count++) { - pointerOut[sizeof(T) - count - 1] = pointerIn[count]; - } - return tmp; - #elif BYTE_ORDER_SYSTEM == LITTLE_ENDIAN - return in; -#else - #error Unknown Byte Order - #endif - } - /** - * convert a bytestream representing a single variable between little endian - * and machine endian. - */ - static void convertLittleEndian(uint8_t *out, const uint8_t *in, - size_t size) { -#ifndef BYTE_ORDER_SYSTEM - #error BYTE_ORDER_SYSTEM not defined - #elif BYTE_ORDER_SYSTEM == BIG_ENDIAN - for (size_t count = 0; count < size; count++) { - out[size - count - 1] = in[count]; - } - return; - #elif BYTE_ORDER_SYSTEM == LITTLE_ENDIAN - memcpy(out, in, size); - return; -#endif - } -}; - -#endif /* ENDIANSWAPPER_H_ */ +#ifndef ENDIANSWAPPER_H_ +#define ENDIANSWAPPER_H_ + +#include "../osal/Endiness.h" +#include +#include + +/** + * Helper class to convert variables or bitstreams between machine + * endian and either big or little endian. + * Machine endian is the endianness used by the machine running the + * program and is one of big or little endian. As this is portable + * code, it is not known at coding time which it is. At compile time + * it is however, which is why this is implemented using compiler + * macros and translates to a copy operation at runtime. + * + * This changes the layout of multi-byte variables in the machine's + * memory. In most cases, you should not need to use this class. + * Probably what you are looking for is the SerializeAdapter. + * If you still decide you need this class, please read and understand + * the code first. + * + * The order of the individual bytes of the multi-byte variable is + * reversed, the byte at the highest address is moved to the lowest + * address and vice versa, same for the bytes in between. + * + * Note that the conversion is also its inversion, that is converting + * from machine to a specified endianness is the same operation as + * converting from specified to machine (I looked it up, mathematicians + * would call it an involution): + * + * X == convertBigEndian(convertBigEndian(X)) + * + * Thus, there is only one function supplied to do the conversion. + */ +class EndianConverter { +private: + EndianConverter() {}; +public: + /** + * Convert a typed variable between big endian and machine endian. + * Intended for plain old datatypes. + */ + template + static T convertBigEndian(T in) { +#ifndef BYTE_ORDER_SYSTEM +#error BYTE_ORDER_SYSTEM not defined +#elif BYTE_ORDER_SYSTEM == LITTLE_ENDIAN + T tmp; + uint8_t *pointerOut = (uint8_t*) &tmp; + uint8_t *pointerIn = (uint8_t*) ∈ + for (size_t count = 0; count < sizeof(T); count++) { + pointerOut[sizeof(T) - count - 1] = pointerIn[count]; + } + return tmp; +#elif BYTE_ORDER_SYSTEM == BIG_ENDIAN + return in; +#else +#error Unknown Byte Order +#endif + } + + /** + * convert a bytestream representing a single variable between big endian + * and machine endian. + */ + static void convertBigEndian(uint8_t *out, const uint8_t *in, + size_t size) { +#ifndef BYTE_ORDER_SYSTEM +#error BYTE_ORDER_SYSTEM not defined +#elif BYTE_ORDER_SYSTEM == LITTLE_ENDIAN + for (size_t count = 0; count < size; count++) { + out[size - count - 1] = in[count]; + } + return; +#elif BYTE_ORDER_SYSTEM == BIG_ENDIAN + memcpy(out, in, size); + return; +#endif + } + + /** + * Convert a typed variable between little endian and machine endian. + * Intended for plain old datatypes. + */ + template + static T convertLittleEndian(T in) { +#ifndef BYTE_ORDER_SYSTEM + #error BYTE_ORDER_SYSTEM not defined + #elif BYTE_ORDER_SYSTEM == BIG_ENDIAN + T tmp; + uint8_t *pointerOut = (uint8_t *) &tmp; + uint8_t *pointerIn = (uint8_t *) ∈ + for (size_t count = 0; count < sizeof(T); count++) { + pointerOut[sizeof(T) - count - 1] = pointerIn[count]; + } + return tmp; + #elif BYTE_ORDER_SYSTEM == LITTLE_ENDIAN + return in; +#else + #error Unknown Byte Order + #endif + } + /** + * convert a bytestream representing a single variable between little endian + * and machine endian. + */ + static void convertLittleEndian(uint8_t *out, const uint8_t *in, + size_t size) { +#ifndef BYTE_ORDER_SYSTEM + #error BYTE_ORDER_SYSTEM not defined + #elif BYTE_ORDER_SYSTEM == BIG_ENDIAN + for (size_t count = 0; count < size; count++) { + out[size - count - 1] = in[count]; + } + return; + #elif BYTE_ORDER_SYSTEM == LITTLE_ENDIAN + memcpy(out, in, size); + return; +#endif + } +}; + +#endif /* ENDIANSWAPPER_H_ */ diff --git a/serialize/SerialArrayListAdapter.h b/serialize/SerialArrayListAdapter.h index 17a4558f..19190abd 100644 --- a/serialize/SerialArrayListAdapter.h +++ b/serialize/SerialArrayListAdapter.h @@ -1,91 +1,91 @@ -/** - * @file SerialArrayListAdapter.h - * @brief This file defines the SerialArrayListAdapter class. - * @date 22.07.2014 - * @author baetz - */ -#ifndef SERIALARRAYLISTADAPTER_H_ -#define SERIALARRAYLISTADAPTER_H_ - -#include -#include -#include - -/** - * Also serializes length field ! - * @ingroup serialize - */ -template -class SerialArrayListAdapter : public SerializeIF { -public: - SerialArrayListAdapter(ArrayList *adaptee) : adaptee(adaptee) { - } - - virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) const { - return serialize(adaptee, buffer, size, maxSize, streamEndianness); - } - - static ReturnValue_t serialize(const ArrayList* list, uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) { - ReturnValue_t result = SerializeAdapter::serialize(&list->size, - buffer, size, maxSize, streamEndianness); - count_t i = 0; - while ((result == HasReturnvaluesIF::RETURN_OK) && (i < list->size)) { - result = SerializeAdapter::serialize(&list->entries[i], buffer, size, - maxSize, streamEndianness); - ++i; - } - return result; - } - - virtual size_t getSerializedSize() const { - return getSerializedSize(adaptee); - } - - static uint32_t getSerializedSize(const ArrayList* list) { - uint32_t printSize = sizeof(count_t); - count_t i = 0; - - for (i = 0; i < list->size; ++i) { - printSize += SerializeAdapter::getSerializedSize(&list->entries[i]); - } - - return printSize; - } - - virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - Endianness streamEndianness) { - return deSerialize(adaptee, buffer, size, streamEndianness); - } - - static ReturnValue_t deSerialize(ArrayList* list, const uint8_t** buffer, size_t* size, - Endianness streamEndianness) { - count_t tempSize = 0; - ReturnValue_t result = SerializeAdapter::deSerialize(&tempSize, - buffer, size, streamEndianness); - if (tempSize > list->maxSize()) { - return SerializeIF::TOO_MANY_ELEMENTS; - } - list->size = tempSize; - count_t i = 0; - while ((result == HasReturnvaluesIF::RETURN_OK) && (i < list->size)) { - result = SerializeAdapter::deSerialize( - &list->front()[i], buffer, size, - streamEndianness); - ++i; - } - return result; - } - - - static void swapArrayListEndianness(ArrayList* list) { - list->swapArrayListEndianness(); - } -private: - ArrayList *adaptee; -}; - - - -#endif /* SERIALARRAYLISTADAPTER_H_ */ +/** + * @file SerialArrayListAdapter.h + * @brief This file defines the SerialArrayListAdapter class. + * @date 22.07.2014 + * @author baetz + */ +#ifndef SERIALARRAYLISTADAPTER_H_ +#define SERIALARRAYLISTADAPTER_H_ + +#include "../container/ArrayList.h" +#include "../serialize/SerializeIF.h" +#include + +/** + * Also serializes length field ! + * @ingroup serialize + */ +template +class SerialArrayListAdapter : public SerializeIF { +public: + SerialArrayListAdapter(ArrayList *adaptee) : adaptee(adaptee) { + } + + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + size_t maxSize, Endianness streamEndianness) const { + return serialize(adaptee, buffer, size, maxSize, streamEndianness); + } + + static ReturnValue_t serialize(const ArrayList* list, uint8_t** buffer, size_t* size, + size_t maxSize, Endianness streamEndianness) { + ReturnValue_t result = SerializeAdapter::serialize(&list->size, + buffer, size, maxSize, streamEndianness); + count_t i = 0; + while ((result == HasReturnvaluesIF::RETURN_OK) && (i < list->size)) { + result = SerializeAdapter::serialize(&list->entries[i], buffer, size, + maxSize, streamEndianness); + ++i; + } + return result; + } + + virtual size_t getSerializedSize() const { + return getSerializedSize(adaptee); + } + + static uint32_t getSerializedSize(const ArrayList* list) { + uint32_t printSize = sizeof(count_t); + count_t i = 0; + + for (i = 0; i < list->size; ++i) { + printSize += SerializeAdapter::getSerializedSize(&list->entries[i]); + } + + return printSize; + } + + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + Endianness streamEndianness) { + return deSerialize(adaptee, buffer, size, streamEndianness); + } + + static ReturnValue_t deSerialize(ArrayList* list, const uint8_t** buffer, size_t* size, + Endianness streamEndianness) { + count_t tempSize = 0; + ReturnValue_t result = SerializeAdapter::deSerialize(&tempSize, + buffer, size, streamEndianness); + if (tempSize > list->maxSize()) { + return SerializeIF::TOO_MANY_ELEMENTS; + } + list->size = tempSize; + count_t i = 0; + while ((result == HasReturnvaluesIF::RETURN_OK) && (i < list->size)) { + result = SerializeAdapter::deSerialize( + &list->front()[i], buffer, size, + streamEndianness); + ++i; + } + return result; + } + + + static void swapArrayListEndianness(ArrayList* list) { + list->swapArrayListEndianness(); + } +private: + ArrayList *adaptee; +}; + + + +#endif /* SERIALARRAYLISTADAPTER_H_ */ diff --git a/serialize/SerialBufferAdapter.cpp b/serialize/SerialBufferAdapter.cpp index 1224bba1..b1e0856a 100644 --- a/serialize/SerialBufferAdapter.cpp +++ b/serialize/SerialBufferAdapter.cpp @@ -1,128 +1,128 @@ -#include -#include -#include - -template -SerialBufferAdapter::SerialBufferAdapter(const uint8_t* buffer, - count_t bufferLength, bool serializeLength) : - serializeLength(serializeLength), - constBuffer(buffer), buffer(nullptr), - bufferLength(bufferLength) {} - -template -SerialBufferAdapter::SerialBufferAdapter(uint8_t* buffer, - count_t bufferLength, bool serializeLength) : - serializeLength(serializeLength), constBuffer(buffer), buffer(buffer), - bufferLength(bufferLength) {} - - -template -SerialBufferAdapter::~SerialBufferAdapter() { -} - -template -ReturnValue_t SerialBufferAdapter::serialize(uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) const { - uint32_t serializedLength = bufferLength; - if (serializeLength) { - serializedLength += SerializeAdapter::getSerializedSize( - &bufferLength); - } - if (*size + serializedLength > maxSize) { - return BUFFER_TOO_SHORT; - } else { - if (serializeLength) { - SerializeAdapter::serialize(&bufferLength, buffer, size, - maxSize, streamEndianness); - } - if (constBuffer != nullptr) { - memcpy(*buffer, this->constBuffer, bufferLength); - } - else if (buffer != nullptr) { - // This will propably be never reached, constBuffer should always be - // set if non-const buffer is set. - memcpy(*buffer, this->buffer, bufferLength); - } - else { - return HasReturnvaluesIF::RETURN_FAILED; - } - *size += bufferLength; - (*buffer) += bufferLength; - return HasReturnvaluesIF::RETURN_OK; - } -} - -template -size_t SerialBufferAdapter::getSerializedSize() const { - if (serializeLength) { - return bufferLength + SerializeAdapter::getSerializedSize(&bufferLength); - } else { - return bufferLength; - } -} - -template -ReturnValue_t SerialBufferAdapter::deSerialize(const uint8_t** buffer, - size_t* size, Endianness streamEndianness) { - //TODO Ignores Endian flag! - if (buffer != NULL) { - if(serializeLength){ - T serializedSize = SerializeAdapter::getSerializedSize( - &bufferLength); - if(bufferLength + serializedSize <= *size) { - *buffer += serializedSize; - *size -= serializedSize; - } - else { - return STREAM_TOO_SHORT; - } - } - //No Else If, go on with buffer - if (bufferLength <= *size) { - *size -= bufferLength; - memcpy(this->buffer, *buffer, bufferLength); - (*buffer) += bufferLength; - return HasReturnvaluesIF::RETURN_OK; - } - else { - return STREAM_TOO_SHORT; - } - } - else { - return HasReturnvaluesIF::RETURN_FAILED; - } -} - -template -uint8_t * SerialBufferAdapter::getBuffer() { - if(buffer == nullptr) { - sif::error << "Wrong access function for stored type !" - " Use getConstBuffer()." << std::endl; - return nullptr; - } - return buffer; -} - -template -const uint8_t * SerialBufferAdapter::getConstBuffer() { - if(constBuffer == nullptr) { - sif::error << "SerialBufferAdapter: Buffers are unitialized!" << std::endl; - return nullptr; - } - return constBuffer; -} - -template -void SerialBufferAdapter::setBuffer(uint8_t* buffer, - count_t bufferLength) { - this->buffer = buffer; - this->constBuffer = buffer; - this->bufferLength = bufferLength; -} - - -//forward Template declaration for linker -template class SerialBufferAdapter; -template class SerialBufferAdapter; -template class SerialBufferAdapter; - +#include "../serialize/SerialBufferAdapter.h" +#include "../serviceinterface/ServiceInterfaceStream.h" +#include + +template +SerialBufferAdapter::SerialBufferAdapter(const uint8_t* buffer, + count_t bufferLength, bool serializeLength) : + serializeLength(serializeLength), + constBuffer(buffer), buffer(nullptr), + bufferLength(bufferLength) {} + +template +SerialBufferAdapter::SerialBufferAdapter(uint8_t* buffer, + count_t bufferLength, bool serializeLength) : + serializeLength(serializeLength), constBuffer(buffer), buffer(buffer), + bufferLength(bufferLength) {} + + +template +SerialBufferAdapter::~SerialBufferAdapter() { +} + +template +ReturnValue_t SerialBufferAdapter::serialize(uint8_t** buffer, size_t* size, + size_t maxSize, Endianness streamEndianness) const { + uint32_t serializedLength = bufferLength; + if (serializeLength) { + serializedLength += SerializeAdapter::getSerializedSize( + &bufferLength); + } + if (*size + serializedLength > maxSize) { + return BUFFER_TOO_SHORT; + } else { + if (serializeLength) { + SerializeAdapter::serialize(&bufferLength, buffer, size, + maxSize, streamEndianness); + } + if (constBuffer != nullptr) { + memcpy(*buffer, this->constBuffer, bufferLength); + } + else if (buffer != nullptr) { + // This will propably be never reached, constBuffer should always be + // set if non-const buffer is set. + memcpy(*buffer, this->buffer, bufferLength); + } + else { + return HasReturnvaluesIF::RETURN_FAILED; + } + *size += bufferLength; + (*buffer) += bufferLength; + return HasReturnvaluesIF::RETURN_OK; + } +} + +template +size_t SerialBufferAdapter::getSerializedSize() const { + if (serializeLength) { + return bufferLength + SerializeAdapter::getSerializedSize(&bufferLength); + } else { + return bufferLength; + } +} + +template +ReturnValue_t SerialBufferAdapter::deSerialize(const uint8_t** buffer, + size_t* size, Endianness streamEndianness) { + //TODO Ignores Endian flag! + if (buffer != NULL) { + if(serializeLength){ + T serializedSize = SerializeAdapter::getSerializedSize( + &bufferLength); + if(bufferLength + serializedSize <= *size) { + *buffer += serializedSize; + *size -= serializedSize; + } + else { + return STREAM_TOO_SHORT; + } + } + //No Else If, go on with buffer + if (bufferLength <= *size) { + *size -= bufferLength; + memcpy(this->buffer, *buffer, bufferLength); + (*buffer) += bufferLength; + return HasReturnvaluesIF::RETURN_OK; + } + else { + return STREAM_TOO_SHORT; + } + } + else { + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +template +uint8_t * SerialBufferAdapter::getBuffer() { + if(buffer == nullptr) { + sif::error << "Wrong access function for stored type !" + " Use getConstBuffer()." << std::endl; + return nullptr; + } + return buffer; +} + +template +const uint8_t * SerialBufferAdapter::getConstBuffer() { + if(constBuffer == nullptr) { + sif::error << "SerialBufferAdapter: Buffers are unitialized!" << std::endl; + return nullptr; + } + return constBuffer; +} + +template +void SerialBufferAdapter::setBuffer(uint8_t* buffer, + count_t bufferLength) { + this->buffer = buffer; + this->constBuffer = buffer; + this->bufferLength = bufferLength; +} + + +//forward Template declaration for linker +template class SerialBufferAdapter; +template class SerialBufferAdapter; +template class SerialBufferAdapter; + diff --git a/serialize/SerialBufferAdapter.h b/serialize/SerialBufferAdapter.h index 2c47e0f1..c3dfcd8f 100644 --- a/serialize/SerialBufferAdapter.h +++ b/serialize/SerialBufferAdapter.h @@ -1,78 +1,78 @@ -#ifndef SERIALBUFFERADAPTER_H_ -#define SERIALBUFFERADAPTER_H_ - -#include -#include - -/** - * This adapter provides an interface for SerializeIF to serialize or deserialize - * buffers with no length header but a known size. - * - * Additionally, the buffer length can be serialized too and will be put in - * front of the serialized buffer. - * - * Can be used with SerialLinkedListAdapter by declaring a SerializeElement with - * SerialElement>. - * Right now, the SerialBufferAdapter must always - * be initialized with the buffer and size ! - * - * \ingroup serialize - */ -template -class SerialBufferAdapter: public SerializeIF { -public: - - /** - * Constructor for constant uint8_t buffer. Length field can be serialized optionally. - * Type of length can be supplied as template type. - * @param buffer - * @param bufferLength - * @param serializeLength - */ - SerialBufferAdapter(const uint8_t* buffer, count_t bufferLength, - bool serializeLength = false); - - /** - * Constructor for non-constant uint8_t buffer. - * Length field can be serialized optionally. - * Type of length can be supplied as template type. - * @param buffer - * @param bufferLength - * @param serializeLength Length field will be serialized with size count_t - */ - SerialBufferAdapter(uint8_t* buffer, count_t bufferLength, - bool serializeLength = false); - - virtual ~SerialBufferAdapter(); - - virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) const override; - - virtual size_t getSerializedSize() const override; - - /** - * @brief This function deserializes a buffer into the member buffer. - * @details - * If a length field is present, it is ignored, as the size should have - * been set in the constructor. If the size is not known beforehand, - * consider using SerialFixedArrayListAdapter instead. - * @param buffer [out] Resulting buffer - * @param size remaining size to deserialize, should be larger than buffer - * + size field size - * @param bigEndian - * @return - */ - virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - Endianness streamEndianness) override; - - uint8_t * getBuffer(); - const uint8_t * getConstBuffer(); - void setBuffer(uint8_t* buffer, count_t bufferLength); -private: - bool serializeLength = false; - const uint8_t *constBuffer = nullptr; - uint8_t *buffer = nullptr; - count_t bufferLength = 0; -}; - -#endif /* SERIALBUFFERADAPTER_H_ */ +#ifndef SERIALBUFFERADAPTER_H_ +#define SERIALBUFFERADAPTER_H_ + +#include "../serialize/SerializeIF.h" +#include "../serialize/SerializeAdapter.h" + +/** + * This adapter provides an interface for SerializeIF to serialize or deserialize + * buffers with no length header but a known size. + * + * Additionally, the buffer length can be serialized too and will be put in + * front of the serialized buffer. + * + * Can be used with SerialLinkedListAdapter by declaring a SerializeElement with + * SerialElement>. + * Right now, the SerialBufferAdapter must always + * be initialized with the buffer and size ! + * + * \ingroup serialize + */ +template +class SerialBufferAdapter: public SerializeIF { +public: + + /** + * Constructor for constant uint8_t buffer. Length field can be serialized optionally. + * Type of length can be supplied as template type. + * @param buffer + * @param bufferLength + * @param serializeLength + */ + SerialBufferAdapter(const uint8_t* buffer, count_t bufferLength, + bool serializeLength = false); + + /** + * Constructor for non-constant uint8_t buffer. + * Length field can be serialized optionally. + * Type of length can be supplied as template type. + * @param buffer + * @param bufferLength + * @param serializeLength Length field will be serialized with size count_t + */ + SerialBufferAdapter(uint8_t* buffer, count_t bufferLength, + bool serializeLength = false); + + virtual ~SerialBufferAdapter(); + + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + size_t maxSize, Endianness streamEndianness) const override; + + virtual size_t getSerializedSize() const override; + + /** + * @brief This function deserializes a buffer into the member buffer. + * @details + * If a length field is present, it is ignored, as the size should have + * been set in the constructor. If the size is not known beforehand, + * consider using SerialFixedArrayListAdapter instead. + * @param buffer [out] Resulting buffer + * @param size remaining size to deserialize, should be larger than buffer + * + size field size + * @param bigEndian + * @return + */ + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + Endianness streamEndianness) override; + + uint8_t * getBuffer(); + const uint8_t * getConstBuffer(); + void setBuffer(uint8_t* buffer, count_t bufferLength); +private: + bool serializeLength = false; + const uint8_t *constBuffer = nullptr; + uint8_t *buffer = nullptr; + count_t bufferLength = 0; +}; + +#endif /* SERIALBUFFERADAPTER_H_ */ diff --git a/serialize/SerialFixedArrayListAdapter.h b/serialize/SerialFixedArrayListAdapter.h index 196af67c..7968b420 100644 --- a/serialize/SerialFixedArrayListAdapter.h +++ b/serialize/SerialFixedArrayListAdapter.h @@ -1,63 +1,63 @@ -#ifndef SERIALFIXEDARRAYLISTADAPTER_H_ -#define SERIALFIXEDARRAYLISTADAPTER_H_ - -#include -#include - -/** - * @brief This adapter provides an interface for SerializeIF to serialize and - * deserialize buffers with a header containing the buffer length. - * @details - * Can be used by SerialLinkedListAdapter by declaring - * as a linked element with SerializeElement>. - * The sequence of objects is defined in the constructor by - * using the setStart and setNext functions. - * - * - Buffers with a size header inside that class can be declared with - * @code - * SerialFixedArrayListAdapter mySerialFixedArrayList(...). - * @endcode - * - * - MAX_SIZE: specifies the maximum allowed number of elements - * in FixedArrayList. - * - BUFFER_TYPE: specifies the data type of the buffer - * - count_t: specifies the type/size of the length field - * which defaults to one byte. - * - * @ingroup serialize - */ -template -class SerialFixedArrayListAdapter : - public FixedArrayList, - public SerializeIF { -public: - /** - * Constructor Arguments are forwarded to FixedArrayList constructor. - * Refer to the fixed array list constructors for different options. - * @param args - */ - template - SerialFixedArrayListAdapter(Args... args) : - FixedArrayList( - std::forward(args)...){} - - ReturnValue_t serialize(uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) const { - return SerialArrayListAdapter::serialize(this, - buffer, size, maxSize, streamEndianness); - } - - size_t getSerializedSize() const { - return SerialArrayListAdapter::getSerializedSize(this); - } - - ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - Endianness streamEndianness) { - return SerialArrayListAdapter::deSerialize(this, - buffer, size, streamEndianness); - } - -}; - -#endif /* SERIALFIXEDARRAYLISTADAPTER_H_ */ +#ifndef SERIALFIXEDARRAYLISTADAPTER_H_ +#define SERIALFIXEDARRAYLISTADAPTER_H_ + +#include "../container/FixedArrayList.h" +#include "../serialize/SerialArrayListAdapter.h" + +/** + * @brief This adapter provides an interface for SerializeIF to serialize and + * deserialize buffers with a header containing the buffer length. + * @details + * Can be used by SerialLinkedListAdapter by declaring + * as a linked element with SerializeElement>. + * The sequence of objects is defined in the constructor by + * using the setStart and setNext functions. + * + * - Buffers with a size header inside that class can be declared with + * @code + * SerialFixedArrayListAdapter mySerialFixedArrayList(...). + * @endcode + * + * - MAX_SIZE: specifies the maximum allowed number of elements + * in FixedArrayList. + * - BUFFER_TYPE: specifies the data type of the buffer + * - count_t: specifies the type/size of the length field + * which defaults to one byte. + * + * @ingroup serialize + */ +template +class SerialFixedArrayListAdapter : + public FixedArrayList, + public SerializeIF { +public: + /** + * Constructor Arguments are forwarded to FixedArrayList constructor. + * Refer to the fixed array list constructors for different options. + * @param args + */ + template + SerialFixedArrayListAdapter(Args... args) : + FixedArrayList( + std::forward(args)...){} + + ReturnValue_t serialize(uint8_t** buffer, size_t* size, + size_t maxSize, Endianness streamEndianness) const { + return SerialArrayListAdapter::serialize(this, + buffer, size, maxSize, streamEndianness); + } + + size_t getSerializedSize() const { + return SerialArrayListAdapter::getSerializedSize(this); + } + + ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + Endianness streamEndianness) { + return SerialArrayListAdapter::deSerialize(this, + buffer, size, streamEndianness); + } + +}; + +#endif /* SERIALFIXEDARRAYLISTADAPTER_H_ */ diff --git a/serialize/SerialLinkedListAdapter.h b/serialize/SerialLinkedListAdapter.h index c822bd1b..a4652028 100644 --- a/serialize/SerialLinkedListAdapter.h +++ b/serialize/SerialLinkedListAdapter.h @@ -1,133 +1,133 @@ -/** - * @file SerialLinkedListAdapter.h - * @brief This file defines the SerialLinkedListAdapter class. - * @date 22.07.2014 - * @author baetz - */ -#ifndef SERIALLINKEDLISTADAPTER_H_ -#define SERIALLINKEDLISTADAPTER_H_ - -#include -#include -#include -#include -//This is where we need the SerializeAdapter! - - /** - * @brief Implement the conversion of object data to data streams - * or vice-versa, using linked lists. - * @details - * An alternative to the AutoSerializeAdapter functions - * - All object members with a datatype are declared as - * SerializeElement members inside the class - * implementing this adapter. - * - The element type can also be a SerialBufferAdapter to - * de-/serialize buffers with a known size - * - The element type can also be a SerialFixedArrayListAdapter to - * de-/serialize buffers with a size header, which is scanned automatically. - * - * The sequence of objects is defined in the constructor by using - * the setStart and setNext functions. - * - * 1. The serialization process is done by instantiating the class and - * calling serialize after all SerializeElement entries have been set by - * using the constructor or setter functions. An additional size variable - * can be supplied which is calculated/incremented automatically. - * 2. The deserialization process is done by instantiating the class and - * supplying a buffer with the data which is converted into an object. - * The size of data to serialize can be supplied and is - * decremented in the function. Range checking is done internally. - * - * @ingroup serialize - */ -template -class SerialLinkedListAdapter: public SinglyLinkedList, public SerializeIF { -public: - /** - * Copying is forbidden by deleting the copy constructor and the copy - * assignment operator because of the pointers to the linked list members. - * Unless the child class implements an own copy constructor or - * copy assignment operator, these operation will throw a compiler error. - * @param - */ - SerialLinkedListAdapter(const SerialLinkedListAdapter &) = delete; - SerialLinkedListAdapter& operator=(const SerialLinkedListAdapter&) = delete; - - SerialLinkedListAdapter(typename LinkedElement::Iterator start, - bool printCount = false) : - SinglyLinkedList(start), printCount(printCount) { - } - - SerialLinkedListAdapter(LinkedElement* first, bool printCount = false) : - SinglyLinkedList(first), printCount(printCount) { - - } - - SerialLinkedListAdapter(bool printCount = false) : - SinglyLinkedList(), printCount(printCount) { - } - - virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) const override { - if (printCount) { - count_t mySize = SinglyLinkedList::getSize(); - ReturnValue_t result = SerializeAdapter::serialize(&mySize, - buffer, size, maxSize, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - } - return serialize(SinglyLinkedList::start, buffer, size, maxSize, - streamEndianness); - } - - static ReturnValue_t serialize(const LinkedElement* element, - uint8_t** buffer, size_t* size, size_t maxSize, - Endianness streamEndianness) { - ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; - while ((result == HasReturnvaluesIF::RETURN_OK) && (element != NULL)) { - result = element->value->serialize(buffer, size, maxSize, - streamEndianness); - element = element->getNext(); - } - return result; - } - - virtual size_t getSerializedSize() const override { - if (printCount) { - return SerialLinkedListAdapter::getSerializedSize() - + sizeof(count_t); - } else { - return getSerializedSize(SinglyLinkedList::start); - } - } - - static size_t getSerializedSize(const LinkedElement *element) { - size_t size = 0; - while (element != NULL) { - size += element->value->getSerializedSize(); - element = element->getNext(); - } - return size; - } - - - virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - Endianness streamEndianness) override { - return deSerialize(SinglyLinkedList::start, buffer, size, streamEndianness); - } - - static ReturnValue_t deSerialize(LinkedElement* element, - const uint8_t** buffer, size_t* size, Endianness streamEndianness) { - ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; - while ((result == HasReturnvaluesIF::RETURN_OK) && (element != NULL)) { - result = element->value->deSerialize(buffer, size, streamEndianness); - element = element->getNext(); - } - return result; - } - - bool printCount; -}; - -#endif /* SERIALLINKEDLISTADAPTER_H_ */ +/** + * @file SerialLinkedListAdapter.h + * @brief This file defines the SerialLinkedListAdapter class. + * @date 22.07.2014 + * @author baetz + */ +#ifndef SERIALLINKEDLISTADAPTER_H_ +#define SERIALLINKEDLISTADAPTER_H_ + +#include "../container/SinglyLinkedList.h" +#include "../serialize/SerializeAdapter.h" +#include "../serialize/SerializeElement.h" +#include "../serialize/SerializeIF.h" +//This is where we need the SerializeAdapter! + + /** + * @brief Implement the conversion of object data to data streams + * or vice-versa, using linked lists. + * @details + * An alternative to the AutoSerializeAdapter functions + * - All object members with a datatype are declared as + * SerializeElement members inside the class + * implementing this adapter. + * - The element type can also be a SerialBufferAdapter to + * de-/serialize buffers with a known size + * - The element type can also be a SerialFixedArrayListAdapter to + * de-/serialize buffers with a size header, which is scanned automatically. + * + * The sequence of objects is defined in the constructor by using + * the setStart and setNext functions. + * + * 1. The serialization process is done by instantiating the class and + * calling serialize after all SerializeElement entries have been set by + * using the constructor or setter functions. An additional size variable + * can be supplied which is calculated/incremented automatically. + * 2. The deserialization process is done by instantiating the class and + * supplying a buffer with the data which is converted into an object. + * The size of data to serialize can be supplied and is + * decremented in the function. Range checking is done internally. + * + * @ingroup serialize + */ +template +class SerialLinkedListAdapter: public SinglyLinkedList, public SerializeIF { +public: + /** + * Copying is forbidden by deleting the copy constructor and the copy + * assignment operator because of the pointers to the linked list members. + * Unless the child class implements an own copy constructor or + * copy assignment operator, these operation will throw a compiler error. + * @param + */ + SerialLinkedListAdapter(const SerialLinkedListAdapter &) = delete; + SerialLinkedListAdapter& operator=(const SerialLinkedListAdapter&) = delete; + + SerialLinkedListAdapter(typename LinkedElement::Iterator start, + bool printCount = false) : + SinglyLinkedList(start), printCount(printCount) { + } + + SerialLinkedListAdapter(LinkedElement* first, bool printCount = false) : + SinglyLinkedList(first), printCount(printCount) { + + } + + SerialLinkedListAdapter(bool printCount = false) : + SinglyLinkedList(), printCount(printCount) { + } + + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + size_t maxSize, Endianness streamEndianness) const override { + if (printCount) { + count_t mySize = SinglyLinkedList::getSize(); + ReturnValue_t result = SerializeAdapter::serialize(&mySize, + buffer, size, maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + return serialize(SinglyLinkedList::start, buffer, size, maxSize, + streamEndianness); + } + + static ReturnValue_t serialize(const LinkedElement* element, + uint8_t** buffer, size_t* size, size_t maxSize, + Endianness streamEndianness) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + while ((result == HasReturnvaluesIF::RETURN_OK) && (element != NULL)) { + result = element->value->serialize(buffer, size, maxSize, + streamEndianness); + element = element->getNext(); + } + return result; + } + + virtual size_t getSerializedSize() const override { + if (printCount) { + return SerialLinkedListAdapter::getSerializedSize() + + sizeof(count_t); + } else { + return getSerializedSize(SinglyLinkedList::start); + } + } + + static size_t getSerializedSize(const LinkedElement *element) { + size_t size = 0; + while (element != NULL) { + size += element->value->getSerializedSize(); + element = element->getNext(); + } + return size; + } + + + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + Endianness streamEndianness) override { + return deSerialize(SinglyLinkedList::start, buffer, size, streamEndianness); + } + + static ReturnValue_t deSerialize(LinkedElement* element, + const uint8_t** buffer, size_t* size, Endianness streamEndianness) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + while ((result == HasReturnvaluesIF::RETURN_OK) && (element != NULL)) { + result = element->value->deSerialize(buffer, size, streamEndianness); + element = element->getNext(); + } + return result; + } + + bool printCount; +}; + +#endif /* SERIALLINKEDLISTADAPTER_H_ */ diff --git a/serialize/SerializeAdapter.h b/serialize/SerializeAdapter.h index 4534ffb8..bcddb71a 100644 --- a/serialize/SerializeAdapter.h +++ b/serialize/SerializeAdapter.h @@ -1,175 +1,175 @@ -#ifndef SERIALIZEADAPTER_H_ -#define SERIALIZEADAPTER_H_ - -#include -#include -#include -#include -#include - - /** - * @brief These adapters provides an interface to use the SerializeIF functions - * with arbitrary template objects to facilitate and simplify the - * serialization of classes with different multiple different data types - * into buffers and vice-versa. - * @details - * - * A report class is converted into a TM buffer. The report class implements a - * serialize functions and calls the AutoSerializeAdapter::serialize function - * repeatedly on all object data fields. The getSerializedSize function is - * implemented by calling the AutoSerializeAdapter::getSerializedSize function - * repeatedly on all data fields. - * - * The AutoSerializeAdapter functions can also be used as an alternative to - * memcpy to retrieve data out of a buffer directly into a class variable - * with data type T while being able to specify endianness. The boolean - * bigEndian specifies whether an endian swap is performed on the data before - * serialization or deserialization. - * - * There are three ways to retrieve data out of a buffer to be used in the FSFW - * to use regular aligned (big endian) data. Examples: - * - * 1. Use the AutoSerializeAdapter::deSerialize function - * The pointer *buffer will be incremented automatically by the typeSize - * of the object, so this function can be called on &buffer repeatedly - * without adjusting pointer position. Set bigEndian parameter to true - * to perform endian swapping, if necessary - * @code - * uint16_t data; - * int32_t dataLen = sizeof(data); - * ReturnValue_t result = - * AutoSerializeAdapter::deSerialize(&data,&buffer,&dataLen,true); - * @endcode - * - * 2. Perform a bitshift operation. Watch for for endianness: - * @code - * uint16_t data; - * data = buffer[targetByte1] << 8 | buffer[targetByte2]; - * data = EndianSwapper::swap(data); //optional, or swap order above - * @endcode - * - * 3. memcpy or std::copy can also be used, but watch out if system - * endianness is different from required data endianness. - * Perform endian-swapping if necessary. - * @code - * uint16_t data; - * memcpy(&data,buffer + positionOfTargetByte1,sizeof(data)); - * data = EndianSwapper::swap(data); //optional - * @endcode - * - * When serializing for downlink, the packets are generally serialized assuming - * big endian data format like seen in TmPacketStored.cpp for example. - * - * @ingroup serialize - */ - -class SerializeAdapter { -public: - template - static ReturnValue_t serialize(const T *object, uint8_t **buffer, - size_t *size, size_t maxSize, SerializeIF::Endianness streamEndianness) { - InternalSerializeAdapter::Is> adapter; - return adapter.serialize(object, buffer, size, maxSize, - streamEndianness); - } - template - static uint32_t getSerializedSize(const T *object) { - InternalSerializeAdapter::Is> adapter; - return adapter.getSerializedSize(object); - } - template - static ReturnValue_t deSerialize(T *object, const uint8_t **buffer, - size_t *size, SerializeIF::Endianness streamEndianness) { - InternalSerializeAdapter::Is> adapter; - return adapter.deSerialize(object, buffer, size, streamEndianness); - } -private: - template - class InternalSerializeAdapter { - public: - static ReturnValue_t serialize(const T *object, uint8_t **buffer, - size_t *size, size_t max_size, SerializeIF::Endianness streamEndianness) { - size_t ignoredSize = 0; - if (size == NULL) { - size = &ignoredSize; - } - //TODO check integer overflow of *size - if (sizeof(T) + *size <= max_size) { - T tmp; - switch (streamEndianness) { - case SerializeIF::Endianness::BIG: - tmp = EndianConverter::convertBigEndian(*object); - break; - case SerializeIF::Endianness::LITTLE: - tmp = EndianConverter::convertLittleEndian(*object); - break; - default: - case SerializeIF::Endianness::MACHINE: - tmp = *object; - break; - } - memcpy(*buffer, &tmp, sizeof(T)); - *size += sizeof(T); - (*buffer) += sizeof(T); - return HasReturnvaluesIF::RETURN_OK; - } else { - return SerializeIF::BUFFER_TOO_SHORT; - } - } - - ReturnValue_t deSerialize(T *object, const uint8_t **buffer, - size_t *size, SerializeIF::Endianness streamEndianness) { - T tmp; - if (*size >= sizeof(T)) { - *size -= sizeof(T); - memcpy(&tmp, *buffer, sizeof(T)); - switch (streamEndianness) { - case SerializeIF::Endianness::BIG: - *object = EndianConverter::convertBigEndian(tmp); - break; - case SerializeIF::Endianness::LITTLE: - *object = EndianConverter::convertLittleEndian(tmp); - break; - default: - case SerializeIF::Endianness::MACHINE: - *object = tmp; - break; - } - - *buffer += sizeof(T); - return HasReturnvaluesIF::RETURN_OK; - } else { - return SerializeIF::STREAM_TOO_SHORT; - } - } - - uint32_t getSerializedSize(const T *object) { - return sizeof(T); - } - - }; - - template - class InternalSerializeAdapter { - public: - ReturnValue_t serialize(const T *object, uint8_t **buffer, - size_t *size, size_t max_size, - SerializeIF::Endianness streamEndianness) const { - size_t ignoredSize = 0; - if (size == NULL) { - size = &ignoredSize; - } - return object->serialize(buffer, size, max_size, streamEndianness); - } - uint32_t getSerializedSize(const T *object) const { - return object->getSerializedSize(); - } - - ReturnValue_t deSerialize(T *object, const uint8_t **buffer, - size_t *size, SerializeIF::Endianness streamEndianness) { - return object->deSerialize(buffer, size, streamEndianness); - } - }; -}; - -#endif /* SERIALIZEADAPTER_H_ */ +#ifndef SERIALIZEADAPTER_H_ +#define SERIALIZEADAPTER_H_ + +#include "../container/IsDerivedFrom.h" +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../serialize/EndianConverter.h" +#include "../serialize/SerializeIF.h" +#include + + /** + * @brief These adapters provides an interface to use the SerializeIF functions + * with arbitrary template objects to facilitate and simplify the + * serialization of classes with different multiple different data types + * into buffers and vice-versa. + * @details + * + * A report class is converted into a TM buffer. The report class implements a + * serialize functions and calls the AutoSerializeAdapter::serialize function + * repeatedly on all object data fields. The getSerializedSize function is + * implemented by calling the AutoSerializeAdapter::getSerializedSize function + * repeatedly on all data fields. + * + * The AutoSerializeAdapter functions can also be used as an alternative to + * memcpy to retrieve data out of a buffer directly into a class variable + * with data type T while being able to specify endianness. The boolean + * bigEndian specifies whether an endian swap is performed on the data before + * serialization or deserialization. + * + * There are three ways to retrieve data out of a buffer to be used in the FSFW + * to use regular aligned (big endian) data. Examples: + * + * 1. Use the AutoSerializeAdapter::deSerialize function + * The pointer *buffer will be incremented automatically by the typeSize + * of the object, so this function can be called on &buffer repeatedly + * without adjusting pointer position. Set bigEndian parameter to true + * to perform endian swapping, if necessary + * @code + * uint16_t data; + * int32_t dataLen = sizeof(data); + * ReturnValue_t result = + * AutoSerializeAdapter::deSerialize(&data,&buffer,&dataLen,true); + * @endcode + * + * 2. Perform a bitshift operation. Watch for for endianness: + * @code + * uint16_t data; + * data = buffer[targetByte1] << 8 | buffer[targetByte2]; + * data = EndianSwapper::swap(data); //optional, or swap order above + * @endcode + * + * 3. memcpy or std::copy can also be used, but watch out if system + * endianness is different from required data endianness. + * Perform endian-swapping if necessary. + * @code + * uint16_t data; + * memcpy(&data,buffer + positionOfTargetByte1,sizeof(data)); + * data = EndianSwapper::swap(data); //optional + * @endcode + * + * When serializing for downlink, the packets are generally serialized assuming + * big endian data format like seen in TmPacketStored.cpp for example. + * + * @ingroup serialize + */ + +class SerializeAdapter { +public: + template + static ReturnValue_t serialize(const T *object, uint8_t **buffer, + size_t *size, size_t maxSize, SerializeIF::Endianness streamEndianness) { + InternalSerializeAdapter::Is> adapter; + return adapter.serialize(object, buffer, size, maxSize, + streamEndianness); + } + template + static uint32_t getSerializedSize(const T *object) { + InternalSerializeAdapter::Is> adapter; + return adapter.getSerializedSize(object); + } + template + static ReturnValue_t deSerialize(T *object, const uint8_t **buffer, + size_t *size, SerializeIF::Endianness streamEndianness) { + InternalSerializeAdapter::Is> adapter; + return adapter.deSerialize(object, buffer, size, streamEndianness); + } +private: + template + class InternalSerializeAdapter { + public: + static ReturnValue_t serialize(const T *object, uint8_t **buffer, + size_t *size, size_t max_size, SerializeIF::Endianness streamEndianness) { + size_t ignoredSize = 0; + if (size == NULL) { + size = &ignoredSize; + } + //TODO check integer overflow of *size + if (sizeof(T) + *size <= max_size) { + T tmp; + switch (streamEndianness) { + case SerializeIF::Endianness::BIG: + tmp = EndianConverter::convertBigEndian(*object); + break; + case SerializeIF::Endianness::LITTLE: + tmp = EndianConverter::convertLittleEndian(*object); + break; + default: + case SerializeIF::Endianness::MACHINE: + tmp = *object; + break; + } + memcpy(*buffer, &tmp, sizeof(T)); + *size += sizeof(T); + (*buffer) += sizeof(T); + return HasReturnvaluesIF::RETURN_OK; + } else { + return SerializeIF::BUFFER_TOO_SHORT; + } + } + + ReturnValue_t deSerialize(T *object, const uint8_t **buffer, + size_t *size, SerializeIF::Endianness streamEndianness) { + T tmp; + if (*size >= sizeof(T)) { + *size -= sizeof(T); + memcpy(&tmp, *buffer, sizeof(T)); + switch (streamEndianness) { + case SerializeIF::Endianness::BIG: + *object = EndianConverter::convertBigEndian(tmp); + break; + case SerializeIF::Endianness::LITTLE: + *object = EndianConverter::convertLittleEndian(tmp); + break; + default: + case SerializeIF::Endianness::MACHINE: + *object = tmp; + break; + } + + *buffer += sizeof(T); + return HasReturnvaluesIF::RETURN_OK; + } else { + return SerializeIF::STREAM_TOO_SHORT; + } + } + + uint32_t getSerializedSize(const T *object) { + return sizeof(T); + } + + }; + + template + class InternalSerializeAdapter { + public: + ReturnValue_t serialize(const T *object, uint8_t **buffer, + size_t *size, size_t max_size, + SerializeIF::Endianness streamEndianness) const { + size_t ignoredSize = 0; + if (size == NULL) { + size = &ignoredSize; + } + return object->serialize(buffer, size, max_size, streamEndianness); + } + uint32_t getSerializedSize(const T *object) const { + return object->getSerializedSize(); + } + + ReturnValue_t deSerialize(T *object, const uint8_t **buffer, + size_t *size, SerializeIF::Endianness streamEndianness) { + return object->deSerialize(buffer, size, streamEndianness); + } + }; +}; + +#endif /* SERIALIZEADAPTER_H_ */ diff --git a/serialize/SerializeElement.h b/serialize/SerializeElement.h index 5ad0e4b2..e33192ca 100644 --- a/serialize/SerializeElement.h +++ b/serialize/SerializeElement.h @@ -1,60 +1,60 @@ -#ifndef SERIALIZEELEMENT_H_ -#define SERIALIZEELEMENT_H_ - -#include -#include -#include - -/** - * @brief This class is used to mark datatypes for serialization with the - * SerialLinkedListAdapter - * @details - * Used by declaring any arbitrary datatype with SerializeElement myVariable, - * inside a SerialLinkedListAdapter implementation and setting the sequence - * of objects with setNext() and setStart(). - * Serilization and Deserialization is then performed automatically in - * specified sequence order. - * @ingroup serialize - */ -template -class SerializeElement: public SerializeIF, public LinkedElement { -public: - template - SerializeElement(Args ... args) : - LinkedElement(this), entry(std::forward(args)...) { - - } - SerializeElement() : - LinkedElement(this) { - } - T entry; - ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize, - Endianness streamEndianness) const override { - return SerializeAdapter::serialize(&entry, buffer, size, maxSize, - streamEndianness); - } - - size_t getSerializedSize() const override { - return SerializeAdapter::getSerializedSize(&entry); - } - - virtual ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, - Endianness streamEndianness) override { - return SerializeAdapter::deSerialize(&entry, buffer, size, - streamEndianness); - } - - operator T() { - return entry; - } - - SerializeElement& operator=(T newValue) { - entry = newValue; - return *this; - } - T* operator->() { - return &entry; - } -}; - -#endif /* SERIALIZEELEMENT_H_ */ +#ifndef SERIALIZEELEMENT_H_ +#define SERIALIZEELEMENT_H_ + +#include "../container/SinglyLinkedList.h" +#include "../serialize/SerializeAdapter.h" +#include + +/** + * @brief This class is used to mark datatypes for serialization with the + * SerialLinkedListAdapter + * @details + * Used by declaring any arbitrary datatype with SerializeElement myVariable, + * inside a SerialLinkedListAdapter implementation and setting the sequence + * of objects with setNext() and setStart(). + * Serilization and Deserialization is then performed automatically in + * specified sequence order. + * @ingroup serialize + */ +template +class SerializeElement: public SerializeIF, public LinkedElement { +public: + template + SerializeElement(Args ... args) : + LinkedElement(this), entry(std::forward(args)...) { + + } + SerializeElement() : + LinkedElement(this) { + } + T entry; + ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const override { + return SerializeAdapter::serialize(&entry, buffer, size, maxSize, + streamEndianness); + } + + size_t getSerializedSize() const override { + return SerializeAdapter::getSerializedSize(&entry); + } + + virtual ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) override { + return SerializeAdapter::deSerialize(&entry, buffer, size, + streamEndianness); + } + + operator T() { + return entry; + } + + SerializeElement& operator=(T newValue) { + entry = newValue; + return *this; + } + T* operator->() { + return &entry; + } +}; + +#endif /* SERIALIZEELEMENT_H_ */ diff --git a/serialize/SerializeIF.h b/serialize/SerializeIF.h index 14eef927..8dc4894a 100644 --- a/serialize/SerializeIF.h +++ b/serialize/SerializeIF.h @@ -1,58 +1,58 @@ -#ifndef SERIALIZEIF_H_ -#define SERIALIZEIF_H_ - -#include -#include - -/** - * @defgroup serialize Serialization - * Contains serialisation services. - */ - -/** - * @brief An interface for alle classes which require - * translation of objects data into data streams and vice-versa. - * @details - * If the target architecture is little endian (e.g. ARM), any data types - * created might have the wrong endianess if they are to be used for the FSFW. - * Depending on the system architecture, endian correctness must be assured, - * This is important for incoming and outgoing data. The internal handling - * of data should be performed in the native system endianness. - * There are three ways to copy data (with different options to ensure - * endian correctness): - * - * 1. Use the @c AutoSerializeAdapter::deSerialize function (with - * the endian flag) - * 2. Perform a bitshift operation (with correct order) - * 3. @c memcpy (with @c EndianSwapper if necessary) - * - * When serializing for downlink, the packets are generally serialized - * assuming big endian data format like seen in TmPacketStored.cpp for example. - * - * @ingroup serialize - */ -class SerializeIF { -public: - enum class Endianness : uint8_t { - BIG, LITTLE, MACHINE - }; - - static const uint8_t INTERFACE_ID = CLASS_ID::SERIALIZE_IF; - static const ReturnValue_t BUFFER_TOO_SHORT = MAKE_RETURN_CODE(1); - static const ReturnValue_t STREAM_TOO_SHORT = MAKE_RETURN_CODE(2); - static const ReturnValue_t TOO_MANY_ELEMENTS = MAKE_RETURN_CODE(3); - - virtual ~SerializeIF() { - } - - virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size, - size_t maxSize, Endianness streamEndianness) const = 0; - - virtual size_t getSerializedSize() const = 0; - - virtual ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, - Endianness streamEndianness) = 0; - -}; - -#endif /* SERIALIZEIF_H_ */ +#ifndef SERIALIZEIF_H_ +#define SERIALIZEIF_H_ + +#include "../returnvalues/HasReturnvaluesIF.h" +#include + +/** + * @defgroup serialize Serialization + * Contains serialisation services. + */ + +/** + * @brief An interface for alle classes which require + * translation of objects data into data streams and vice-versa. + * @details + * If the target architecture is little endian (e.g. ARM), any data types + * created might have the wrong endianess if they are to be used for the FSFW. + * Depending on the system architecture, endian correctness must be assured, + * This is important for incoming and outgoing data. The internal handling + * of data should be performed in the native system endianness. + * There are three ways to copy data (with different options to ensure + * endian correctness): + * + * 1. Use the @c AutoSerializeAdapter::deSerialize function (with + * the endian flag) + * 2. Perform a bitshift operation (with correct order) + * 3. @c memcpy (with @c EndianSwapper if necessary) + * + * When serializing for downlink, the packets are generally serialized + * assuming big endian data format like seen in TmPacketStored.cpp for example. + * + * @ingroup serialize + */ +class SerializeIF { +public: + enum class Endianness : uint8_t { + BIG, LITTLE, MACHINE + }; + + static const uint8_t INTERFACE_ID = CLASS_ID::SERIALIZE_IF; + static const ReturnValue_t BUFFER_TOO_SHORT = MAKE_RETURN_CODE(1); + static const ReturnValue_t STREAM_TOO_SHORT = MAKE_RETURN_CODE(2); + static const ReturnValue_t TOO_MANY_ELEMENTS = MAKE_RETURN_CODE(3); + + virtual ~SerializeIF() { + } + + virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size, + size_t maxSize, Endianness streamEndianness) const = 0; + + virtual size_t getSerializedSize() const = 0; + + virtual ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) = 0; + +}; + +#endif /* SERIALIZEIF_H_ */ diff --git a/serviceinterface/ServiceInterfaceBuffer.cpp b/serviceinterface/ServiceInterfaceBuffer.cpp index 8c510eac..e7b2a43e 100644 --- a/serviceinterface/ServiceInterfaceBuffer.cpp +++ b/serviceinterface/ServiceInterfaceBuffer.cpp @@ -1,217 +1,217 @@ -#include -#include -#include -#include - -// to be implemented by bsp -extern "C" void printChar(const char*, bool errStream); - -#ifndef UT699 - -ServiceInterfaceBuffer::ServiceInterfaceBuffer(std::string setMessage, - bool addCrToPreamble, bool buffered , bool errStream, uint16_t port): - isActive(true), logMessage(setMessage), - addCrToPreamble(addCrToPreamble), buffered(buffered), - errStream(errStream) { - if(buffered) { - // Set pointers if the stream is buffered. - setp( buf, buf + BUF_SIZE ); - } - preamble.reserve(MAX_PREAMBLE_SIZE); - preamble.resize(MAX_PREAMBLE_SIZE); -} - -void ServiceInterfaceBuffer::putChars(char const* begin, char const* end) { - char array[BUF_SIZE]; - uint32_t length = end - begin; - if (length > sizeof(array)) { - length = sizeof(array); - } - memcpy(array, begin, length); - - for(; begin != end; begin++){ - if(errStream) { - printChar(begin, true); - } - else { - printChar(begin, false); - } - } -} - -#endif - -int ServiceInterfaceBuffer::overflow(int c) { - if(not buffered and this->isActive) { - if (c != Traits::eof()) { - if(errStream) { - printChar(reinterpret_cast(&c), true); - } - else { - printChar(reinterpret_cast(&c), false); - } - } - return 0; - } - // Handle output - putChars(pbase(), pptr()); - if (c != Traits::eof()) { - char c2 = c; - // Handle the one character that didn't fit to buffer - putChars(&c2, &c2 + 1); - } - // This tells that buffer is empty again - setp(buf, buf + BUF_SIZE - 1); - // I'm not sure about this return value! - return 0; -} - -int ServiceInterfaceBuffer::sync(void) { - if(not this->isActive and not buffered) { - if(not buffered) { - setp(buf, buf + BUF_SIZE - 1); - } - return 0; - } - if(not buffered) { - return 0; - } - - size_t preambleSize = 0; - std::string* preamble = getPreamble(&preambleSize); - // Write logMessage and time - this->putChars(preamble->data(), preamble->data() + preambleSize); - // Handle output - this->putChars(pbase(), pptr()); - // This tells that buffer is empty again - setp(buf, buf + BUF_SIZE - 1); - return 0; -} - -bool ServiceInterfaceBuffer::isBuffered() const { - return buffered; -} - -std::string* ServiceInterfaceBuffer::getPreamble(size_t * preambleSize) { - Clock::TimeOfDay_t loggerTime; - Clock::getDateAndTime(&loggerTime); - size_t currentSize = 0; - char* parsePosition = &preamble[0]; - if(addCrToPreamble) { - preamble[0] = '\r'; - currentSize += 1; - parsePosition += 1; - } - int32_t charCount = sprintf(parsePosition, - "%s: | %02" SCNu32 ":%02" SCNu32 ":%02" SCNu32 ".%03" SCNu32 " | ", - this->logMessage.c_str(), loggerTime.hour, - loggerTime.minute, - loggerTime.second, - loggerTime.usecond /1000); - if(charCount < 0) { - printf("ServiceInterfaceBuffer: Failure parsing preamble\r\n"); - return &preamble; - } - if(charCount > MAX_PREAMBLE_SIZE) { - printf("ServiceInterfaceBuffer: Char count too large for maximum " - "preamble size"); - return &preamble; - } - currentSize += charCount; - if(preambleSize != nullptr) { - *preambleSize = currentSize; - } - return &preamble; -} - - - -#ifdef UT699 -#include - -ServiceInterfaceBuffer::ServiceInterfaceBuffer(std::string set_message, - uint16_t port) { - this->log_message = set_message; - this->isActive = true; - setp( buf, buf + BUF_SIZE ); -} - -void ServiceInterfaceBuffer::putChars(char const* begin, char const* end) { - char array[BUF_SIZE]; - uint32_t length = end - begin; - if (length > sizeof(array)) { - length = sizeof(array); - } - memcpy(array, begin, length); - - if (!Interrupt::isInterruptInProgress()) { - std::cout << array; - } else { - //Uncomment the following line if you need ISR debug output. -// printk(array); - } -} -#endif //UT699 - -#ifdef ML505 -#include -ServiceInterfaceBuffer::ServiceInterfaceBuffer(std::string set_message, - uint16_t port) : - isActive(true), log_message(set_message), udpSocket(0), remoteAddressLength( - sizeof(remoteAddress)) { - setp(buf, buf + BUF_SIZE); - memset((uint8_t*) &remoteAddress, 0, sizeof(remoteAddress)); - remoteAddress.sin_family = AF_INET; - remoteAddress.sin_port = htons(port); - remoteAddress.sin_addr.s_addr = htonl(inet_addr("192.168.250.100")); -} - -void ServiceInterfaceBuffer::putChars(char const* begin, char const* end) { - - char array[BUF_SIZE]; - uint32_t length = end - begin; - if (length > sizeof(array)) { - length = sizeof(array); - } - memcpy(array, begin, length); - - if (udpSocket <= 0) { - initSocket(); - } - - if (udpSocket > 0) { - sendto(udpSocket, array, length, 0, (sockaddr*) &remoteAddress, - sizeof(remoteAddress)); - } - -} - -void ServiceInterfaceBuffer::initSocket() { - sockaddr_in address; - memset((uint8_t*) &address, 0, sizeof(address)); - address.sin_family = AF_INET; - address.sin_port = htons(0); - address.sin_addr.s_addr = htonl(INADDR_ANY); - - udpSocket = socket(PF_INET, SOCK_DGRAM, 0); - if (socket < 0) { - printf("Error opening socket!\n"); - return; - } - timeval timeout = { 0, 20 }; - if (setsockopt(udpSocket, SOL_SOCKET, SO_RCVTIMEO, &timeout, - sizeof(timeout)) < 0) { - printf("Error setting SO_RCVTIMEO socket options!\n"); - return; - } - if (setsockopt(udpSocket, SOL_SOCKET, SO_SNDTIMEO, &timeout, - sizeof(timeout)) < 0) { - printf("Error setting SO_SNDTIMEO socket options!\n"); - return; - } - if (bind(udpSocket, (sockaddr *) &address, sizeof(address)) < 0) { - printf("Error binding socket!\n"); - } -} - -#endif //ML505 +#include "../timemanager/Clock.h" +#include "../serviceinterface/ServiceInterfaceBuffer.h" +#include +#include + +// to be implemented by bsp +extern "C" void printChar(const char*, bool errStream); + +#ifndef UT699 + +ServiceInterfaceBuffer::ServiceInterfaceBuffer(std::string setMessage, + bool addCrToPreamble, bool buffered , bool errStream, uint16_t port): + isActive(true), logMessage(setMessage), + addCrToPreamble(addCrToPreamble), buffered(buffered), + errStream(errStream) { + if(buffered) { + // Set pointers if the stream is buffered. + setp( buf, buf + BUF_SIZE ); + } + preamble.reserve(MAX_PREAMBLE_SIZE); + preamble.resize(MAX_PREAMBLE_SIZE); +} + +void ServiceInterfaceBuffer::putChars(char const* begin, char const* end) { + char array[BUF_SIZE]; + uint32_t length = end - begin; + if (length > sizeof(array)) { + length = sizeof(array); + } + memcpy(array, begin, length); + + for(; begin != end; begin++){ + if(errStream) { + printChar(begin, true); + } + else { + printChar(begin, false); + } + } +} + +#endif + +int ServiceInterfaceBuffer::overflow(int c) { + if(not buffered and this->isActive) { + if (c != Traits::eof()) { + if(errStream) { + printChar(reinterpret_cast(&c), true); + } + else { + printChar(reinterpret_cast(&c), false); + } + } + return 0; + } + // Handle output + putChars(pbase(), pptr()); + if (c != Traits::eof()) { + char c2 = c; + // Handle the one character that didn't fit to buffer + putChars(&c2, &c2 + 1); + } + // This tells that buffer is empty again + setp(buf, buf + BUF_SIZE - 1); + // I'm not sure about this return value! + return 0; +} + +int ServiceInterfaceBuffer::sync(void) { + if(not this->isActive and not buffered) { + if(not buffered) { + setp(buf, buf + BUF_SIZE - 1); + } + return 0; + } + if(not buffered) { + return 0; + } + + size_t preambleSize = 0; + std::string* preamble = getPreamble(&preambleSize); + // Write logMessage and time + this->putChars(preamble->data(), preamble->data() + preambleSize); + // Handle output + this->putChars(pbase(), pptr()); + // This tells that buffer is empty again + setp(buf, buf + BUF_SIZE - 1); + return 0; +} + +bool ServiceInterfaceBuffer::isBuffered() const { + return buffered; +} + +std::string* ServiceInterfaceBuffer::getPreamble(size_t * preambleSize) { + Clock::TimeOfDay_t loggerTime; + Clock::getDateAndTime(&loggerTime); + size_t currentSize = 0; + char* parsePosition = &preamble[0]; + if(addCrToPreamble) { + preamble[0] = '\r'; + currentSize += 1; + parsePosition += 1; + } + int32_t charCount = sprintf(parsePosition, + "%s: | %02" SCNu32 ":%02" SCNu32 ":%02" SCNu32 ".%03" SCNu32 " | ", + this->logMessage.c_str(), loggerTime.hour, + loggerTime.minute, + loggerTime.second, + loggerTime.usecond /1000); + if(charCount < 0) { + printf("ServiceInterfaceBuffer: Failure parsing preamble\r\n"); + return &preamble; + } + if(charCount > MAX_PREAMBLE_SIZE) { + printf("ServiceInterfaceBuffer: Char count too large for maximum " + "preamble size"); + return &preamble; + } + currentSize += charCount; + if(preambleSize != nullptr) { + *preambleSize = currentSize; + } + return &preamble; +} + + + +#ifdef UT699 +#include "../osal/rtems/Interrupt.h" + +ServiceInterfaceBuffer::ServiceInterfaceBuffer(std::string set_message, + uint16_t port) { + this->log_message = set_message; + this->isActive = true; + setp( buf, buf + BUF_SIZE ); +} + +void ServiceInterfaceBuffer::putChars(char const* begin, char const* end) { + char array[BUF_SIZE]; + uint32_t length = end - begin; + if (length > sizeof(array)) { + length = sizeof(array); + } + memcpy(array, begin, length); + + if (!Interrupt::isInterruptInProgress()) { + std::cout << array; + } else { + //Uncomment the following line if you need ISR debug output. +// printk(array); + } +} +#endif //UT699 + +#ifdef ML505 +#include +ServiceInterfaceBuffer::ServiceInterfaceBuffer(std::string set_message, + uint16_t port) : + isActive(true), log_message(set_message), udpSocket(0), remoteAddressLength( + sizeof(remoteAddress)) { + setp(buf, buf + BUF_SIZE); + memset((uint8_t*) &remoteAddress, 0, sizeof(remoteAddress)); + remoteAddress.sin_family = AF_INET; + remoteAddress.sin_port = htons(port); + remoteAddress.sin_addr.s_addr = htonl(inet_addr("192.168.250.100")); +} + +void ServiceInterfaceBuffer::putChars(char const* begin, char const* end) { + + char array[BUF_SIZE]; + uint32_t length = end - begin; + if (length > sizeof(array)) { + length = sizeof(array); + } + memcpy(array, begin, length); + + if (udpSocket <= 0) { + initSocket(); + } + + if (udpSocket > 0) { + sendto(udpSocket, array, length, 0, (sockaddr*) &remoteAddress, + sizeof(remoteAddress)); + } + +} + +void ServiceInterfaceBuffer::initSocket() { + sockaddr_in address; + memset((uint8_t*) &address, 0, sizeof(address)); + address.sin_family = AF_INET; + address.sin_port = htons(0); + address.sin_addr.s_addr = htonl(INADDR_ANY); + + udpSocket = socket(PF_INET, SOCK_DGRAM, 0); + if (socket < 0) { + printf("Error opening socket!\n"); + return; + } + timeval timeout = { 0, 20 }; + if (setsockopt(udpSocket, SOL_SOCKET, SO_RCVTIMEO, &timeout, + sizeof(timeout)) < 0) { + printf("Error setting SO_RCVTIMEO socket options!\n"); + return; + } + if (setsockopt(udpSocket, SOL_SOCKET, SO_SNDTIMEO, &timeout, + sizeof(timeout)) < 0) { + printf("Error setting SO_SNDTIMEO socket options!\n"); + return; + } + if (bind(udpSocket, (sockaddr *) &address, sizeof(address)) < 0) { + printf("Error binding socket!\n"); + } +} + +#endif //ML505 diff --git a/serviceinterface/ServiceInterfaceBuffer.h b/serviceinterface/ServiceInterfaceBuffer.h index 7a2ce2ee..a5c135b6 100644 --- a/serviceinterface/ServiceInterfaceBuffer.h +++ b/serviceinterface/ServiceInterfaceBuffer.h @@ -1,145 +1,145 @@ -#ifndef FRAMEWORK_SERVICEINTERFACE_SERVICEINTERFACEBUFFER_H_ -#define FRAMEWORK_SERVICEINTERFACE_SERVICEINTERFACEBUFFER_H_ - -#include -#include -#include -#include - -#ifndef UT699 - -/** - * @brief This is the underlying stream buffer which implements the - * streambuf class and overloads the overflow() and sync() methods - * @details - * This class is used to modify the output of the stream, for example by adding. - * It also calls the char printing function which is implemented in the - * board supply package (BSP). - */ -class ServiceInterfaceBuffer: - public std::streambuf { - friend class ServiceInterfaceStream; -public: - static constexpr uint8_t MAX_PREAMBLE_SIZE = 40; - - ServiceInterfaceBuffer(std::string setMessage, bool addCrToPreamble, - bool buffered, bool errStream, uint16_t port); - -protected: - bool isActive; - //! This is called when buffer becomes full. If - //! buffer is not used, then this is called every - //! time when characters are put to stream. - int overflow(int c = Traits::eof()) override; - - //! This function is called when stream is flushed, - //! for example when std::endl is put to stream. - int sync(void) override; - - bool isBuffered() const; -private: - //! For additional message information - std::string logMessage; - std::string preamble; - // For EOF detection - typedef std::char_traits Traits; - - //! This is useful for some terminal programs which do not have - //! implicit carriage return with newline characters. - bool addCrToPreamble; - - //! Specifies whether the stream operates in buffered or unbuffered mode. - bool buffered; - //! This specifies to print to stderr and work in unbuffered mode. - bool errStream; - - //! Needed for buffered mode. - static size_t const BUF_SIZE = 128; - char buf[BUF_SIZE]; - - //! In this function, the characters are parsed. - void putChars(char const* begin, char const* end); - - std::string* getPreamble(size_t * preambleSize = nullptr); -}; - -#endif - - -#ifdef UT699 -class ServiceInterfaceBuffer: public std::basic_streambuf > { - friend class ServiceInterfaceStream; -public: - ServiceInterfaceBuffer(std::string set_message, uint16_t port); -protected: - bool isActive; - // This is called when buffer becomes full. If - // buffer is not used, then this is called every - // time when characters are put to stream. - virtual int overflow(int c = Traits::eof()); - - // This function is called when stream is flushed, - // for example when std::endl is put to stream. - virtual int sync(void); - -private: - // For additional message information - std::string log_message; - // For EOF detection - typedef std::char_traits Traits; - - // Work in buffer mode. It is also possible to work without buffer. - static size_t const BUF_SIZE = 128; - char buf[BUF_SIZE]; - - // In this function, the characters are parsed. - void putChars(char const* begin, char const* end); -}; -#endif //UT699 - -#ifdef ML505 -#include -#include -#include -#include -#include - -class ServiceInterfaceBuffer: public std::basic_streambuf > { - friend class ServiceInterfaceStream; -public: - ServiceInterfaceBuffer(std::string set_message, uint16_t port); -protected: - bool isActive; - // This is called when buffer becomes full. If - // buffer is not used, then this is called every - // time when characters are put to stream. - virtual int overflow(int c = Traits::eof()); - - // This function is called when stream is flushed, - // for example when std::endl is put to stream. - virtual int sync(void); - -private: - // For additional message information - std::string log_message; - // For EOF detection - typedef std::char_traits Traits; - - // Work in buffer mode. It is also possible to work without buffer. - static size_t const BUF_SIZE = 128; - char buf[BUF_SIZE]; - - // In this function, the characters are parsed. - void putChars(char const* begin, char const* end); - - int udpSocket; - sockaddr_in remoteAddress; - socklen_t remoteAddressLength; - void initSocket(); -}; -#endif //ML505 - - -#endif /* FRAMEWORK_SERVICEINTERFACE_SERVICEINTERFACEBUFFER_H_ */ +#ifndef FRAMEWORK_SERVICEINTERFACE_SERVICEINTERFACEBUFFER_H_ +#define FRAMEWORK_SERVICEINTERFACE_SERVICEINTERFACEBUFFER_H_ + +#include "../returnvalues/HasReturnvaluesIF.h" +#include +#include +#include + +#ifndef UT699 + +/** + * @brief This is the underlying stream buffer which implements the + * streambuf class and overloads the overflow() and sync() methods + * @details + * This class is used to modify the output of the stream, for example by adding. + * It also calls the char printing function which is implemented in the + * board supply package (BSP). + */ +class ServiceInterfaceBuffer: + public std::streambuf { + friend class ServiceInterfaceStream; +public: + static constexpr uint8_t MAX_PREAMBLE_SIZE = 40; + + ServiceInterfaceBuffer(std::string setMessage, bool addCrToPreamble, + bool buffered, bool errStream, uint16_t port); + +protected: + bool isActive; + //! This is called when buffer becomes full. If + //! buffer is not used, then this is called every + //! time when characters are put to stream. + int overflow(int c = Traits::eof()) override; + + //! This function is called when stream is flushed, + //! for example when std::endl is put to stream. + int sync(void) override; + + bool isBuffered() const; +private: + //! For additional message information + std::string logMessage; + std::string preamble; + // For EOF detection + typedef std::char_traits Traits; + + //! This is useful for some terminal programs which do not have + //! implicit carriage return with newline characters. + bool addCrToPreamble; + + //! Specifies whether the stream operates in buffered or unbuffered mode. + bool buffered; + //! This specifies to print to stderr and work in unbuffered mode. + bool errStream; + + //! Needed for buffered mode. + static size_t const BUF_SIZE = 128; + char buf[BUF_SIZE]; + + //! In this function, the characters are parsed. + void putChars(char const* begin, char const* end); + + std::string* getPreamble(size_t * preambleSize = nullptr); +}; + +#endif + + +#ifdef UT699 +class ServiceInterfaceBuffer: public std::basic_streambuf > { + friend class ServiceInterfaceStream; +public: + ServiceInterfaceBuffer(std::string set_message, uint16_t port); +protected: + bool isActive; + // This is called when buffer becomes full. If + // buffer is not used, then this is called every + // time when characters are put to stream. + virtual int overflow(int c = Traits::eof()); + + // This function is called when stream is flushed, + // for example when std::endl is put to stream. + virtual int sync(void); + +private: + // For additional message information + std::string log_message; + // For EOF detection + typedef std::char_traits Traits; + + // Work in buffer mode. It is also possible to work without buffer. + static size_t const BUF_SIZE = 128; + char buf[BUF_SIZE]; + + // In this function, the characters are parsed. + void putChars(char const* begin, char const* end); +}; +#endif //UT699 + +#ifdef ML505 +#include +#include +#include +#include +#include + +class ServiceInterfaceBuffer: public std::basic_streambuf > { + friend class ServiceInterfaceStream; +public: + ServiceInterfaceBuffer(std::string set_message, uint16_t port); +protected: + bool isActive; + // This is called when buffer becomes full. If + // buffer is not used, then this is called every + // time when characters are put to stream. + virtual int overflow(int c = Traits::eof()); + + // This function is called when stream is flushed, + // for example when std::endl is put to stream. + virtual int sync(void); + +private: + // For additional message information + std::string log_message; + // For EOF detection + typedef std::char_traits Traits; + + // Work in buffer mode. It is also possible to work without buffer. + static size_t const BUF_SIZE = 128; + char buf[BUF_SIZE]; + + // In this function, the characters are parsed. + void putChars(char const* begin, char const* end); + + int udpSocket; + sockaddr_in remoteAddress; + socklen_t remoteAddressLength; + void initSocket(); +}; +#endif //ML505 + + +#endif /* FRAMEWORK_SERVICEINTERFACE_SERVICEINTERFACEBUFFER_H_ */ diff --git a/serviceinterface/ServiceInterfaceStream.cpp b/serviceinterface/ServiceInterfaceStream.cpp index 31bc7c73..7c6676dd 100644 --- a/serviceinterface/ServiceInterfaceStream.cpp +++ b/serviceinterface/ServiceInterfaceStream.cpp @@ -1,32 +1,32 @@ -#include - -ServiceInterfaceStream::ServiceInterfaceStream(std::string setMessage, - bool addCrToPreamble, bool buffered, bool errStream, uint16_t port) : - std::ostream(&streambuf), - streambuf(setMessage, addCrToPreamble, buffered, errStream, port) {} - -void ServiceInterfaceStream::setActive( bool myActive) { - this->streambuf.isActive = myActive; -} - -std::string* ServiceInterfaceStream::getPreamble() { - return streambuf.getPreamble(); -} - -void ServiceInterfaceStream::print(std::string error, - bool withPreamble, bool withNewline, bool flush) { - if(not streambuf.isBuffered() and withPreamble) { - *this << getPreamble() << error; - } - else { - *this << error; - } - - if(withNewline) { - *this << "\n"; - } - // if mode is non-buffered, no need to flush. - if(flush and streambuf.isBuffered()) { - this->flush(); - } -} +#include "../serviceinterface/ServiceInterfaceStream.h" + +ServiceInterfaceStream::ServiceInterfaceStream(std::string setMessage, + bool addCrToPreamble, bool buffered, bool errStream, uint16_t port) : + std::ostream(&streambuf), + streambuf(setMessage, addCrToPreamble, buffered, errStream, port) {} + +void ServiceInterfaceStream::setActive( bool myActive) { + this->streambuf.isActive = myActive; +} + +std::string* ServiceInterfaceStream::getPreamble() { + return streambuf.getPreamble(); +} + +void ServiceInterfaceStream::print(std::string error, + bool withPreamble, bool withNewline, bool flush) { + if(not streambuf.isBuffered() and withPreamble) { + *this << getPreamble() << error; + } + else { + *this << error; + } + + if(withNewline) { + *this << "\n"; + } + // if mode is non-buffered, no need to flush. + if(flush and streambuf.isBuffered()) { + this->flush(); + } +} diff --git a/serviceinterface/ServiceInterfaceStream.h b/serviceinterface/ServiceInterfaceStream.h index dc111459..b1786a38 100644 --- a/serviceinterface/ServiceInterfaceStream.h +++ b/serviceinterface/ServiceInterfaceStream.h @@ -1,58 +1,58 @@ -#ifndef FRAMEWORK_SERVICEINTERFACE_SERVICEINTERFACESTREAM_H_ -#define FRAMEWORK_SERVICEINTERFACE_SERVICEINTERFACESTREAM_H_ - -#include -#include -#include - -/** - * Generic service interface stream which can be used like std::cout or - * std::cerr but has additional capability. Add preamble and timestamp - * to output. Can be run in buffered or unbuffered mode. - */ -class ServiceInterfaceStream : public std::ostream { -public: - /** - * This constructor is used by specifying the preamble message. - * Optionally, the output can be directed to stderr and a CR character - * can be prepended to the preamble. - * @param setMessage message of preamble. - * @param addCrToPreamble Useful for applications like Puttty. - * @param buffered specify whether to use buffered mode. - * @param errStream specify which output stream to use (stderr or stdout). - */ - ServiceInterfaceStream(std::string setMessage, - bool addCrToPreamble = false, bool buffered = true, - bool errStream = false, uint16_t port = 1234); - - //! An inactive stream will not print anything. - void setActive( bool ); - - /** - * This can be used to retrieve the preamble in case it should be printed in - * the unbuffered mode. - * @return Preamle consisting of log message and timestamp. - */ - std::string* getPreamble(); - - /** - * This prints an error with a preamble. Useful if using the unbuffered - * mode. Flushes in default mode (prints immediately). - */ - void print(std::string error, bool withPreamble = true, - bool withNewline = true, bool flush = true); - -protected: - ServiceInterfaceBuffer streambuf; -}; - -// Forward declaration of interface streams. These should be instantiated in -// main. They can then be used like std::cout or std::cerr. -namespace sif { -extern ServiceInterfaceStream debug; -extern ServiceInterfaceStream info; -extern ServiceInterfaceStream warning; -extern ServiceInterfaceStream error; -} - -#endif /* FRAMEWORK_SERVICEINTERFACE_SERVICEINTERFACESTREAM_H_ */ +#ifndef FRAMEWORK_SERVICEINTERFACE_SERVICEINTERFACESTREAM_H_ +#define FRAMEWORK_SERVICEINTERFACE_SERVICEINTERFACESTREAM_H_ + +#include "../serviceinterface/ServiceInterfaceBuffer.h" +#include +#include + +/** + * Generic service interface stream which can be used like std::cout or + * std::cerr but has additional capability. Add preamble and timestamp + * to output. Can be run in buffered or unbuffered mode. + */ +class ServiceInterfaceStream : public std::ostream { +public: + /** + * This constructor is used by specifying the preamble message. + * Optionally, the output can be directed to stderr and a CR character + * can be prepended to the preamble. + * @param setMessage message of preamble. + * @param addCrToPreamble Useful for applications like Puttty. + * @param buffered specify whether to use buffered mode. + * @param errStream specify which output stream to use (stderr or stdout). + */ + ServiceInterfaceStream(std::string setMessage, + bool addCrToPreamble = false, bool buffered = true, + bool errStream = false, uint16_t port = 1234); + + //! An inactive stream will not print anything. + void setActive( bool ); + + /** + * This can be used to retrieve the preamble in case it should be printed in + * the unbuffered mode. + * @return Preamle consisting of log message and timestamp. + */ + std::string* getPreamble(); + + /** + * This prints an error with a preamble. Useful if using the unbuffered + * mode. Flushes in default mode (prints immediately). + */ + void print(std::string error, bool withPreamble = true, + bool withNewline = true, bool flush = true); + +protected: + ServiceInterfaceBuffer streambuf; +}; + +// Forward declaration of interface streams. These should be instantiated in +// main. They can then be used like std::cout or std::cerr. +namespace sif { +extern ServiceInterfaceStream debug; +extern ServiceInterfaceStream info; +extern ServiceInterfaceStream warning; +extern ServiceInterfaceStream error; +} + +#endif /* FRAMEWORK_SERVICEINTERFACE_SERVICEINTERFACESTREAM_H_ */ diff --git a/storagemanager/ConstStorageAccessor.cpp b/storagemanager/ConstStorageAccessor.cpp index 0bfde58c..ea9f2e44 100644 --- a/storagemanager/ConstStorageAccessor.cpp +++ b/storagemanager/ConstStorageAccessor.cpp @@ -1,87 +1,87 @@ -#include -#include -#include -#include - -ConstStorageAccessor::ConstStorageAccessor(store_address_t storeId): - storeId(storeId) {} - -ConstStorageAccessor::ConstStorageAccessor(store_address_t storeId, - StorageManagerIF* store): - storeId(storeId), store(store) { - internalState = AccessState::ASSIGNED; -} - -ConstStorageAccessor::~ConstStorageAccessor() { - if(deleteData and store != nullptr) { - sif::debug << "deleting store data" << std::endl; - store->deleteData(storeId); - } -} - -ConstStorageAccessor::ConstStorageAccessor(ConstStorageAccessor&& other): - constDataPointer(other.constDataPointer), storeId(other.storeId), - size_(other.size_), store(other.store), deleteData(other.deleteData), - internalState(other.internalState) { - // This prevent premature deletion - other.store = nullptr; -} - -ConstStorageAccessor& ConstStorageAccessor::operator=( - ConstStorageAccessor&& other) { - constDataPointer = other.constDataPointer; - storeId = other.storeId; - store = other.store; - size_ = other.size_; - deleteData = other.deleteData; - this->store = other.store; - // This prevents premature deletion - other.store = nullptr; - return *this; -} - -const uint8_t* ConstStorageAccessor::data() const { - return constDataPointer; -} - -size_t ConstStorageAccessor::size() const { - if(internalState == AccessState::UNINIT) { - sif::warning << "StorageAccessor: Not initialized!" << std::endl; - } - return size_; -} - -ReturnValue_t ConstStorageAccessor::getDataCopy(uint8_t *pointer, - size_t maxSize) { - if(internalState == AccessState::UNINIT) { - sif::warning << "StorageAccessor: Not initialized!" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - if(size_ > maxSize) { - sif::error << "StorageAccessor: Supplied buffer not large enough" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - std::copy(constDataPointer, constDataPointer + size_, pointer); - return HasReturnvaluesIF::RETURN_OK; -} - -void ConstStorageAccessor::release() { - deleteData = false; -} - -store_address_t ConstStorageAccessor::getId() const { - return storeId; -} - -void ConstStorageAccessor::print() const { - if(internalState == AccessState::UNINIT or constDataPointer == nullptr) { - sif::warning << "StorageAccessor: Not initialized!" << std::endl; - return; - } - arrayprinter::print(constDataPointer, size_); -} - -void ConstStorageAccessor::assignStore(StorageManagerIF* store) { - internalState = AccessState::ASSIGNED; - this->store = store; -} +#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../storagemanager/ConstStorageAccessor.h" +#include "../storagemanager/StorageManagerIF.h" +#include "../globalfunctions/arrayprinter.h" + +ConstStorageAccessor::ConstStorageAccessor(store_address_t storeId): + storeId(storeId) {} + +ConstStorageAccessor::ConstStorageAccessor(store_address_t storeId, + StorageManagerIF* store): + storeId(storeId), store(store) { + internalState = AccessState::ASSIGNED; +} + +ConstStorageAccessor::~ConstStorageAccessor() { + if(deleteData and store != nullptr) { + sif::debug << "deleting store data" << std::endl; + store->deleteData(storeId); + } +} + +ConstStorageAccessor::ConstStorageAccessor(ConstStorageAccessor&& other): + constDataPointer(other.constDataPointer), storeId(other.storeId), + size_(other.size_), store(other.store), deleteData(other.deleteData), + internalState(other.internalState) { + // This prevent premature deletion + other.store = nullptr; +} + +ConstStorageAccessor& ConstStorageAccessor::operator=( + ConstStorageAccessor&& other) { + constDataPointer = other.constDataPointer; + storeId = other.storeId; + store = other.store; + size_ = other.size_; + deleteData = other.deleteData; + this->store = other.store; + // This prevents premature deletion + other.store = nullptr; + return *this; +} + +const uint8_t* ConstStorageAccessor::data() const { + return constDataPointer; +} + +size_t ConstStorageAccessor::size() const { + if(internalState == AccessState::UNINIT) { + sif::warning << "StorageAccessor: Not initialized!" << std::endl; + } + return size_; +} + +ReturnValue_t ConstStorageAccessor::getDataCopy(uint8_t *pointer, + size_t maxSize) { + if(internalState == AccessState::UNINIT) { + sif::warning << "StorageAccessor: Not initialized!" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + if(size_ > maxSize) { + sif::error << "StorageAccessor: Supplied buffer not large enough" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + std::copy(constDataPointer, constDataPointer + size_, pointer); + return HasReturnvaluesIF::RETURN_OK; +} + +void ConstStorageAccessor::release() { + deleteData = false; +} + +store_address_t ConstStorageAccessor::getId() const { + return storeId; +} + +void ConstStorageAccessor::print() const { + if(internalState == AccessState::UNINIT or constDataPointer == nullptr) { + sif::warning << "StorageAccessor: Not initialized!" << std::endl; + return; + } + arrayprinter::print(constDataPointer, size_); +} + +void ConstStorageAccessor::assignStore(StorageManagerIF* store) { + internalState = AccessState::ASSIGNED; + this->store = store; +} diff --git a/storagemanager/ConstStorageAccessor.h b/storagemanager/ConstStorageAccessor.h index 020030a9..ec2da8ce 100644 --- a/storagemanager/ConstStorageAccessor.h +++ b/storagemanager/ConstStorageAccessor.h @@ -1,116 +1,116 @@ -#ifndef FRAMEWORK_STORAGEMANAGER_CONSTSTORAGEACCESSOR_H_ -#define FRAMEWORK_STORAGEMANAGER_CONSTSTORAGEACCESSOR_H_ - -#include -#include -#include - -class StorageManagerIF; - -/** - * @brief Helper classes to facilitate safe access to storages which is also - * conforming to RAII principles - * @details - * Accessor class which can be returned by pool manager or passed and set by - * pool managers to have safe access to the pool resources. - * - * These helper can be used together with the StorageManager classes to manage - * access to a storage. It can take care of thread-safety while also providing - * mechanisms to automatically clear storage data. - */ -class ConstStorageAccessor { - //! StorageManager classes have exclusive access to private variables. - template - friend class PoolManager; - template - friend class LocalPool; -public: - /** - * @brief Simple constructor which takes the store ID of the storage - * entry to access. - * @param storeId - */ - ConstStorageAccessor(store_address_t storeId); - ConstStorageAccessor(store_address_t storeId, StorageManagerIF* store); - - /** - * @brief The destructor in default configuration takes care of - * deleting the accessed pool entry and unlocking the mutex - */ - virtual ~ConstStorageAccessor(); - - /** - * @brief Returns a pointer to the read-only data - * @return - */ - const uint8_t* data() const; - - /** - * @brief Copies the read-only data to the supplied pointer - * @param pointer - */ - virtual ReturnValue_t getDataCopy(uint8_t *pointer, size_t maxSize); - - /** - * @brief Calling this will prevent the Accessor from deleting the data - * when the destructor is called. - */ - void release(); - - /** - * Get the size of the data - * @return - */ - size_t size() const; - - /** - * Get the storage ID. - * @return - */ - store_address_t getId() const; - - void print() const; - - /** - * @brief Move ctor and move assignment allow returning accessors as - * a returnvalue. They prevent resource being free prematurely. - * Refer to: https://github.com/MicrosoftDocs/cpp-docs/blob/master/docs/cpp/ - * move-constructors-and-move-assignment-operators-cpp.md - * @param - * @return - */ - ConstStorageAccessor& operator= (ConstStorageAccessor&&); - ConstStorageAccessor(ConstStorageAccessor&&); - - //! The copy ctor and copy assignemnt should be deleted implicitely - //! according to https://foonathan.net/2019/02/special-member-functions/ - //! but I still deleted them to make it more explicit. (remember rule of 5). - ConstStorageAccessor& operator=(const ConstStorageAccessor&) = delete; - ConstStorageAccessor(const ConstStorageAccessor&) = delete; -protected: - const uint8_t* constDataPointer = nullptr; - store_address_t storeId; - size_t size_ = 0; - //! Managing pool, has to assign itself. - StorageManagerIF* store = nullptr; - bool deleteData = true; - - enum class AccessState { - UNINIT, - ASSIGNED - }; - //! Internal state for safety reasons. - AccessState internalState = AccessState::UNINIT; - /** - * Used by the pool manager instances to assign themselves to the - * accessor. This is necessary to delete the data when the acessor - * exits the scope ! The internal state will be considered read - * when this function is called, so take care all data is set properly as - * well. - * @param - */ - void assignStore(StorageManagerIF*); -}; - - -#endif /* FRAMEWORK_STORAGEMANAGER_CONSTSTORAGEACCESSOR_H_ */ +#ifndef FRAMEWORK_STORAGEMANAGER_CONSTSTORAGEACCESSOR_H_ +#define FRAMEWORK_STORAGEMANAGER_CONSTSTORAGEACCESSOR_H_ + +#include "../storagemanager/storeAddress.h" +#include "../returnvalues/HasReturnvaluesIF.h" +#include + +class StorageManagerIF; + +/** + * @brief Helper classes to facilitate safe access to storages which is also + * conforming to RAII principles + * @details + * Accessor class which can be returned by pool manager or passed and set by + * pool managers to have safe access to the pool resources. + * + * These helper can be used together with the StorageManager classes to manage + * access to a storage. It can take care of thread-safety while also providing + * mechanisms to automatically clear storage data. + */ +class ConstStorageAccessor { + //! StorageManager classes have exclusive access to private variables. + template + friend class PoolManager; + template + friend class LocalPool; +public: + /** + * @brief Simple constructor which takes the store ID of the storage + * entry to access. + * @param storeId + */ + ConstStorageAccessor(store_address_t storeId); + ConstStorageAccessor(store_address_t storeId, StorageManagerIF* store); + + /** + * @brief The destructor in default configuration takes care of + * deleting the accessed pool entry and unlocking the mutex + */ + virtual ~ConstStorageAccessor(); + + /** + * @brief Returns a pointer to the read-only data + * @return + */ + const uint8_t* data() const; + + /** + * @brief Copies the read-only data to the supplied pointer + * @param pointer + */ + virtual ReturnValue_t getDataCopy(uint8_t *pointer, size_t maxSize); + + /** + * @brief Calling this will prevent the Accessor from deleting the data + * when the destructor is called. + */ + void release(); + + /** + * Get the size of the data + * @return + */ + size_t size() const; + + /** + * Get the storage ID. + * @return + */ + store_address_t getId() const; + + void print() const; + + /** + * @brief Move ctor and move assignment allow returning accessors as + * a returnvalue. They prevent resource being free prematurely. + * Refer to: https://github.com/MicrosoftDocs/cpp-docs/blob/master/docs/cpp/ + * move-constructors-and-move-assignment-operators-cpp.md + * @param + * @return + */ + ConstStorageAccessor& operator= (ConstStorageAccessor&&); + ConstStorageAccessor(ConstStorageAccessor&&); + + //! The copy ctor and copy assignemnt should be deleted implicitely + //! according to https://foonathan.net/2019/02/special-member-functions/ + //! but I still deleted them to make it more explicit. (remember rule of 5). + ConstStorageAccessor& operator=(const ConstStorageAccessor&) = delete; + ConstStorageAccessor(const ConstStorageAccessor&) = delete; +protected: + const uint8_t* constDataPointer = nullptr; + store_address_t storeId; + size_t size_ = 0; + //! Managing pool, has to assign itself. + StorageManagerIF* store = nullptr; + bool deleteData = true; + + enum class AccessState { + UNINIT, + ASSIGNED + }; + //! Internal state for safety reasons. + AccessState internalState = AccessState::UNINIT; + /** + * Used by the pool manager instances to assign themselves to the + * accessor. This is necessary to delete the data when the acessor + * exits the scope ! The internal state will be considered read + * when this function is called, so take care all data is set properly as + * well. + * @param + */ + void assignStore(StorageManagerIF*); +}; + + +#endif /* FRAMEWORK_STORAGEMANAGER_CONSTSTORAGEACCESSOR_H_ */ diff --git a/storagemanager/LocalPool.h b/storagemanager/LocalPool.h index 7e349dcd..5ead7981 100644 --- a/storagemanager/LocalPool.h +++ b/storagemanager/LocalPool.h @@ -1,189 +1,189 @@ -#ifndef FRAMEWORK_STORAGEMANAGER_LOCALPOOL_H_ -#define FRAMEWORK_STORAGEMANAGER_LOCALPOOL_H_ - -#include -#include -#include -#include -#include -#include -#include - -/** - * @brief The LocalPool class provides an intermediate data storage with - * a fixed pool size policy. - * @details The class implements the StorageManagerIF interface. While the - * total number of pools is fixed, the element sizes in one pool and - * the number of pool elements per pool are set on construction. - * The full amount of memory is allocated on construction. - * The overhead is 4 byte per pool element to store the size - * information of each stored element. - * To maintain an "empty" information, the pool size is limited to - * 0xFFFF-1 bytes. - * It is possible to store empty packets in the pool. - * The local pool is NOT thread-safe. - * @author Bastian Baetz - */ -template -class LocalPool: public SystemObject, public StorageManagerIF { -public: - /** - * @brief This definition generally sets the number of different sized pools. - * @details This must be less than the maximum number of pools (currently 0xff). - */ - // static const uint32_t NUMBER_OF_POOLS; - /** - * @brief This is the default constructor for a pool manager instance. - * @details By passing two arrays of size NUMBER_OF_POOLS, the constructor - * allocates memory (with @c new) for store and size_list. These - * regions are all set to zero on start up. - * @param setObjectId The object identifier to be set. This allows for - * multiple instances of LocalPool in the system. - * @param element_sizes An array of size NUMBER_OF_POOLS in which the size - * of a single element in each pool is determined. - * The sizes must be provided in ascending order. - * - * @param n_elements An array of size NUMBER_OF_POOLS in which the - * number of elements for each pool is determined. - * The position of these values correspond to those in - * element_sizes. - * @param registered Register the pool in object manager or not. - * Default is false (local pool). - * @param spillsToHigherPools A variable to determine whether - * higher n pools are used if the store is full. - */ - LocalPool(object_id_t setObjectId, - const uint16_t element_sizes[NUMBER_OF_POOLS], - const uint16_t n_elements[NUMBER_OF_POOLS], - bool registered = false, - bool spillsToHigherPools = false); - /** - * @brief In the LocalPool's destructor all allocated memory is freed. - */ - virtual ~LocalPool(void); - - /** - * Documentation: See StorageManagerIF.h - */ - ReturnValue_t addData(store_address_t* storageId, const uint8_t * data, - size_t size, bool ignoreFault = false) override; - ReturnValue_t getFreeElement(store_address_t* storageId,const size_t size, - uint8_t** p_data, bool ignoreFault = false) override; - - ConstAccessorPair getData(store_address_t packet_id) override; - ReturnValue_t getData(store_address_t packet_id, ConstStorageAccessor&) override; - ReturnValue_t getData(store_address_t packet_id, const uint8_t** packet_ptr, - size_t * size) override; - - AccessorPair modifyData(store_address_t packet_id) override; - ReturnValue_t modifyData(store_address_t packet_id, StorageAccessor&) override; - ReturnValue_t modifyData(store_address_t packet_id, uint8_t** packet_ptr, - size_t * size) override; - - virtual ReturnValue_t deleteData(store_address_t) override; - virtual ReturnValue_t deleteData(uint8_t* ptr, size_t size, - store_address_t* storeId = NULL) override; - void clearStore() override; - ReturnValue_t initialize() override; -protected: - /** - * With this helper method, a free element of @c size is reserved. - * @param size The minimum packet size that shall be reserved. - * @param[out] address Storage ID of the reserved data. - * @return - #RETURN_OK on success, - * - the return codes of #getPoolIndex or #findEmpty otherwise. - */ - virtual ReturnValue_t reserveSpace(const uint32_t size, - store_address_t* address, bool ignoreFault); - - InternalErrorReporterIF *internalErrorReporter; -private: - /** - * Indicates that this element is free. - * This value limits the maximum size of a pool. Change to larger data type - * if increase is required. - */ - static const uint32_t STORAGE_FREE = 0xFFFFFFFF; - /** - * @brief In this array, the element sizes of each pool is stored. - * @details The sizes are maintained for internal pool management. The sizes - * must be set in ascending order on construction. - */ - uint32_t element_sizes[NUMBER_OF_POOLS]; - /** - * @brief n_elements stores the number of elements per pool. - * @details These numbers are maintained for internal pool management. - */ - uint16_t n_elements[NUMBER_OF_POOLS]; - /** - * @brief store represents the actual memory pool. - * @details It is an array of pointers to memory, which was allocated with - * a @c new call on construction. - */ - uint8_t* store[NUMBER_OF_POOLS]; - /** - * @brief The size_list attribute stores the size values of every pool element. - * @details As the number of elements is determined on construction, the size list - * is also dynamically allocated there. - */ - uint32_t* size_list[NUMBER_OF_POOLS]; - //! A variable to determine whether higher n pools are used if - //! the store is full. - bool spillsToHigherPools; - /** - * @brief This method safely stores the given data in the given packet_id. - * @details It also sets the size in size_list. The method does not perform - * any range checks, these are done in advance. - * @param packet_id The storage identifier in which the data shall be stored. - * @param data The data to be stored. - * @param size The size of the data to be stored. - */ - void write(store_address_t packet_id, const uint8_t* data, size_t size); - /** - * @brief A helper method to read the element size of a certain pool. - * @param pool_index The pool in which to look. - * @return Returns the size of an element or 0. - */ - uint32_t getPageSize(uint16_t pool_index); - /** - * @brief This helper method looks up a fitting pool for a given size. - * @details The pools are looked up in ascending order, so the first that - * fits is used. - * @param packet_size The size of the data to be stored. - * @return Returns the pool that fits or StorageManagerIF::INVALID_ADDRESS. - */ - /** - * @brief This helper method looks up a fitting pool for a given size. - * @details The pools are looked up in ascending order, so the first that - * fits is used. - * @param packet_size The size of the data to be stored. - * @param[out] poolIndex The fitting pool index found. - * @return - #RETURN_OK on success, - * - #DATA_TOO_LARGE otherwise. - */ - ReturnValue_t getPoolIndex(size_t packet_size, uint16_t* poolIndex, - uint16_t startAtIndex = 0); - /** - * @brief This helper method calculates the true array position in store - * of a given packet id. - * @details The method does not perform any range checks, these are done in - * advance. - * @param packet_id The packet id to look up. - * @return Returns the position of the data in store. - */ - uint32_t getRawPosition(store_address_t packet_id); - /** - * @brief This is a helper method to find an empty element in a given pool. - * @details The method searches size_list for the first empty element, so - * duration grows with the fill level of the pool. - * @param pool_index The pool in which the search is performed. - * @param[out] element The first found element in the pool. - * @return - #RETURN_OK on success, - * - #DATA_STORAGE_FULL if the store is full - */ - ReturnValue_t findEmpty(uint16_t pool_index, uint16_t* element); -}; - -#include - -#endif /* FRAMEWORK_STORAGEMANAGER_LOCALPOOL_H_ */ +#ifndef FRAMEWORK_STORAGEMANAGER_LOCALPOOL_H_ +#define FRAMEWORK_STORAGEMANAGER_LOCALPOOL_H_ + +#include "../objectmanager/SystemObject.h" +#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../storagemanager/StorageManagerIF.h" +#include "../objectmanager/ObjectManagerIF.h" +#include "../internalError/InternalErrorReporterIF.h" +#include "../storagemanager/StorageAccessor.h" +#include + +/** + * @brief The LocalPool class provides an intermediate data storage with + * a fixed pool size policy. + * @details The class implements the StorageManagerIF interface. While the + * total number of pools is fixed, the element sizes in one pool and + * the number of pool elements per pool are set on construction. + * The full amount of memory is allocated on construction. + * The overhead is 4 byte per pool element to store the size + * information of each stored element. + * To maintain an "empty" information, the pool size is limited to + * 0xFFFF-1 bytes. + * It is possible to store empty packets in the pool. + * The local pool is NOT thread-safe. + * @author Bastian Baetz + */ +template +class LocalPool: public SystemObject, public StorageManagerIF { +public: + /** + * @brief This definition generally sets the number of different sized pools. + * @details This must be less than the maximum number of pools (currently 0xff). + */ + // static const uint32_t NUMBER_OF_POOLS; + /** + * @brief This is the default constructor for a pool manager instance. + * @details By passing two arrays of size NUMBER_OF_POOLS, the constructor + * allocates memory (with @c new) for store and size_list. These + * regions are all set to zero on start up. + * @param setObjectId The object identifier to be set. This allows for + * multiple instances of LocalPool in the system. + * @param element_sizes An array of size NUMBER_OF_POOLS in which the size + * of a single element in each pool is determined. + * The sizes must be provided in ascending order. + * + * @param n_elements An array of size NUMBER_OF_POOLS in which the + * number of elements for each pool is determined. + * The position of these values correspond to those in + * element_sizes. + * @param registered Register the pool in object manager or not. + * Default is false (local pool). + * @param spillsToHigherPools A variable to determine whether + * higher n pools are used if the store is full. + */ + LocalPool(object_id_t setObjectId, + const uint16_t element_sizes[NUMBER_OF_POOLS], + const uint16_t n_elements[NUMBER_OF_POOLS], + bool registered = false, + bool spillsToHigherPools = false); + /** + * @brief In the LocalPool's destructor all allocated memory is freed. + */ + virtual ~LocalPool(void); + + /** + * Documentation: See StorageManagerIF.h + */ + ReturnValue_t addData(store_address_t* storageId, const uint8_t * data, + size_t size, bool ignoreFault = false) override; + ReturnValue_t getFreeElement(store_address_t* storageId,const size_t size, + uint8_t** p_data, bool ignoreFault = false) override; + + ConstAccessorPair getData(store_address_t packet_id) override; + ReturnValue_t getData(store_address_t packet_id, ConstStorageAccessor&) override; + ReturnValue_t getData(store_address_t packet_id, const uint8_t** packet_ptr, + size_t * size) override; + + AccessorPair modifyData(store_address_t packet_id) override; + ReturnValue_t modifyData(store_address_t packet_id, StorageAccessor&) override; + ReturnValue_t modifyData(store_address_t packet_id, uint8_t** packet_ptr, + size_t * size) override; + + virtual ReturnValue_t deleteData(store_address_t) override; + virtual ReturnValue_t deleteData(uint8_t* ptr, size_t size, + store_address_t* storeId = NULL) override; + void clearStore() override; + ReturnValue_t initialize() override; +protected: + /** + * With this helper method, a free element of @c size is reserved. + * @param size The minimum packet size that shall be reserved. + * @param[out] address Storage ID of the reserved data. + * @return - #RETURN_OK on success, + * - the return codes of #getPoolIndex or #findEmpty otherwise. + */ + virtual ReturnValue_t reserveSpace(const uint32_t size, + store_address_t* address, bool ignoreFault); + + InternalErrorReporterIF *internalErrorReporter; +private: + /** + * Indicates that this element is free. + * This value limits the maximum size of a pool. Change to larger data type + * if increase is required. + */ + static const uint32_t STORAGE_FREE = 0xFFFFFFFF; + /** + * @brief In this array, the element sizes of each pool is stored. + * @details The sizes are maintained for internal pool management. The sizes + * must be set in ascending order on construction. + */ + uint32_t element_sizes[NUMBER_OF_POOLS]; + /** + * @brief n_elements stores the number of elements per pool. + * @details These numbers are maintained for internal pool management. + */ + uint16_t n_elements[NUMBER_OF_POOLS]; + /** + * @brief store represents the actual memory pool. + * @details It is an array of pointers to memory, which was allocated with + * a @c new call on construction. + */ + uint8_t* store[NUMBER_OF_POOLS]; + /** + * @brief The size_list attribute stores the size values of every pool element. + * @details As the number of elements is determined on construction, the size list + * is also dynamically allocated there. + */ + uint32_t* size_list[NUMBER_OF_POOLS]; + //! A variable to determine whether higher n pools are used if + //! the store is full. + bool spillsToHigherPools; + /** + * @brief This method safely stores the given data in the given packet_id. + * @details It also sets the size in size_list. The method does not perform + * any range checks, these are done in advance. + * @param packet_id The storage identifier in which the data shall be stored. + * @param data The data to be stored. + * @param size The size of the data to be stored. + */ + void write(store_address_t packet_id, const uint8_t* data, size_t size); + /** + * @brief A helper method to read the element size of a certain pool. + * @param pool_index The pool in which to look. + * @return Returns the size of an element or 0. + */ + uint32_t getPageSize(uint16_t pool_index); + /** + * @brief This helper method looks up a fitting pool for a given size. + * @details The pools are looked up in ascending order, so the first that + * fits is used. + * @param packet_size The size of the data to be stored. + * @return Returns the pool that fits or StorageManagerIF::INVALID_ADDRESS. + */ + /** + * @brief This helper method looks up a fitting pool for a given size. + * @details The pools are looked up in ascending order, so the first that + * fits is used. + * @param packet_size The size of the data to be stored. + * @param[out] poolIndex The fitting pool index found. + * @return - #RETURN_OK on success, + * - #DATA_TOO_LARGE otherwise. + */ + ReturnValue_t getPoolIndex(size_t packet_size, uint16_t* poolIndex, + uint16_t startAtIndex = 0); + /** + * @brief This helper method calculates the true array position in store + * of a given packet id. + * @details The method does not perform any range checks, these are done in + * advance. + * @param packet_id The packet id to look up. + * @return Returns the position of the data in store. + */ + uint32_t getRawPosition(store_address_t packet_id); + /** + * @brief This is a helper method to find an empty element in a given pool. + * @details The method searches size_list for the first empty element, so + * duration grows with the fill level of the pool. + * @param pool_index The pool in which the search is performed. + * @param[out] element The first found element in the pool. + * @return - #RETURN_OK on success, + * - #DATA_STORAGE_FULL if the store is full + */ + ReturnValue_t findEmpty(uint16_t pool_index, uint16_t* element); +}; + +#include "../storagemanager/LocalPool.tpp" + +#endif /* FRAMEWORK_STORAGEMANAGER_LOCALPOOL_H_ */ diff --git a/storagemanager/PoolManager.h b/storagemanager/PoolManager.h index 3c1c1217..2dc3266a 100644 --- a/storagemanager/PoolManager.h +++ b/storagemanager/PoolManager.h @@ -1,49 +1,49 @@ -#ifndef FRAMEWORK_STORAGEMANAGER_POOLMANAGER_H_ -#define FRAMEWORK_STORAGEMANAGER_POOLMANAGER_H_ - -#include -#include -#include - -/** - * @brief The PoolManager class provides an intermediate data storage with - * a fixed pool size policy for inter-process communication. - * @details Uses local pool calls but is thread safe by protecting the call - * with a lock. - * @author Bastian Baetz - */ -template -class PoolManager : public LocalPool { -public: - PoolManager(object_id_t setObjectId, - const uint16_t element_sizes[NUMBER_OF_POOLS], - const uint16_t n_elements[NUMBER_OF_POOLS]); - - //! @brief In the PoolManager's destructor all allocated memory is freed. - virtual ~PoolManager(); - - //! @brief LocalPool overrides for thread-safety. Decorator function which - //! wraps LocalPool calls with a mutex protection. - ReturnValue_t deleteData(store_address_t) override; - ReturnValue_t deleteData(uint8_t* buffer, size_t size, - store_address_t* storeId = nullptr) override; - -protected: - //! Default mutex timeout value to prevent permanent blocking. - static constexpr uint32_t mutexTimeout = 50; - - ReturnValue_t reserveSpace(const uint32_t size, store_address_t* address, - bool ignoreFault) override; - - /** - * @brief The mutex is created in the constructor and makes - * access mutual exclusive. - * @details Locking and unlocking is done during searching for free slots - * and deleting existing slots. - */ - MutexIF* mutex; -}; - -#include "PoolManager.tpp" - -#endif /* POOLMANAGER_H_ */ +#ifndef FRAMEWORK_STORAGEMANAGER_POOLMANAGER_H_ +#define FRAMEWORK_STORAGEMANAGER_POOLMANAGER_H_ + +#include "../storagemanager/LocalPool.h" +#include "../ipc/MutexHelper.h" +#include "../storagemanager/StorageAccessor.h" + +/** + * @brief The PoolManager class provides an intermediate data storage with + * a fixed pool size policy for inter-process communication. + * @details Uses local pool calls but is thread safe by protecting the call + * with a lock. + * @author Bastian Baetz + */ +template +class PoolManager : public LocalPool { +public: + PoolManager(object_id_t setObjectId, + const uint16_t element_sizes[NUMBER_OF_POOLS], + const uint16_t n_elements[NUMBER_OF_POOLS]); + + //! @brief In the PoolManager's destructor all allocated memory is freed. + virtual ~PoolManager(); + + //! @brief LocalPool overrides for thread-safety. Decorator function which + //! wraps LocalPool calls with a mutex protection. + ReturnValue_t deleteData(store_address_t) override; + ReturnValue_t deleteData(uint8_t* buffer, size_t size, + store_address_t* storeId = nullptr) override; + +protected: + //! Default mutex timeout value to prevent permanent blocking. + static constexpr uint32_t mutexTimeout = 50; + + ReturnValue_t reserveSpace(const uint32_t size, store_address_t* address, + bool ignoreFault) override; + + /** + * @brief The mutex is created in the constructor and makes + * access mutual exclusive. + * @details Locking and unlocking is done during searching for free slots + * and deleting existing slots. + */ + MutexIF* mutex; +}; + +#include "PoolManager.tpp" + +#endif /* POOLMANAGER_H_ */ diff --git a/storagemanager/StorageAccessor.cpp b/storagemanager/StorageAccessor.cpp index b827b9c0..d4d2a54d 100644 --- a/storagemanager/StorageAccessor.cpp +++ b/storagemanager/StorageAccessor.cpp @@ -1,67 +1,67 @@ -#include -#include -#include - -StorageAccessor::StorageAccessor(store_address_t storeId): - ConstStorageAccessor(storeId) { -} - -StorageAccessor::StorageAccessor(store_address_t storeId, - StorageManagerIF* store): - ConstStorageAccessor(storeId, store) { -} - -StorageAccessor& StorageAccessor::operator =( - StorageAccessor&& other) { - // Call the parent move assignment and also assign own member. - dataPointer = other.dataPointer; - StorageAccessor::operator=(std::move(other)); - return * this; -} - -// Call the parent move ctor and also transfer own member. -StorageAccessor::StorageAccessor(StorageAccessor&& other): - ConstStorageAccessor(std::move(other)), dataPointer(other.dataPointer) { -} - -ReturnValue_t StorageAccessor::getDataCopy(uint8_t *pointer, size_t maxSize) { - if(internalState == AccessState::UNINIT) { - sif::warning << "StorageAccessor: Not initialized!" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - if(size_ > maxSize) { - sif::error << "StorageAccessor: Supplied buffer not large " - "enough" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - std::copy(dataPointer, dataPointer + size_, pointer); - return HasReturnvaluesIF::RETURN_OK; -} - -uint8_t* StorageAccessor::data() { - if(internalState == AccessState::UNINIT) { - sif::warning << "StorageAccessor: Not initialized!" << std::endl; - } - return dataPointer; -} - -ReturnValue_t StorageAccessor::write(uint8_t *data, size_t size, - uint16_t offset) { - if(internalState == AccessState::UNINIT) { - sif::warning << "StorageAccessor: Not initialized!" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - if(offset + size > size_) { - sif::error << "StorageAccessor: Data too large for pool " - "entry!" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - std::copy(data, data + size, dataPointer + offset); - return HasReturnvaluesIF::RETURN_OK; -} - -void StorageAccessor::assignConstPointer() { - constDataPointer = dataPointer; -} - - +#include "../storagemanager/StorageAccessor.h" +#include "../storagemanager/StorageManagerIF.h" +#include "../serviceinterface/ServiceInterfaceStream.h" + +StorageAccessor::StorageAccessor(store_address_t storeId): + ConstStorageAccessor(storeId) { +} + +StorageAccessor::StorageAccessor(store_address_t storeId, + StorageManagerIF* store): + ConstStorageAccessor(storeId, store) { +} + +StorageAccessor& StorageAccessor::operator =( + StorageAccessor&& other) { + // Call the parent move assignment and also assign own member. + dataPointer = other.dataPointer; + StorageAccessor::operator=(std::move(other)); + return * this; +} + +// Call the parent move ctor and also transfer own member. +StorageAccessor::StorageAccessor(StorageAccessor&& other): + ConstStorageAccessor(std::move(other)), dataPointer(other.dataPointer) { +} + +ReturnValue_t StorageAccessor::getDataCopy(uint8_t *pointer, size_t maxSize) { + if(internalState == AccessState::UNINIT) { + sif::warning << "StorageAccessor: Not initialized!" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + if(size_ > maxSize) { + sif::error << "StorageAccessor: Supplied buffer not large " + "enough" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + std::copy(dataPointer, dataPointer + size_, pointer); + return HasReturnvaluesIF::RETURN_OK; +} + +uint8_t* StorageAccessor::data() { + if(internalState == AccessState::UNINIT) { + sif::warning << "StorageAccessor: Not initialized!" << std::endl; + } + return dataPointer; +} + +ReturnValue_t StorageAccessor::write(uint8_t *data, size_t size, + uint16_t offset) { + if(internalState == AccessState::UNINIT) { + sif::warning << "StorageAccessor: Not initialized!" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + if(offset + size > size_) { + sif::error << "StorageAccessor: Data too large for pool " + "entry!" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + std::copy(data, data + size, dataPointer + offset); + return HasReturnvaluesIF::RETURN_OK; +} + +void StorageAccessor::assignConstPointer() { + constDataPointer = dataPointer; +} + + diff --git a/storagemanager/StorageAccessor.h b/storagemanager/StorageAccessor.h index d75e06ac..1ca5f7dd 100644 --- a/storagemanager/StorageAccessor.h +++ b/storagemanager/StorageAccessor.h @@ -1,45 +1,45 @@ -#ifndef FRAMEWORK_STORAGEMANAGER_STORAGEACCESSOR_H_ -#define FRAMEWORK_STORAGEMANAGER_STORAGEACCESSOR_H_ - -#include - -class StorageManagerIF; - -/** - * @brief Child class for modifyable data. Also has a normal pointer member. - */ -class StorageAccessor: public ConstStorageAccessor { - //! StorageManager classes have exclusive access to private variables. - template - friend class PoolManager; - template - friend class LocalPool; -public: - StorageAccessor(store_address_t storeId); - StorageAccessor(store_address_t storeId, StorageManagerIF* store); - - /** - * @brief Move ctor and move assignment allow returning accessors as - * a returnvalue. They prevent resource being freed prematurely. - * See: https://github.com/MicrosoftDocs/cpp-docs/blob/master/docs/cpp/ - * move-constructors-and-move-assignment-operators-cpp.md - * @param - * @return - */ - StorageAccessor& operator=(StorageAccessor&&); - StorageAccessor(StorageAccessor&&); - - ReturnValue_t write(uint8_t *data, size_t size, - uint16_t offset = 0); - uint8_t* data(); - ReturnValue_t getDataCopy(uint8_t *pointer, size_t maxSize) override; - -private: - //! Non-const pointer for modifyable data. - uint8_t* dataPointer = nullptr; - //! For modifyable data, the const pointer is assigned to the normal - //! pointer by the pool manager so both access functions can be used safely - void assignConstPointer(); -}; - -#endif /* TEST_PROTOTYPES_STORAGEACCESSOR_H_ */ +#ifndef FRAMEWORK_STORAGEMANAGER_STORAGEACCESSOR_H_ +#define FRAMEWORK_STORAGEMANAGER_STORAGEACCESSOR_H_ + +#include "../storagemanager/ConstStorageAccessor.h" + +class StorageManagerIF; + +/** + * @brief Child class for modifyable data. Also has a normal pointer member. + */ +class StorageAccessor: public ConstStorageAccessor { + //! StorageManager classes have exclusive access to private variables. + template + friend class PoolManager; + template + friend class LocalPool; +public: + StorageAccessor(store_address_t storeId); + StorageAccessor(store_address_t storeId, StorageManagerIF* store); + + /** + * @brief Move ctor and move assignment allow returning accessors as + * a returnvalue. They prevent resource being freed prematurely. + * See: https://github.com/MicrosoftDocs/cpp-docs/blob/master/docs/cpp/ + * move-constructors-and-move-assignment-operators-cpp.md + * @param + * @return + */ + StorageAccessor& operator=(StorageAccessor&&); + StorageAccessor(StorageAccessor&&); + + ReturnValue_t write(uint8_t *data, size_t size, + uint16_t offset = 0); + uint8_t* data(); + ReturnValue_t getDataCopy(uint8_t *pointer, size_t maxSize) override; + +private: + //! Non-const pointer for modifyable data. + uint8_t* dataPointer = nullptr; + //! For modifyable data, the const pointer is assigned to the normal + //! pointer by the pool manager so both access functions can be used safely + void assignConstPointer(); +}; + +#endif /* TEST_PROTOTYPES_STORAGEACCESSOR_H_ */ diff --git a/storagemanager/StorageManagerIF.h b/storagemanager/StorageManagerIF.h index f8aee819..85341f2e 100644 --- a/storagemanager/StorageManagerIF.h +++ b/storagemanager/StorageManagerIF.h @@ -1,167 +1,167 @@ -#ifndef STORAGEMANAGERIF_H_H -#define STORAGEMANAGERIF_H_H - -#include -#include -#include -#include -#include -#include - -using AccessorPair = std::pair; -using ConstAccessorPair = std::pair; - -/** - * @brief This class provides an interface for intermediate data storage. - * @details The Storage manager classes shall be used to store larger chunks of - * data in RAM for exchange between tasks. This interface expects the - * data to be stored in one consecutive block of memory, so tasks can - * write directly to the destination pointer. - * For interprocess communication, the stores must be locked during - * insertion and deletion. If the receiving storage identifier is - * passed token-like between tasks, a lock during read and write - * operations is not necessary. - * @author Bastian Baetz - * @date 18.09.2012 - */ -class StorageManagerIF : public HasReturnvaluesIF { -public: - static const uint8_t INTERFACE_ID = CLASS_ID::STORAGE_MANAGER_IF; //!< The unique ID for return codes for this interface. - static const ReturnValue_t DATA_TOO_LARGE = MAKE_RETURN_CODE(1); //!< This return code indicates that the data to be stored is too large for the store. - static const ReturnValue_t DATA_STORAGE_FULL = MAKE_RETURN_CODE(2); //!< This return code indicates that a data storage is full. - static const ReturnValue_t ILLEGAL_STORAGE_ID = MAKE_RETURN_CODE(3); //!< This return code indicates that data was requested with an illegal storage ID. - static const ReturnValue_t DATA_DOES_NOT_EXIST = MAKE_RETURN_CODE(4); //!< This return code indicates that the requested ID was valid, but no data is stored there. - static const ReturnValue_t ILLEGAL_ADDRESS = MAKE_RETURN_CODE(5); - static const ReturnValue_t POOL_TOO_LARGE = MAKE_RETURN_CODE(6); //!< Pool size too large on initialization. - - static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::OBSW; - static const Event GET_DATA_FAILED = MAKE_EVENT(0, SEVERITY::LOW); - static const Event STORE_DATA_FAILED = MAKE_EVENT(1, SEVERITY::LOW); - - static const uint32_t INVALID_ADDRESS = 0xFFFFFFFF; //!< Indicates an invalid (i.e unused) storage address. - /** - * @brief This is the empty virtual destructor as required for C++ interfaces. - */ - virtual ~StorageManagerIF() { - } - ; - /** - * @brief With addData, a free storage position is allocated and data - * stored there. - * @details During the allocation, the StorageManager is blocked. - * @param storageId A pointer to the storageId to retrieve. - * @param data The data to be stored in the StorageManager. - * @param size The amount of data to be stored. - * @return Returns @li RETURN_OK if data was added. - * @li RETURN_FAILED if data could not be added. - * storageId is unchanged then. - */ - virtual ReturnValue_t addData(store_address_t* storageId, - const uint8_t * data, size_t size, bool ignoreFault = false) = 0; - /** - * @brief With deleteData, the storageManager frees the memory region - * identified by packet_id. - * @param packet_id The identifier of the memory region to be freed. - * @return @li RETURN_OK on success. - * @li RETURN_FAILED if deletion did not work - * (e.g. an illegal packet_id was passed). - */ - virtual ReturnValue_t deleteData(store_address_t packet_id) = 0; - /** - * @brief Another deleteData which uses the pointer and size of the - * stored data to delete the content. - * @param buffer Pointer to the data. - * @param size Size of data to be stored. - * @param storeId Store id of the deleted element (optional) - * @return @li RETURN_OK on success. - * @li failure code if deletion did not work - */ - virtual ReturnValue_t deleteData(uint8_t* buffer, size_t size, - store_address_t* storeId = nullptr) = 0; - - - /** - * @brief Access the data by supplying a store ID. - * @details - * A pair consisting of the retrieval result and an instance of a - * ConstStorageAccessor class is returned - * @param storeId - * @return Pair of return value and a ConstStorageAccessor instance - */ - virtual ConstAccessorPair getData(store_address_t storeId) = 0; - - /** - * @brief Access the data by supplying a store ID and a helper - * instance - * @param storeId - * @param constAccessor Wrapper function to access store data. - * @return - */ - virtual ReturnValue_t getData(store_address_t storeId, - ConstStorageAccessor& constAccessor) = 0; - - - /** - * @brief getData returns an address to data and the size of the data - * for a given packet_id. - * @param packet_id The id of the data to be returned - * @param packet_ptr The passed pointer address is set to the the memory - * position - * @param size The exact size of the stored data is returned here. - * @return @li RETURN_OK on success. - * @li RETURN_FAILED if fetching data did not work - * (e.g. an illegal packet_id was passed). - */ - virtual ReturnValue_t getData(store_address_t packet_id, - const uint8_t** packet_ptr, size_t* size) = 0; - - - /** - * Modify data by supplying a store ID - * @param storeId - * @return Pair of return value and StorageAccessor helper - */ - virtual AccessorPair modifyData(store_address_t storeId) = 0; - - /** - * Modify data by supplying a store ID and a StorageAccessor helper instance. - * @param storeId - * @param accessor Helper class to access the modifiable data. - * @return - */ - virtual ReturnValue_t modifyData(store_address_t storeId, - StorageAccessor& accessor) = 0; - - /** - * Get pointer and size of modifiable data by supplying the storeId - * @param packet_id - * @param packet_ptr [out] Pointer to pointer of data to set - * @param size [out] Pointer to size to set - * @return - */ - virtual ReturnValue_t modifyData(store_address_t packet_id, - uint8_t** packet_ptr, size_t* size) = 0; - /** - * This method reserves an element of \c size. - * - * It returns the packet id of this element as well as a direct pointer to the - * data of the element. It must be assured that exactly \c size data is - * written to p_data! - * @param storageId A pointer to the storageId to retrieve. - * @param size The size of the space to be reserved. - * @param p_data A pointer to the element data is returned here. - * @return Returns @li RETURN_OK if data was added. - * @li RETURN_FAILED if data could not be added. - * storageId is unchanged then. - */ - virtual ReturnValue_t getFreeElement(store_address_t* storageId, - const size_t size, uint8_t** p_data, bool ignoreFault = false ) = 0; - - /** - * Clears the whole store. - * Use with care! - */ - virtual void clearStore() = 0; -}; - -#endif /* STORAGEMANAGERIF_H_ */ +#ifndef STORAGEMANAGERIF_H_H +#define STORAGEMANAGERIF_H_H + +#include "../events/Event.h" +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../storagemanager/StorageAccessor.h" +#include "../storagemanager/storeAddress.h" +#include +#include + +using AccessorPair = std::pair; +using ConstAccessorPair = std::pair; + +/** + * @brief This class provides an interface for intermediate data storage. + * @details The Storage manager classes shall be used to store larger chunks of + * data in RAM for exchange between tasks. This interface expects the + * data to be stored in one consecutive block of memory, so tasks can + * write directly to the destination pointer. + * For interprocess communication, the stores must be locked during + * insertion and deletion. If the receiving storage identifier is + * passed token-like between tasks, a lock during read and write + * operations is not necessary. + * @author Bastian Baetz + * @date 18.09.2012 + */ +class StorageManagerIF : public HasReturnvaluesIF { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::STORAGE_MANAGER_IF; //!< The unique ID for return codes for this interface. + static const ReturnValue_t DATA_TOO_LARGE = MAKE_RETURN_CODE(1); //!< This return code indicates that the data to be stored is too large for the store. + static const ReturnValue_t DATA_STORAGE_FULL = MAKE_RETURN_CODE(2); //!< This return code indicates that a data storage is full. + static const ReturnValue_t ILLEGAL_STORAGE_ID = MAKE_RETURN_CODE(3); //!< This return code indicates that data was requested with an illegal storage ID. + static const ReturnValue_t DATA_DOES_NOT_EXIST = MAKE_RETURN_CODE(4); //!< This return code indicates that the requested ID was valid, but no data is stored there. + static const ReturnValue_t ILLEGAL_ADDRESS = MAKE_RETURN_CODE(5); + static const ReturnValue_t POOL_TOO_LARGE = MAKE_RETURN_CODE(6); //!< Pool size too large on initialization. + + static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::OBSW; + static const Event GET_DATA_FAILED = MAKE_EVENT(0, SEVERITY::LOW); + static const Event STORE_DATA_FAILED = MAKE_EVENT(1, SEVERITY::LOW); + + static const uint32_t INVALID_ADDRESS = 0xFFFFFFFF; //!< Indicates an invalid (i.e unused) storage address. + /** + * @brief This is the empty virtual destructor as required for C++ interfaces. + */ + virtual ~StorageManagerIF() { + } + ; + /** + * @brief With addData, a free storage position is allocated and data + * stored there. + * @details During the allocation, the StorageManager is blocked. + * @param storageId A pointer to the storageId to retrieve. + * @param data The data to be stored in the StorageManager. + * @param size The amount of data to be stored. + * @return Returns @li RETURN_OK if data was added. + * @li RETURN_FAILED if data could not be added. + * storageId is unchanged then. + */ + virtual ReturnValue_t addData(store_address_t* storageId, + const uint8_t * data, size_t size, bool ignoreFault = false) = 0; + /** + * @brief With deleteData, the storageManager frees the memory region + * identified by packet_id. + * @param packet_id The identifier of the memory region to be freed. + * @return @li RETURN_OK on success. + * @li RETURN_FAILED if deletion did not work + * (e.g. an illegal packet_id was passed). + */ + virtual ReturnValue_t deleteData(store_address_t packet_id) = 0; + /** + * @brief Another deleteData which uses the pointer and size of the + * stored data to delete the content. + * @param buffer Pointer to the data. + * @param size Size of data to be stored. + * @param storeId Store id of the deleted element (optional) + * @return @li RETURN_OK on success. + * @li failure code if deletion did not work + */ + virtual ReturnValue_t deleteData(uint8_t* buffer, size_t size, + store_address_t* storeId = nullptr) = 0; + + + /** + * @brief Access the data by supplying a store ID. + * @details + * A pair consisting of the retrieval result and an instance of a + * ConstStorageAccessor class is returned + * @param storeId + * @return Pair of return value and a ConstStorageAccessor instance + */ + virtual ConstAccessorPair getData(store_address_t storeId) = 0; + + /** + * @brief Access the data by supplying a store ID and a helper + * instance + * @param storeId + * @param constAccessor Wrapper function to access store data. + * @return + */ + virtual ReturnValue_t getData(store_address_t storeId, + ConstStorageAccessor& constAccessor) = 0; + + + /** + * @brief getData returns an address to data and the size of the data + * for a given packet_id. + * @param packet_id The id of the data to be returned + * @param packet_ptr The passed pointer address is set to the the memory + * position + * @param size The exact size of the stored data is returned here. + * @return @li RETURN_OK on success. + * @li RETURN_FAILED if fetching data did not work + * (e.g. an illegal packet_id was passed). + */ + virtual ReturnValue_t getData(store_address_t packet_id, + const uint8_t** packet_ptr, size_t* size) = 0; + + + /** + * Modify data by supplying a store ID + * @param storeId + * @return Pair of return value and StorageAccessor helper + */ + virtual AccessorPair modifyData(store_address_t storeId) = 0; + + /** + * Modify data by supplying a store ID and a StorageAccessor helper instance. + * @param storeId + * @param accessor Helper class to access the modifiable data. + * @return + */ + virtual ReturnValue_t modifyData(store_address_t storeId, + StorageAccessor& accessor) = 0; + + /** + * Get pointer and size of modifiable data by supplying the storeId + * @param packet_id + * @param packet_ptr [out] Pointer to pointer of data to set + * @param size [out] Pointer to size to set + * @return + */ + virtual ReturnValue_t modifyData(store_address_t packet_id, + uint8_t** packet_ptr, size_t* size) = 0; + /** + * This method reserves an element of \c size. + * + * It returns the packet id of this element as well as a direct pointer to the + * data of the element. It must be assured that exactly \c size data is + * written to p_data! + * @param storageId A pointer to the storageId to retrieve. + * @param size The size of the space to be reserved. + * @param p_data A pointer to the element data is returned here. + * @return Returns @li RETURN_OK if data was added. + * @li RETURN_FAILED if data could not be added. + * storageId is unchanged then. + */ + virtual ReturnValue_t getFreeElement(store_address_t* storageId, + const size_t size, uint8_t** p_data, bool ignoreFault = false ) = 0; + + /** + * Clears the whole store. + * Use with care! + */ + virtual void clearStore() = 0; +}; + +#endif /* STORAGEMANAGERIF_H_ */ diff --git a/subsystem/Subsystem.cpp b/subsystem/Subsystem.cpp index fcf2e189..a4869eba 100644 --- a/subsystem/Subsystem.cpp +++ b/subsystem/Subsystem.cpp @@ -1,662 +1,662 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -Subsystem::Subsystem(object_id_t setObjectId, object_id_t parent, - uint32_t maxNumberOfSequences, uint32_t maxNumberOfTables) : - SubsystemBase(setObjectId, parent, 0), isInTransition(false), childrenChangedHealth( - false), uptimeStartTable(0), currentTargetTable(), targetMode( - 0), targetSubmode(SUBMODE_NONE), initialMode(0), currentSequenceIterator(), modeTables( - maxNumberOfTables), modeSequences(maxNumberOfSequences), IPCStore( - NULL) -#ifdef USE_MODESTORE -,modeStore(NULL) -#endif -{ - -} - -Subsystem::~Subsystem() { - //Auto-generated destructor stub -} - -ReturnValue_t Subsystem::checkSequence(HybridIterator iter, - Mode_t fallbackSequence) { - - //only check for existence, checking the fallback would lead to a (possibly infinite) recursion. - //the fallback sequence will be checked when it is needed. - if (!existsModeSequence(fallbackSequence)) { - return FALLBACK_SEQUENCE_DOES_NOT_EXIST; - } - - if (iter.value == NULL) { - return NO_TARGET_TABLE; - } - - for (; iter.value != NULL; ++iter) { - if (!existsModeTable(iter->getTableId())) { - return TABLE_DOES_NOT_EXIST; - } else { - ReturnValue_t result = checkTable(getTable(iter->getTableId())); - if (result != RETURN_OK) { - return result; - } - } - } - return RETURN_OK; -} - -ReturnValue_t Subsystem::checkSequence(Mode_t sequence) { - if (!existsModeSequence(sequence)) { - return SEQUENCE_DOES_NOT_EXIST; - } - HybridIterator iter = getSequence(sequence); - return checkSequence(iter, getFallbackSequence(sequence)); -} - -bool Subsystem::existsModeSequence(Mode_t id) { - return modeSequences.exists(id) == RETURN_OK; -} - -bool Subsystem::existsModeTable(Mode_t id) { - return modeTables.exists(id) == RETURN_OK; -} - -HybridIterator Subsystem::getCurrentTable() { - return getTable(currentSequenceIterator->getTableId()); -} - -void Subsystem::performChildOperation() { - if (isInTransition) { - if (commandsOutstanding <= 0) { //all children of the current table were commanded and replied - if (currentSequenceIterator.value == NULL) { //we're through with this sequence - if (checkStateAgainstTable(currentTargetTable, targetSubmode) - == RETURN_OK) { - setMode(targetMode, targetSubmode); - isInTransition = false; - return; - } else { - transitionFailed(TARGET_TABLE_NOT_REACHED, - getSequence(targetMode)->getTableId()); - return; - } - } - if (currentSequenceIterator->checkSuccess()) { - if (checkStateAgainstTable(getCurrentTable(), targetSubmode) - != RETURN_OK) { - transitionFailed(TABLE_CHECK_FAILED, - currentSequenceIterator->getTableId()); - return; - } - } - if (currentSequenceIterator->getWaitSeconds() != 0) { - if (uptimeStartTable == 0) { - Clock::getUptime(&uptimeStartTable); - return; - } else { - uint32_t uptimeNow; - Clock::getUptime(&uptimeNow); - if ((uptimeNow - uptimeStartTable) - < (currentSequenceIterator->getWaitSeconds() * 1000)) { - return; - } - } - } - uptimeStartTable = 0; - //next Table, but only if there is one - if ((++currentSequenceIterator).value != NULL) { //we're through with this sequence - executeTable(getCurrentTable(), targetSubmode); - } - } - } else { - if (childrenChangedHealth) { - triggerEvent(CHILD_CHANGED_HEALTH, 0, 0); - childrenChangedHealth = false; - startTransition(mode, submode); - } else if (childrenChangedMode) { - if (checkStateAgainstTable(currentTargetTable, submode) - != RETURN_OK) { - triggerEvent(CANT_KEEP_MODE, mode, submode); - cantKeepMode(); - } - } - } -} - -HybridIterator Subsystem::getSequence(Mode_t id) { - SequenceInfo *sequenceInfo = modeSequences.findValue(id); - if (sequenceInfo->entries.islinked) { - return HybridIterator( - sequenceInfo->entries.firstLinkedElement); - } else { - return HybridIterator( - sequenceInfo->entries.array->front(), - sequenceInfo->entries.array->back()); - } -} - -HybridIterator Subsystem::getTable(Mode_t id) { - EntryPointer *entry = modeTables.findValue(id); - if (entry->islinked) { - return HybridIterator(entry->firstLinkedElement); - } else { - return HybridIterator(entry->array->front(), - entry->array->back()); - } -} - -ReturnValue_t Subsystem::handleCommandMessage(CommandMessage *message) { - ReturnValue_t result; - switch (message->getCommand()) { - case HealthMessage::HEALTH_INFO: { - HealthState health = HealthMessage::getHealth(message); - if (health != EXTERNAL_CONTROL) { - //Ignore external control, as it has an effect only if the mode changes, - //which is communicated with an additional mode info event. - childrenChangedHealth = true; - } - } - break; - case ModeSequenceMessage::ADD_SEQUENCE: { - FixedArrayList sequence; - const uint8_t *pointer; - size_t sizeRead; - result = IPCStore->getData( - ModeSequenceMessage::getStoreAddress(message), &pointer, - &sizeRead); - if (result == RETURN_OK) { - Mode_t fallbackId; - size_t size = sizeRead; - result = SerializeAdapter::deSerialize(&fallbackId, &pointer, &size, - SerializeIF::Endianness::BIG); - if (result == RETURN_OK) { - result = SerialArrayListAdapter::deSerialize( - &sequence, &pointer, &size, - SerializeIF::Endianness::BIG); - if (result == RETURN_OK) { - result = addSequence(&sequence, - ModeSequenceMessage::getSequenceId(message), - fallbackId); - } - } - IPCStore->deleteData(ModeSequenceMessage::getStoreAddress(message)); - } - replyToCommand(result, 0); - } - break; - case ModeSequenceMessage::ADD_TABLE: { - FixedArrayList table; - const uint8_t *pointer; - size_t sizeRead; - result = IPCStore->getData( - ModeSequenceMessage::getStoreAddress(message), &pointer, - &sizeRead); - if (result == RETURN_OK) { - size_t size = sizeRead; - result = SerialArrayListAdapter::deSerialize(&table, - &pointer, &size, SerializeIF::Endianness::BIG); - if (result == RETURN_OK) { - result = addTable(&table, - ModeSequenceMessage::getSequenceId(message)); - } - IPCStore->deleteData(ModeSequenceMessage::getStoreAddress(message)); - } - replyToCommand(result, 0); - - } - break; - case ModeSequenceMessage::DELETE_SEQUENCE: - if (isInTransition) { - replyToCommand(IN_TRANSITION, 0); - break; - } - result = deleteSequence(ModeSequenceMessage::getSequenceId(message)); - replyToCommand(result, 0); - break; - case ModeSequenceMessage::DELETE_TABLE: - if (isInTransition) { - replyToCommand(IN_TRANSITION, 0); - break; - } - result = deleteTable(ModeSequenceMessage::getTableId(message)); - replyToCommand(result, 0); - break; - case ModeSequenceMessage::LIST_SEQUENCES: { - SerialFixedArrayListAdapter sequences; - FixedMap::Iterator iter; - for (iter = modeSequences.begin(); iter != modeSequences.end(); - ++iter) { - sequences.insert(iter.value->first); - } - SerializeIF *pointer = &sequences; - sendSerializablesAsCommandMessage(ModeSequenceMessage::SEQUENCE_LIST, - &pointer, 1); - } - break; - case ModeSequenceMessage::LIST_TABLES: { - SerialFixedArrayListAdapter tables; - FixedMap::Iterator iter; - for (iter = modeTables.begin(); iter != modeTables.end(); ++iter) { - tables.insert(iter.value->first); - } - SerializeIF *pointer = &tables; - sendSerializablesAsCommandMessage(ModeSequenceMessage::TABLE_LIST, - &pointer, 1); - } - break; - case ModeSequenceMessage::READ_SEQUENCE: { - ReturnValue_t result; - Mode_t sequence = ModeSequenceMessage::getSequenceId(message); - SequenceInfo *sequenceInfo = NULL; - result = modeSequences.find(sequence, &sequenceInfo); - if (result != RETURN_OK) { - replyToCommand(result, 0); - } - - SerializeIF *elements[3]; - SerializeElement sequenceId(sequence); - SerializeElement fallbackSequenceId( - getFallbackSequence(sequence)); - - elements[0] = &sequenceId; - elements[1] = &fallbackSequenceId; - - if (sequenceInfo->entries.islinked) { - SerialLinkedListAdapter list( - sequenceInfo->entries.firstLinkedElement, true); - elements[2] = &list; - sendSerializablesAsCommandMessage(ModeSequenceMessage::SEQUENCE, - elements, 3); - } else { - SerialArrayListAdapter serializableArray( - sequenceInfo->entries.array); - - elements[2] = &serializableArray; - sendSerializablesAsCommandMessage(ModeSequenceMessage::SEQUENCE, - elements, 3); - } - } - break; - case ModeSequenceMessage::READ_TABLE: { - ReturnValue_t result; - Mode_t table = ModeSequenceMessage::getSequenceId(message); - EntryPointer *entry = NULL; - result = modeTables.find(table, &entry); - if (result != RETURN_OK) { - replyToCommand(result, 0); - } - - SerializeIF *elements[2]; - SerializeElement tableId(table); - - elements[0] = &tableId; - - if (entry->islinked) { - SerialLinkedListAdapter list( - entry->firstLinkedElement, true); - elements[1] = &list; - sendSerializablesAsCommandMessage(ModeSequenceMessage::TABLE, - elements, 2); - } else { - SerialArrayListAdapter serializableArray( - entry->array); - elements[1] = &serializableArray; - sendSerializablesAsCommandMessage(ModeSequenceMessage::TABLE, - elements, 2); - } - } - break; - case ModeSequenceMessage::READ_FREE_SEQUENCE_SLOTS: { - uint32_t freeSlots = modeSequences.maxSize() - modeSequences.size(); - CommandMessage reply; - ModeSequenceMessage::setModeSequenceMessage(&reply, - ModeSequenceMessage::FREE_SEQUENCE_SLOTS, freeSlots); - commandQueue->reply(&reply); - } - break; - case ModeSequenceMessage::READ_FREE_TABLE_SLOTS: { - uint32_t free = modeTables.maxSize() - modeTables.size(); - CommandMessage reply; - ModeSequenceMessage::setModeSequenceMessage(&reply, - ModeSequenceMessage::FREE_TABLE_SLOTS, free); - commandQueue->reply(&reply); - } - break; - default: - return RETURN_FAILED; - } - return RETURN_OK; -} - -void Subsystem::replyToCommand(ReturnValue_t status, uint32_t parameter) { - if (status == RETURN_OK) { - CommandMessage reply(CommandMessage::REPLY_COMMAND_OK, 0, 0); - commandQueue->reply(&reply); - } else { - CommandMessage reply(CommandMessage::REPLY_REJECTED, status, 0); - commandQueue->reply(&reply); - } -} - -ReturnValue_t Subsystem::addSequence(ArrayList *sequence, - Mode_t id, Mode_t fallbackSequence, bool inStore, bool preInit) { - - ReturnValue_t result; - - //Before initialize() is called, tables must not be checked as the children are not added yet. - //Sequences added before are checked by initialize() - if (!preInit) { - result = checkSequence( - HybridIterator(sequence->front(), - sequence->back()), fallbackSequence); - if (result != RETURN_OK) { - return result; - } - } - - SequenceInfo info; - - info.fallbackSequence = fallbackSequence; - - info.entries.islinked = inStore; - info.entries.array = sequence; - - result = modeSequences.insert(id, info); - - if (result != RETURN_OK) { - return result; - } - - if (inStore) { -#ifdef USE_MODESTORE - result = modeStore->storeArray(sequence, - &(modeSequences.find(id)->entries.firstLinkedElement)); - if (result != RETURN_OK) { - modeSequences.erase(id); - } -#else - modeSequences.erase(id); - return RETURN_FAILED; -#endif - } - - return result; - -} - -ReturnValue_t Subsystem::addTable(ArrayList *table, Mode_t id, - bool inStore, bool preInit) { - - ReturnValue_t result; - - //Before initialize() is called, tables must not be checked as the children are not added yet. - //Tables added before are checked by initialize() - if (!preInit) { - result = checkTable( - HybridIterator(table->front(), table->back())); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - } - - EntryPointer pointer; - - pointer.islinked = inStore; - pointer.array = table; - - result = modeTables.insert(id, pointer); - - if (result != RETURN_OK) { - return result; - } - - if (inStore) { -#ifdef USE_MODESTORE - result = modeStore->storeArray(table, - &(modeTables.find(id)->firstLinkedElement)); - if (result != RETURN_OK) { - modeTables.erase(id); - } -#else - modeTables.erase(id); - return RETURN_FAILED; -#endif - } - return result; -} - -ReturnValue_t Subsystem::deleteSequence(Mode_t id) { - - if (isFallbackSequence(id)) { - return IS_FALLBACK_SEQUENCE; - } - - SequenceInfo *sequenceInfo; - ReturnValue_t result; - result = modeSequences.find(id, &sequenceInfo); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - if (!sequenceInfo->entries.islinked) { - return ACCESS_DENIED; - } - -#ifdef USE_MODESTORE - modeStore->deleteList(sequenceInfo->entries.firstLinkedElement); -#endif - modeSequences.erase(id); - return RETURN_OK; -} - -ReturnValue_t Subsystem::deleteTable(Mode_t id) { - - if (isTableUsed(id)) { - return TABLE_IN_USE; - } - - EntryPointer *pointer; - ReturnValue_t result; - result = modeTables.find(id, &pointer); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - if (!pointer->islinked) { - return ACCESS_DENIED; - } - -#ifdef USE_MODESTORE - modeStore->deleteList(pointer->firstLinkedElement); -#endif - modeSequences.erase(id); - return RETURN_OK; -} - -ReturnValue_t Subsystem::initialize() { - ReturnValue_t result = SubsystemBase::initialize(); - - if (result != RETURN_OK) { - return result; - } - - IPCStore = objectManager->get(objects::IPC_STORE); - if (IPCStore == NULL) { - return RETURN_FAILED; - } - -#ifdef USE_MODESTORE - modeStore = objectManager->get(objects::MODE_STORE); - - if (modeStore == NULL) { - return RETURN_FAILED; - } -#endif - - if ((modeSequences.maxSize() > MAX_NUMBER_OF_TABLES_OR_SEQUENCES) - || (modeTables.maxSize() > MAX_NUMBER_OF_TABLES_OR_SEQUENCES)) { - return TABLE_OR_SEQUENCE_LENGTH_INVALID; - } - - mode = initialMode; - - return RETURN_OK; -} - -MessageQueueId_t Subsystem::getSequenceCommandQueue() const { - return SubsystemBase::getCommandQueue(); -} - -ReturnValue_t Subsystem::checkModeCommand(Mode_t mode, Submode_t submode, - uint32_t *msToReachTheMode) { - //Need to accept all submodes to be able to inherit submodes -// if (submode != SUBMODE_NONE) { -// return INVALID_SUBMODE; -// } - - if (isInTransition && (mode != getFallbackSequence(targetMode))) { - return HasModesIF::IN_TRANSITION; - } else { - return checkSequence(mode); - } -} - -void Subsystem::startTransition(Mode_t sequence, Submode_t submode) { - if (modeHelper.isForced()) { - triggerEvent(FORCING_MODE, sequence, submode); - } else { - triggerEvent(CHANGING_MODE, sequence, submode); - } - targetMode = sequence; - targetSubmode = submode; - isInTransition = true; - commandsOutstanding = 0; - currentSequenceIterator = getSequence(sequence); - - currentTargetTable = getTable(currentSequenceIterator->getTableId()); - - ++currentSequenceIterator; - - if (currentSequenceIterator.value != NULL) { - executeTable(getCurrentTable(), targetSubmode); - } -} - -Mode_t Subsystem::getFallbackSequence(Mode_t sequence) { - for (FixedMap::Iterator iter = modeSequences.begin(); - iter != modeSequences.end(); ++iter) { - if (iter.value->first == sequence) { - return iter->fallbackSequence; - } - } - return -1; -} - -bool Subsystem::isFallbackSequence(Mode_t SequenceId) { - for (FixedMap::Iterator iter = modeSequences.begin(); - iter != modeSequences.end(); iter++) { - if (iter->fallbackSequence == SequenceId) { - return true; - } - } - return false; -} - -bool Subsystem::isTableUsed(Mode_t tableId) { - for (FixedMap::Iterator sequence = - modeSequences.begin(); sequence != modeSequences.end(); - sequence++) { - HybridIterator sequenceIterator = getSequence( - sequence.value->first); - while (sequenceIterator.value != NULL) { - if (sequenceIterator->getTableId() == tableId) { - return true; - } - ++sequenceIterator; - } - } - return false; -} - -void Subsystem::transitionFailed(ReturnValue_t failureCode, - uint32_t parameter) { - triggerEvent(MODE_TRANSITION_FAILED, failureCode, parameter); - if (mode == targetMode) { - //already tried going back to the current mode - //go into fallback mode, also set current mode to fallback mode, so we come here at the next fail - modeHelper.setForced(true); - ReturnValue_t result; - if ((result = checkSequence(getFallbackSequence(mode))) != RETURN_OK) { - triggerEvent(FALLBACK_FAILED, result, getFallbackSequence(mode)); - isInTransition = false; //keep still and allow arbitrary mode commands to recover - return; - } - mode = getFallbackSequence(mode); - startTransition(mode, submode); - } else { - //try to go back to the current mode - startTransition(mode, submode); - } -} - -void Subsystem::sendSerializablesAsCommandMessage(Command_t command, - SerializeIF **elements, uint8_t count) { - ReturnValue_t result; - size_t maxSize = 0; - for (uint8_t i = 0; i < count; i++) { - maxSize += elements[i]->getSerializedSize(); - } - uint8_t *storeBuffer; - store_address_t address; - size_t size = 0; - - result = IPCStore->getFreeElement(&address, maxSize, &storeBuffer); - if (result != HasReturnvaluesIF::RETURN_OK) { - replyToCommand(result, 0); - return; - } - for (uint8_t i = 0; i < count; i++) { - elements[i]->serialize(&storeBuffer, &size, maxSize, - SerializeIF::Endianness::BIG); - } - CommandMessage reply; - ModeSequenceMessage::setModeSequenceMessage(&reply, command, address); - if (commandQueue->reply(&reply) != RETURN_OK) { - IPCStore->deleteData(address); - } -} - -ReturnValue_t Subsystem::checkObjectConnections() { - ReturnValue_t result = RETURN_OK; - for (FixedMap::Iterator iter = modeSequences.begin(); - iter != modeSequences.end(); iter++) { - result = checkSequence(iter.value->first); - if (result != RETURN_OK) { - return result; - } - - } - return RETURN_OK; -} - -void Subsystem::setInitialMode(Mode_t mode) { - initialMode = mode; -} - -void Subsystem::cantKeepMode() { - ReturnValue_t result; - if ((result = checkSequence(getFallbackSequence(mode))) != RETURN_OK) { - triggerEvent(FALLBACK_FAILED, result, getFallbackSequence(mode)); - return; - } - - modeHelper.setForced(true); - - //already set the mode, so that we do not try to go back in our old mode when the transition fails - mode = getFallbackSequence(mode); - //SHOULDDO: We should store submodes for fallback sequence as well, otherwise we should get rid of submodes completely. - startTransition(mode, SUBMODE_NONE); -} +#include "../health/HealthMessage.h" +#include "../objectmanager/ObjectManagerIF.h" +#include "../serialize/SerialArrayListAdapter.h" +#include "../serialize/SerialFixedArrayListAdapter.h" +#include "../serialize/SerializeElement.h" +#include "../serialize/SerialLinkedListAdapter.h" +#include "../subsystem/Subsystem.h" +#include + +Subsystem::Subsystem(object_id_t setObjectId, object_id_t parent, + uint32_t maxNumberOfSequences, uint32_t maxNumberOfTables) : + SubsystemBase(setObjectId, parent, 0), isInTransition(false), childrenChangedHealth( + false), uptimeStartTable(0), currentTargetTable(), targetMode( + 0), targetSubmode(SUBMODE_NONE), initialMode(0), currentSequenceIterator(), modeTables( + maxNumberOfTables), modeSequences(maxNumberOfSequences), IPCStore( + NULL) +#ifdef USE_MODESTORE +,modeStore(NULL) +#endif +{ + +} + +Subsystem::~Subsystem() { + //Auto-generated destructor stub +} + +ReturnValue_t Subsystem::checkSequence(HybridIterator iter, + Mode_t fallbackSequence) { + + //only check for existence, checking the fallback would lead to a (possibly infinite) recursion. + //the fallback sequence will be checked when it is needed. + if (!existsModeSequence(fallbackSequence)) { + return FALLBACK_SEQUENCE_DOES_NOT_EXIST; + } + + if (iter.value == NULL) { + return NO_TARGET_TABLE; + } + + for (; iter.value != NULL; ++iter) { + if (!existsModeTable(iter->getTableId())) { + return TABLE_DOES_NOT_EXIST; + } else { + ReturnValue_t result = checkTable(getTable(iter->getTableId())); + if (result != RETURN_OK) { + return result; + } + } + } + return RETURN_OK; +} + +ReturnValue_t Subsystem::checkSequence(Mode_t sequence) { + if (!existsModeSequence(sequence)) { + return SEQUENCE_DOES_NOT_EXIST; + } + HybridIterator iter = getSequence(sequence); + return checkSequence(iter, getFallbackSequence(sequence)); +} + +bool Subsystem::existsModeSequence(Mode_t id) { + return modeSequences.exists(id) == RETURN_OK; +} + +bool Subsystem::existsModeTable(Mode_t id) { + return modeTables.exists(id) == RETURN_OK; +} + +HybridIterator Subsystem::getCurrentTable() { + return getTable(currentSequenceIterator->getTableId()); +} + +void Subsystem::performChildOperation() { + if (isInTransition) { + if (commandsOutstanding <= 0) { //all children of the current table were commanded and replied + if (currentSequenceIterator.value == NULL) { //we're through with this sequence + if (checkStateAgainstTable(currentTargetTable, targetSubmode) + == RETURN_OK) { + setMode(targetMode, targetSubmode); + isInTransition = false; + return; + } else { + transitionFailed(TARGET_TABLE_NOT_REACHED, + getSequence(targetMode)->getTableId()); + return; + } + } + if (currentSequenceIterator->checkSuccess()) { + if (checkStateAgainstTable(getCurrentTable(), targetSubmode) + != RETURN_OK) { + transitionFailed(TABLE_CHECK_FAILED, + currentSequenceIterator->getTableId()); + return; + } + } + if (currentSequenceIterator->getWaitSeconds() != 0) { + if (uptimeStartTable == 0) { + Clock::getUptime(&uptimeStartTable); + return; + } else { + uint32_t uptimeNow; + Clock::getUptime(&uptimeNow); + if ((uptimeNow - uptimeStartTable) + < (currentSequenceIterator->getWaitSeconds() * 1000)) { + return; + } + } + } + uptimeStartTable = 0; + //next Table, but only if there is one + if ((++currentSequenceIterator).value != NULL) { //we're through with this sequence + executeTable(getCurrentTable(), targetSubmode); + } + } + } else { + if (childrenChangedHealth) { + triggerEvent(CHILD_CHANGED_HEALTH, 0, 0); + childrenChangedHealth = false; + startTransition(mode, submode); + } else if (childrenChangedMode) { + if (checkStateAgainstTable(currentTargetTable, submode) + != RETURN_OK) { + triggerEvent(CANT_KEEP_MODE, mode, submode); + cantKeepMode(); + } + } + } +} + +HybridIterator Subsystem::getSequence(Mode_t id) { + SequenceInfo *sequenceInfo = modeSequences.findValue(id); + if (sequenceInfo->entries.islinked) { + return HybridIterator( + sequenceInfo->entries.firstLinkedElement); + } else { + return HybridIterator( + sequenceInfo->entries.array->front(), + sequenceInfo->entries.array->back()); + } +} + +HybridIterator Subsystem::getTable(Mode_t id) { + EntryPointer *entry = modeTables.findValue(id); + if (entry->islinked) { + return HybridIterator(entry->firstLinkedElement); + } else { + return HybridIterator(entry->array->front(), + entry->array->back()); + } +} + +ReturnValue_t Subsystem::handleCommandMessage(CommandMessage *message) { + ReturnValue_t result; + switch (message->getCommand()) { + case HealthMessage::HEALTH_INFO: { + HealthState health = HealthMessage::getHealth(message); + if (health != EXTERNAL_CONTROL) { + //Ignore external control, as it has an effect only if the mode changes, + //which is communicated with an additional mode info event. + childrenChangedHealth = true; + } + } + break; + case ModeSequenceMessage::ADD_SEQUENCE: { + FixedArrayList sequence; + const uint8_t *pointer; + size_t sizeRead; + result = IPCStore->getData( + ModeSequenceMessage::getStoreAddress(message), &pointer, + &sizeRead); + if (result == RETURN_OK) { + Mode_t fallbackId; + size_t size = sizeRead; + result = SerializeAdapter::deSerialize(&fallbackId, &pointer, &size, + SerializeIF::Endianness::BIG); + if (result == RETURN_OK) { + result = SerialArrayListAdapter::deSerialize( + &sequence, &pointer, &size, + SerializeIF::Endianness::BIG); + if (result == RETURN_OK) { + result = addSequence(&sequence, + ModeSequenceMessage::getSequenceId(message), + fallbackId); + } + } + IPCStore->deleteData(ModeSequenceMessage::getStoreAddress(message)); + } + replyToCommand(result, 0); + } + break; + case ModeSequenceMessage::ADD_TABLE: { + FixedArrayList table; + const uint8_t *pointer; + size_t sizeRead; + result = IPCStore->getData( + ModeSequenceMessage::getStoreAddress(message), &pointer, + &sizeRead); + if (result == RETURN_OK) { + size_t size = sizeRead; + result = SerialArrayListAdapter::deSerialize(&table, + &pointer, &size, SerializeIF::Endianness::BIG); + if (result == RETURN_OK) { + result = addTable(&table, + ModeSequenceMessage::getSequenceId(message)); + } + IPCStore->deleteData(ModeSequenceMessage::getStoreAddress(message)); + } + replyToCommand(result, 0); + + } + break; + case ModeSequenceMessage::DELETE_SEQUENCE: + if (isInTransition) { + replyToCommand(IN_TRANSITION, 0); + break; + } + result = deleteSequence(ModeSequenceMessage::getSequenceId(message)); + replyToCommand(result, 0); + break; + case ModeSequenceMessage::DELETE_TABLE: + if (isInTransition) { + replyToCommand(IN_TRANSITION, 0); + break; + } + result = deleteTable(ModeSequenceMessage::getTableId(message)); + replyToCommand(result, 0); + break; + case ModeSequenceMessage::LIST_SEQUENCES: { + SerialFixedArrayListAdapter sequences; + FixedMap::Iterator iter; + for (iter = modeSequences.begin(); iter != modeSequences.end(); + ++iter) { + sequences.insert(iter.value->first); + } + SerializeIF *pointer = &sequences; + sendSerializablesAsCommandMessage(ModeSequenceMessage::SEQUENCE_LIST, + &pointer, 1); + } + break; + case ModeSequenceMessage::LIST_TABLES: { + SerialFixedArrayListAdapter tables; + FixedMap::Iterator iter; + for (iter = modeTables.begin(); iter != modeTables.end(); ++iter) { + tables.insert(iter.value->first); + } + SerializeIF *pointer = &tables; + sendSerializablesAsCommandMessage(ModeSequenceMessage::TABLE_LIST, + &pointer, 1); + } + break; + case ModeSequenceMessage::READ_SEQUENCE: { + ReturnValue_t result; + Mode_t sequence = ModeSequenceMessage::getSequenceId(message); + SequenceInfo *sequenceInfo = NULL; + result = modeSequences.find(sequence, &sequenceInfo); + if (result != RETURN_OK) { + replyToCommand(result, 0); + } + + SerializeIF *elements[3]; + SerializeElement sequenceId(sequence); + SerializeElement fallbackSequenceId( + getFallbackSequence(sequence)); + + elements[0] = &sequenceId; + elements[1] = &fallbackSequenceId; + + if (sequenceInfo->entries.islinked) { + SerialLinkedListAdapter list( + sequenceInfo->entries.firstLinkedElement, true); + elements[2] = &list; + sendSerializablesAsCommandMessage(ModeSequenceMessage::SEQUENCE, + elements, 3); + } else { + SerialArrayListAdapter serializableArray( + sequenceInfo->entries.array); + + elements[2] = &serializableArray; + sendSerializablesAsCommandMessage(ModeSequenceMessage::SEQUENCE, + elements, 3); + } + } + break; + case ModeSequenceMessage::READ_TABLE: { + ReturnValue_t result; + Mode_t table = ModeSequenceMessage::getSequenceId(message); + EntryPointer *entry = NULL; + result = modeTables.find(table, &entry); + if (result != RETURN_OK) { + replyToCommand(result, 0); + } + + SerializeIF *elements[2]; + SerializeElement tableId(table); + + elements[0] = &tableId; + + if (entry->islinked) { + SerialLinkedListAdapter list( + entry->firstLinkedElement, true); + elements[1] = &list; + sendSerializablesAsCommandMessage(ModeSequenceMessage::TABLE, + elements, 2); + } else { + SerialArrayListAdapter serializableArray( + entry->array); + elements[1] = &serializableArray; + sendSerializablesAsCommandMessage(ModeSequenceMessage::TABLE, + elements, 2); + } + } + break; + case ModeSequenceMessage::READ_FREE_SEQUENCE_SLOTS: { + uint32_t freeSlots = modeSequences.maxSize() - modeSequences.size(); + CommandMessage reply; + ModeSequenceMessage::setModeSequenceMessage(&reply, + ModeSequenceMessage::FREE_SEQUENCE_SLOTS, freeSlots); + commandQueue->reply(&reply); + } + break; + case ModeSequenceMessage::READ_FREE_TABLE_SLOTS: { + uint32_t free = modeTables.maxSize() - modeTables.size(); + CommandMessage reply; + ModeSequenceMessage::setModeSequenceMessage(&reply, + ModeSequenceMessage::FREE_TABLE_SLOTS, free); + commandQueue->reply(&reply); + } + break; + default: + return RETURN_FAILED; + } + return RETURN_OK; +} + +void Subsystem::replyToCommand(ReturnValue_t status, uint32_t parameter) { + if (status == RETURN_OK) { + CommandMessage reply(CommandMessage::REPLY_COMMAND_OK, 0, 0); + commandQueue->reply(&reply); + } else { + CommandMessage reply(CommandMessage::REPLY_REJECTED, status, 0); + commandQueue->reply(&reply); + } +} + +ReturnValue_t Subsystem::addSequence(ArrayList *sequence, + Mode_t id, Mode_t fallbackSequence, bool inStore, bool preInit) { + + ReturnValue_t result; + + //Before initialize() is called, tables must not be checked as the children are not added yet. + //Sequences added before are checked by initialize() + if (!preInit) { + result = checkSequence( + HybridIterator(sequence->front(), + sequence->back()), fallbackSequence); + if (result != RETURN_OK) { + return result; + } + } + + SequenceInfo info; + + info.fallbackSequence = fallbackSequence; + + info.entries.islinked = inStore; + info.entries.array = sequence; + + result = modeSequences.insert(id, info); + + if (result != RETURN_OK) { + return result; + } + + if (inStore) { +#ifdef USE_MODESTORE + result = modeStore->storeArray(sequence, + &(modeSequences.find(id)->entries.firstLinkedElement)); + if (result != RETURN_OK) { + modeSequences.erase(id); + } +#else + modeSequences.erase(id); + return RETURN_FAILED; +#endif + } + + return result; + +} + +ReturnValue_t Subsystem::addTable(ArrayList *table, Mode_t id, + bool inStore, bool preInit) { + + ReturnValue_t result; + + //Before initialize() is called, tables must not be checked as the children are not added yet. + //Tables added before are checked by initialize() + if (!preInit) { + result = checkTable( + HybridIterator(table->front(), table->back())); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + + EntryPointer pointer; + + pointer.islinked = inStore; + pointer.array = table; + + result = modeTables.insert(id, pointer); + + if (result != RETURN_OK) { + return result; + } + + if (inStore) { +#ifdef USE_MODESTORE + result = modeStore->storeArray(table, + &(modeTables.find(id)->firstLinkedElement)); + if (result != RETURN_OK) { + modeTables.erase(id); + } +#else + modeTables.erase(id); + return RETURN_FAILED; +#endif + } + return result; +} + +ReturnValue_t Subsystem::deleteSequence(Mode_t id) { + + if (isFallbackSequence(id)) { + return IS_FALLBACK_SEQUENCE; + } + + SequenceInfo *sequenceInfo; + ReturnValue_t result; + result = modeSequences.find(id, &sequenceInfo); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if (!sequenceInfo->entries.islinked) { + return ACCESS_DENIED; + } + +#ifdef USE_MODESTORE + modeStore->deleteList(sequenceInfo->entries.firstLinkedElement); +#endif + modeSequences.erase(id); + return RETURN_OK; +} + +ReturnValue_t Subsystem::deleteTable(Mode_t id) { + + if (isTableUsed(id)) { + return TABLE_IN_USE; + } + + EntryPointer *pointer; + ReturnValue_t result; + result = modeTables.find(id, &pointer); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if (!pointer->islinked) { + return ACCESS_DENIED; + } + +#ifdef USE_MODESTORE + modeStore->deleteList(pointer->firstLinkedElement); +#endif + modeSequences.erase(id); + return RETURN_OK; +} + +ReturnValue_t Subsystem::initialize() { + ReturnValue_t result = SubsystemBase::initialize(); + + if (result != RETURN_OK) { + return result; + } + + IPCStore = objectManager->get(objects::IPC_STORE); + if (IPCStore == NULL) { + return RETURN_FAILED; + } + +#ifdef USE_MODESTORE + modeStore = objectManager->get(objects::MODE_STORE); + + if (modeStore == NULL) { + return RETURN_FAILED; + } +#endif + + if ((modeSequences.maxSize() > MAX_NUMBER_OF_TABLES_OR_SEQUENCES) + || (modeTables.maxSize() > MAX_NUMBER_OF_TABLES_OR_SEQUENCES)) { + return TABLE_OR_SEQUENCE_LENGTH_INVALID; + } + + mode = initialMode; + + return RETURN_OK; +} + +MessageQueueId_t Subsystem::getSequenceCommandQueue() const { + return SubsystemBase::getCommandQueue(); +} + +ReturnValue_t Subsystem::checkModeCommand(Mode_t mode, Submode_t submode, + uint32_t *msToReachTheMode) { + //Need to accept all submodes to be able to inherit submodes +// if (submode != SUBMODE_NONE) { +// return INVALID_SUBMODE; +// } + + if (isInTransition && (mode != getFallbackSequence(targetMode))) { + return HasModesIF::IN_TRANSITION; + } else { + return checkSequence(mode); + } +} + +void Subsystem::startTransition(Mode_t sequence, Submode_t submode) { + if (modeHelper.isForced()) { + triggerEvent(FORCING_MODE, sequence, submode); + } else { + triggerEvent(CHANGING_MODE, sequence, submode); + } + targetMode = sequence; + targetSubmode = submode; + isInTransition = true; + commandsOutstanding = 0; + currentSequenceIterator = getSequence(sequence); + + currentTargetTable = getTable(currentSequenceIterator->getTableId()); + + ++currentSequenceIterator; + + if (currentSequenceIterator.value != NULL) { + executeTable(getCurrentTable(), targetSubmode); + } +} + +Mode_t Subsystem::getFallbackSequence(Mode_t sequence) { + for (FixedMap::Iterator iter = modeSequences.begin(); + iter != modeSequences.end(); ++iter) { + if (iter.value->first == sequence) { + return iter->fallbackSequence; + } + } + return -1; +} + +bool Subsystem::isFallbackSequence(Mode_t SequenceId) { + for (FixedMap::Iterator iter = modeSequences.begin(); + iter != modeSequences.end(); iter++) { + if (iter->fallbackSequence == SequenceId) { + return true; + } + } + return false; +} + +bool Subsystem::isTableUsed(Mode_t tableId) { + for (FixedMap::Iterator sequence = + modeSequences.begin(); sequence != modeSequences.end(); + sequence++) { + HybridIterator sequenceIterator = getSequence( + sequence.value->first); + while (sequenceIterator.value != NULL) { + if (sequenceIterator->getTableId() == tableId) { + return true; + } + ++sequenceIterator; + } + } + return false; +} + +void Subsystem::transitionFailed(ReturnValue_t failureCode, + uint32_t parameter) { + triggerEvent(MODE_TRANSITION_FAILED, failureCode, parameter); + if (mode == targetMode) { + //already tried going back to the current mode + //go into fallback mode, also set current mode to fallback mode, so we come here at the next fail + modeHelper.setForced(true); + ReturnValue_t result; + if ((result = checkSequence(getFallbackSequence(mode))) != RETURN_OK) { + triggerEvent(FALLBACK_FAILED, result, getFallbackSequence(mode)); + isInTransition = false; //keep still and allow arbitrary mode commands to recover + return; + } + mode = getFallbackSequence(mode); + startTransition(mode, submode); + } else { + //try to go back to the current mode + startTransition(mode, submode); + } +} + +void Subsystem::sendSerializablesAsCommandMessage(Command_t command, + SerializeIF **elements, uint8_t count) { + ReturnValue_t result; + size_t maxSize = 0; + for (uint8_t i = 0; i < count; i++) { + maxSize += elements[i]->getSerializedSize(); + } + uint8_t *storeBuffer; + store_address_t address; + size_t size = 0; + + result = IPCStore->getFreeElement(&address, maxSize, &storeBuffer); + if (result != HasReturnvaluesIF::RETURN_OK) { + replyToCommand(result, 0); + return; + } + for (uint8_t i = 0; i < count; i++) { + elements[i]->serialize(&storeBuffer, &size, maxSize, + SerializeIF::Endianness::BIG); + } + CommandMessage reply; + ModeSequenceMessage::setModeSequenceMessage(&reply, command, address); + if (commandQueue->reply(&reply) != RETURN_OK) { + IPCStore->deleteData(address); + } +} + +ReturnValue_t Subsystem::checkObjectConnections() { + ReturnValue_t result = RETURN_OK; + for (FixedMap::Iterator iter = modeSequences.begin(); + iter != modeSequences.end(); iter++) { + result = checkSequence(iter.value->first); + if (result != RETURN_OK) { + return result; + } + + } + return RETURN_OK; +} + +void Subsystem::setInitialMode(Mode_t mode) { + initialMode = mode; +} + +void Subsystem::cantKeepMode() { + ReturnValue_t result; + if ((result = checkSequence(getFallbackSequence(mode))) != RETURN_OK) { + triggerEvent(FALLBACK_FAILED, result, getFallbackSequence(mode)); + return; + } + + modeHelper.setForced(true); + + //already set the mode, so that we do not try to go back in our old mode when the transition fails + mode = getFallbackSequence(mode); + //SHOULDDO: We should store submodes for fallback sequence as well, otherwise we should get rid of submodes completely. + startTransition(mode, SUBMODE_NONE); +} diff --git a/subsystem/Subsystem.h b/subsystem/Subsystem.h index ca1020b9..b296a2e8 100644 --- a/subsystem/Subsystem.h +++ b/subsystem/Subsystem.h @@ -1,164 +1,164 @@ -#ifndef SUBSYSTEM_H_ -#define SUBSYSTEM_H_ - -#include -#include -#include -#include -#include -#include -#include - -class Subsystem: public SubsystemBase, public HasModeSequenceIF { -public: - static const uint8_t INTERFACE_ID = CLASS_ID::SUBSYSTEM; - static const ReturnValue_t SEQUENCE_ALREADY_EXISTS = MAKE_RETURN_CODE(0x01); - static const ReturnValue_t TABLE_ALREADY_EXISTS = MAKE_RETURN_CODE(0x02); - static const ReturnValue_t TABLE_DOES_NOT_EXIST = MAKE_RETURN_CODE(0x03); - static const ReturnValue_t TABLE_OR_SEQUENCE_LENGTH_INVALID = MAKE_RETURN_CODE(0x04); - static const ReturnValue_t SEQUENCE_DOES_NOT_EXIST = MAKE_RETURN_CODE(0x05); - static const ReturnValue_t TABLE_CONTAINS_INVALID_OBJECT_ID = - MAKE_RETURN_CODE(0x06); - static const ReturnValue_t FALLBACK_SEQUENCE_DOES_NOT_EXIST = - MAKE_RETURN_CODE(0x07); - static const ReturnValue_t NO_TARGET_TABLE = MAKE_RETURN_CODE(0x08); - static const ReturnValue_t SEQUENCE_OR_TABLE_TOO_LONG = MAKE_RETURN_CODE(0x09); - static const ReturnValue_t IS_FALLBACK_SEQUENCE = MAKE_RETURN_CODE(0x0B); - static const ReturnValue_t ACCESS_DENIED = MAKE_RETURN_CODE(0x0C); - static const ReturnValue_t TABLE_IN_USE = MAKE_RETURN_CODE(0x0E); - - static const ReturnValue_t TARGET_TABLE_NOT_REACHED = MAKE_RETURN_CODE(0xA1); - static const ReturnValue_t TABLE_CHECK_FAILED = MAKE_RETURN_CODE(0xA2); - - - - Subsystem(object_id_t setObjectId, object_id_t parent, - uint32_t maxNumberOfSequences, uint32_t maxNumberOfTables); - virtual ~Subsystem(); - - ReturnValue_t addSequence(ArrayList* sequence, Mode_t id, - Mode_t fallbackSequence, bool inStore = true, bool preInit = true); - - ReturnValue_t addTable(ArrayList *table, Mode_t id, - bool inStore = true, bool preInit = true); - - void setInitialMode(Mode_t mode); - - virtual ReturnValue_t initialize(); - - virtual ReturnValue_t checkObjectConnections(); - - virtual MessageQueueId_t getSequenceCommandQueue() const; - - /** - * - * - * IMPORTANT: Do not call on non existing sequence! Use existsSequence() first - * - * @param sequence - * @return - */ - ReturnValue_t checkSequence(Mode_t sequence); - - /** - * - * - * IMPORTANT: Do not call on non existing sequence! Use existsSequence() first - * - * @param iter - * @return - */ - ReturnValue_t checkSequence(HybridIterator iter, Mode_t fallbackSequence); -protected: - - struct EntryPointer { - bool islinked; - union { - ModeListEntry *firstLinkedElement; - ArrayList *array; - }; - }; - - struct SequenceInfo { - Mode_t fallbackSequence; - EntryPointer entries; - }; - - static const uint8_t MAX_NUMBER_OF_TABLES_OR_SEQUENCES = 70; - - static const uint8_t MAX_LENGTH_OF_TABLE_OR_SEQUENCE = 20; - - bool isInTransition; - - bool childrenChangedHealth; - - uint32_t uptimeStartTable; - - HybridIterator currentTargetTable; - - Mode_t targetMode; - - Submode_t targetSubmode; - - Mode_t initialMode; - - HybridIterator currentSequenceIterator; - - FixedMap modeTables; - - FixedMap modeSequences; - - StorageManagerIF *IPCStore; - -#ifdef USE_MODESTORE - ModeStoreIF *modeStore; -#endif - - bool existsModeSequence(Mode_t id); - - HybridIterator getSequence(Mode_t id); - - bool existsModeTable(Mode_t id); - - HybridIterator getTable(Mode_t id); - - HybridIterator getCurrentTable(); - -// void startSequence(Mode_t sequence); - - /** - * DO NOT USE ON NON EXISTING SEQUENCE - * - * @param a sequence - * @return the fallback sequence's Id - */ - Mode_t getFallbackSequence(Mode_t sequence); - - void replyToCommand(ReturnValue_t status, uint32_t parameter); - - ReturnValue_t deleteSequence(Mode_t id); - - ReturnValue_t deleteTable(Mode_t id); - - virtual void performChildOperation(); - - virtual ReturnValue_t handleCommandMessage(CommandMessage *message); - - bool isFallbackSequence(Mode_t SequenceId); - - bool isTableUsed(Mode_t tableId); - - virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, - uint32_t *msToReachTheMode); - - virtual void startTransition(Mode_t mode, Submode_t submode); - - void sendSerializablesAsCommandMessage(Command_t command, SerializeIF **elements, uint8_t count); - - void transitionFailed(ReturnValue_t failureCode, uint32_t parameter); - - void cantKeepMode(); - -}; - -#endif /* SUBSYSTEM_H_ */ +#ifndef SUBSYSTEM_H_ +#define SUBSYSTEM_H_ + +#include "../container/FixedArrayList.h" +#include "../container/FixedMap.h" +#include "../container/HybridIterator.h" +#include "../container/SinglyLinkedList.h" +#include "../serialize/SerialArrayListAdapter.h" +#include "../subsystem/modes/ModeDefinitions.h" +#include "../subsystem/SubsystemBase.h" + +class Subsystem: public SubsystemBase, public HasModeSequenceIF { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::SUBSYSTEM; + static const ReturnValue_t SEQUENCE_ALREADY_EXISTS = MAKE_RETURN_CODE(0x01); + static const ReturnValue_t TABLE_ALREADY_EXISTS = MAKE_RETURN_CODE(0x02); + static const ReturnValue_t TABLE_DOES_NOT_EXIST = MAKE_RETURN_CODE(0x03); + static const ReturnValue_t TABLE_OR_SEQUENCE_LENGTH_INVALID = MAKE_RETURN_CODE(0x04); + static const ReturnValue_t SEQUENCE_DOES_NOT_EXIST = MAKE_RETURN_CODE(0x05); + static const ReturnValue_t TABLE_CONTAINS_INVALID_OBJECT_ID = + MAKE_RETURN_CODE(0x06); + static const ReturnValue_t FALLBACK_SEQUENCE_DOES_NOT_EXIST = + MAKE_RETURN_CODE(0x07); + static const ReturnValue_t NO_TARGET_TABLE = MAKE_RETURN_CODE(0x08); + static const ReturnValue_t SEQUENCE_OR_TABLE_TOO_LONG = MAKE_RETURN_CODE(0x09); + static const ReturnValue_t IS_FALLBACK_SEQUENCE = MAKE_RETURN_CODE(0x0B); + static const ReturnValue_t ACCESS_DENIED = MAKE_RETURN_CODE(0x0C); + static const ReturnValue_t TABLE_IN_USE = MAKE_RETURN_CODE(0x0E); + + static const ReturnValue_t TARGET_TABLE_NOT_REACHED = MAKE_RETURN_CODE(0xA1); + static const ReturnValue_t TABLE_CHECK_FAILED = MAKE_RETURN_CODE(0xA2); + + + + Subsystem(object_id_t setObjectId, object_id_t parent, + uint32_t maxNumberOfSequences, uint32_t maxNumberOfTables); + virtual ~Subsystem(); + + ReturnValue_t addSequence(ArrayList* sequence, Mode_t id, + Mode_t fallbackSequence, bool inStore = true, bool preInit = true); + + ReturnValue_t addTable(ArrayList *table, Mode_t id, + bool inStore = true, bool preInit = true); + + void setInitialMode(Mode_t mode); + + virtual ReturnValue_t initialize(); + + virtual ReturnValue_t checkObjectConnections(); + + virtual MessageQueueId_t getSequenceCommandQueue() const; + + /** + * + * + * IMPORTANT: Do not call on non existing sequence! Use existsSequence() first + * + * @param sequence + * @return + */ + ReturnValue_t checkSequence(Mode_t sequence); + + /** + * + * + * IMPORTANT: Do not call on non existing sequence! Use existsSequence() first + * + * @param iter + * @return + */ + ReturnValue_t checkSequence(HybridIterator iter, Mode_t fallbackSequence); +protected: + + struct EntryPointer { + bool islinked; + union { + ModeListEntry *firstLinkedElement; + ArrayList *array; + }; + }; + + struct SequenceInfo { + Mode_t fallbackSequence; + EntryPointer entries; + }; + + static const uint8_t MAX_NUMBER_OF_TABLES_OR_SEQUENCES = 70; + + static const uint8_t MAX_LENGTH_OF_TABLE_OR_SEQUENCE = 20; + + bool isInTransition; + + bool childrenChangedHealth; + + uint32_t uptimeStartTable; + + HybridIterator currentTargetTable; + + Mode_t targetMode; + + Submode_t targetSubmode; + + Mode_t initialMode; + + HybridIterator currentSequenceIterator; + + FixedMap modeTables; + + FixedMap modeSequences; + + StorageManagerIF *IPCStore; + +#ifdef USE_MODESTORE + ModeStoreIF *modeStore; +#endif + + bool existsModeSequence(Mode_t id); + + HybridIterator getSequence(Mode_t id); + + bool existsModeTable(Mode_t id); + + HybridIterator getTable(Mode_t id); + + HybridIterator getCurrentTable(); + +// void startSequence(Mode_t sequence); + + /** + * DO NOT USE ON NON EXISTING SEQUENCE + * + * @param a sequence + * @return the fallback sequence's Id + */ + Mode_t getFallbackSequence(Mode_t sequence); + + void replyToCommand(ReturnValue_t status, uint32_t parameter); + + ReturnValue_t deleteSequence(Mode_t id); + + ReturnValue_t deleteTable(Mode_t id); + + virtual void performChildOperation(); + + virtual ReturnValue_t handleCommandMessage(CommandMessage *message); + + bool isFallbackSequence(Mode_t SequenceId); + + bool isTableUsed(Mode_t tableId); + + virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, + uint32_t *msToReachTheMode); + + virtual void startTransition(Mode_t mode, Submode_t submode); + + void sendSerializablesAsCommandMessage(Command_t command, SerializeIF **elements, uint8_t count); + + void transitionFailed(ReturnValue_t failureCode, uint32_t parameter); + + void cantKeepMode(); + +}; + +#endif /* SUBSYSTEM_H_ */ diff --git a/subsystem/SubsystemBase.cpp b/subsystem/SubsystemBase.cpp index 71fa81b7..2bd6c1ad 100644 --- a/subsystem/SubsystemBase.cpp +++ b/subsystem/SubsystemBase.cpp @@ -1,356 +1,356 @@ -#include -#include -#include -#include - -SubsystemBase::SubsystemBase(object_id_t setObjectId, object_id_t parent, - Mode_t initialMode, uint16_t commandQueueDepth) : - SystemObject(setObjectId), mode(initialMode), submode(SUBMODE_NONE), - childrenChangedMode(false), commandsOutstanding(0), commandQueue(NULL), - healthHelper(this, setObjectId), modeHelper(this), parentId(parent) { - commandQueue = QueueFactory::instance()->createMessageQueue(commandQueueDepth, - MessageQueueMessage::MAX_MESSAGE_SIZE); -} - -SubsystemBase::~SubsystemBase() { - QueueFactory::instance()->deleteMessageQueue(commandQueue); - -} - -ReturnValue_t SubsystemBase::registerChild(object_id_t objectId) { - ChildInfo info; - - HasModesIF *child = objectManager->get(objectId); - //This is a rather ugly hack to have the changedHealth info for all children available. (needed for FOGs). - HasHealthIF* healthChild = objectManager->get(objectId); - if (child == nullptr) { - if (healthChild == nullptr) { - return CHILD_DOESNT_HAVE_MODES; - } else { - info.commandQueue = healthChild->getCommandQueue(); - info.mode = MODE_OFF; - } - } else { - info.commandQueue = child->getCommandQueue(); - info.mode = -1; //intentional to force an initial command during system startup - } - - info.submode = SUBMODE_NONE; - info.healthChanged = false; - - std::pair::iterator, bool> returnValue = - childrenMap.insert( - std::pair(objectId, info)); - if (!(returnValue.second)) { - return COULD_NOT_INSERT_CHILD; - } else { - return RETURN_OK; - } -} - -ReturnValue_t SubsystemBase::checkStateAgainstTable( - HybridIterator tableIter, Submode_t targetSubmode) { - - std::map::iterator childIter; - - for (; tableIter.value != NULL; ++tableIter) { - object_id_t object = tableIter.value->getObject(); - - if ((childIter = childrenMap.find(object)) == childrenMap.end()) { - return RETURN_FAILED; - } - - if (childIter->second.mode != tableIter.value->getMode()) { - return RETURN_FAILED; - } - - Submode_t submodeToCheckAgainst = tableIter.value->getSubmode(); - if (tableIter.value->inheritSubmode()) { - submodeToCheckAgainst = targetSubmode; - } - - if (childIter->second.submode != submodeToCheckAgainst) { - return RETURN_FAILED; - } - } - return RETURN_OK; -} - -void SubsystemBase::executeTable(HybridIterator tableIter, - Submode_t targetSubmode) { - CommandMessage command; - - std::map::iterator iter; - - commandsOutstanding = 0; - - for (; tableIter.value != nullptr; ++tableIter) { - object_id_t object = tableIter.value->getObject(); - if ((iter = childrenMap.find(object)) == childrenMap.end()) { - //illegal table entry, should only happen due to misconfigured mode table - sif::debug << std::hex << getObjectId() << ": invalid mode table entry" - << std::endl; - continue; - } - - Submode_t submodeToCommand = tableIter.value->getSubmode(); - if (tableIter.value->inheritSubmode()) { - submodeToCommand = targetSubmode; - } - - if (healthHelper.healthTable->hasHealth(object)) { - if (healthHelper.healthTable->isFaulty(object)) { - ModeMessage::setModeMessage(&command, - ModeMessage::CMD_MODE_COMMAND, HasModesIF::MODE_OFF, - SUBMODE_NONE); - } else { - if (modeHelper.isForced()) { - ModeMessage::setModeMessage(&command, - ModeMessage::CMD_MODE_COMMAND_FORCED, - tableIter.value->getMode(), submodeToCommand); - } else { - if (healthHelper.healthTable->isCommandable(object)) { - ModeMessage::setModeMessage(&command, - ModeMessage::CMD_MODE_COMMAND, - tableIter.value->getMode(), submodeToCommand); - } else { - continue; - } - } - } - } else { - ModeMessage::setModeMessage(&command, ModeMessage::CMD_MODE_COMMAND, - tableIter.value->getMode(), submodeToCommand); - } - - if ((iter->second.mode == ModeMessage::getMode(&command)) - && (iter->second.submode == ModeMessage::getSubmode(&command)) - && !modeHelper.isForced()) { - continue; //don't send redundant mode commands (produces event spam), but still command if mode is forced to reach lower levels - } - ReturnValue_t result = commandQueue->sendMessage( - iter->second.commandQueue, &command); - if (result == RETURN_OK) { - ++commandsOutstanding; - } - } - -} - -ReturnValue_t SubsystemBase::updateChildMode(MessageQueueId_t queue, - Mode_t mode, Submode_t submode) { - std::map::iterator iter; - - for (iter = childrenMap.begin(); iter != childrenMap.end(); iter++) { - if (iter->second.commandQueue == queue) { - iter->second.mode = mode; - iter->second.submode = submode; - return RETURN_OK; - } - } - return CHILD_NOT_FOUND; -} - -ReturnValue_t SubsystemBase::updateChildChangedHealth(MessageQueueId_t queue, -bool changedHealth) { - for (auto iter = childrenMap.begin(); iter != childrenMap.end(); iter++) { - if (iter->second.commandQueue == queue) { - iter->second.healthChanged = changedHealth; - return RETURN_OK; - } - } - return CHILD_NOT_FOUND; -} - -MessageQueueId_t SubsystemBase::getCommandQueue() const { - return commandQueue->getId(); -} - -ReturnValue_t SubsystemBase::initialize() { - MessageQueueId_t parentQueue = 0; - ReturnValue_t result = SystemObject::initialize(); - - if (result != RETURN_OK) { - return result; - } - - if (parentId != 0) { - SubsystemBase *parent = objectManager->get(parentId); - if (parent == NULL) { - return RETURN_FAILED; - } - parentQueue = parent->getCommandQueue(); - - parent->registerChild(getObjectId()); - } - - result = healthHelper.initialize(parentQueue); - - if (result != RETURN_OK) { - return result; - } - - result = modeHelper.initialize(parentQueue); - - if (result != RETURN_OK) { - return result; - } - - return RETURN_OK; -} - -ReturnValue_t SubsystemBase::performOperation(uint8_t opCode) { - - childrenChangedMode = false; - - checkCommandQueue(); - - performChildOperation(); - - return RETURN_OK; -} - -ReturnValue_t SubsystemBase::handleModeReply(CommandMessage* message) { - switch (message->getCommand()) { - case ModeMessage::REPLY_MODE_INFO: - updateChildMode(message->getSender(), ModeMessage::getMode(message), - ModeMessage::getSubmode(message)); - childrenChangedMode = true; - return RETURN_OK; - case ModeMessage::REPLY_MODE_REPLY: - case ModeMessage::REPLY_WRONG_MODE_REPLY: - updateChildMode(message->getSender(), ModeMessage::getMode(message), - ModeMessage::getSubmode(message)); - childrenChangedMode = true; - commandsOutstanding--; - return RETURN_OK; - case ModeMessage::REPLY_CANT_REACH_MODE: - commandsOutstanding--; - { - for (auto iter = childrenMap.begin(); iter != childrenMap.end(); - iter++) { - if (iter->second.commandQueue == message->getSender()) { - triggerEvent(MODE_CMD_REJECTED, iter->first, - message->getParameter()); - } - } - } - return RETURN_OK; -// case ModeMessage::CMD_MODE_COMMAND: -// handleCommandedMode(message); -// return RETURN_OK; -// case ModeMessage::CMD_MODE_ANNOUNCE: -// triggerEvent(MODE_INFO, mode, submode); -// return RETURN_OK; -// case ModeMessage::CMD_MODE_ANNOUNCE_RECURSIVELY: -// triggerEvent(MODE_INFO, mode, submode); -// commandAllChildren(message); -// return RETURN_OK; - default: - return RETURN_FAILED; - } -} - -ReturnValue_t SubsystemBase::checkTable( - HybridIterator tableIter) { - for (; tableIter.value != NULL; ++tableIter) { - if (childrenMap.find(tableIter.value->getObject()) - == childrenMap.end()) { - return TABLE_CONTAINS_INVALID_OBJECT_ID; - } - } - return RETURN_OK; -} - -void SubsystemBase::replyToCommand(CommandMessage* message) { - commandQueue->reply(message); -} - -void SubsystemBase::setMode(Mode_t newMode, Submode_t newSubmode) { - modeHelper.modeChanged(newMode, newSubmode); - mode = newMode; - submode = newSubmode; - modeChanged(); - announceMode(false); -} - -void SubsystemBase::setMode(Mode_t newMode) { - setMode(newMode, submode); -} - -void SubsystemBase::commandAllChildren(CommandMessage* message) { - std::map::iterator iter; - for (iter = childrenMap.begin(); iter != childrenMap.end(); ++iter) { - commandQueue->sendMessage(iter->second.commandQueue, message); - } -} - -void SubsystemBase::getMode(Mode_t* mode, Submode_t* submode) { - *mode = this->mode; - *submode = this->submode; -} - -void SubsystemBase::setToExternalControl() { - healthHelper.setHealth(EXTERNAL_CONTROL); -} - -void SubsystemBase::announceMode(bool recursive) { - triggerEvent(MODE_INFO, mode, submode); - if (recursive) { - CommandMessage command; - ModeMessage::setModeMessage(&command, - ModeMessage::CMD_MODE_ANNOUNCE_RECURSIVELY, 0, 0); - commandAllChildren(&command); - } -} - -void SubsystemBase::checkCommandQueue() { - ReturnValue_t result; - CommandMessage command; - - for (result = commandQueue->receiveMessage(&command); result == RETURN_OK; - result = commandQueue->receiveMessage(&command)) { - - result = healthHelper.handleHealthCommand(&command); - if (result == RETURN_OK) { - continue; - } - - result = modeHelper.handleModeCommand(&command); - if (result == RETURN_OK) { - continue; - } - - result = handleModeReply(&command); - if (result == RETURN_OK) { - continue; - } - - result = handleCommandMessage(&command); - if (result != RETURN_OK) { - CommandMessage reply; - reply.setReplyRejected(CommandMessage::UNKNOWN_COMMAND, - command.getCommand()); - replyToCommand(&reply); - } - } -} - -ReturnValue_t SubsystemBase::setHealth(HealthState health) { - switch (health) { - case HEALTHY: - case EXTERNAL_CONTROL: - healthHelper.setHealth(health); - return RETURN_OK; - default: - return INVALID_HEALTH_STATE; - } -} - -HasHealthIF::HealthState SubsystemBase::getHealth() { - return healthHelper.getHealth(); -} - -void SubsystemBase::modeChanged() { -} - +#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../subsystem/SubsystemBase.h" +#include "../ipc/QueueFactory.h" + +SubsystemBase::SubsystemBase(object_id_t setObjectId, object_id_t parent, + Mode_t initialMode, uint16_t commandQueueDepth) : + SystemObject(setObjectId), mode(initialMode), submode(SUBMODE_NONE), + childrenChangedMode(false), commandsOutstanding(0), commandQueue(NULL), + healthHelper(this, setObjectId), modeHelper(this), parentId(parent) { + commandQueue = QueueFactory::instance()->createMessageQueue(commandQueueDepth, + MessageQueueMessage::MAX_MESSAGE_SIZE); +} + +SubsystemBase::~SubsystemBase() { + QueueFactory::instance()->deleteMessageQueue(commandQueue); + +} + +ReturnValue_t SubsystemBase::registerChild(object_id_t objectId) { + ChildInfo info; + + HasModesIF *child = objectManager->get(objectId); + //This is a rather ugly hack to have the changedHealth info for all children available. (needed for FOGs). + HasHealthIF* healthChild = objectManager->get(objectId); + if (child == nullptr) { + if (healthChild == nullptr) { + return CHILD_DOESNT_HAVE_MODES; + } else { + info.commandQueue = healthChild->getCommandQueue(); + info.mode = MODE_OFF; + } + } else { + info.commandQueue = child->getCommandQueue(); + info.mode = -1; //intentional to force an initial command during system startup + } + + info.submode = SUBMODE_NONE; + info.healthChanged = false; + + std::pair::iterator, bool> returnValue = + childrenMap.insert( + std::pair(objectId, info)); + if (!(returnValue.second)) { + return COULD_NOT_INSERT_CHILD; + } else { + return RETURN_OK; + } +} + +ReturnValue_t SubsystemBase::checkStateAgainstTable( + HybridIterator tableIter, Submode_t targetSubmode) { + + std::map::iterator childIter; + + for (; tableIter.value != NULL; ++tableIter) { + object_id_t object = tableIter.value->getObject(); + + if ((childIter = childrenMap.find(object)) == childrenMap.end()) { + return RETURN_FAILED; + } + + if (childIter->second.mode != tableIter.value->getMode()) { + return RETURN_FAILED; + } + + Submode_t submodeToCheckAgainst = tableIter.value->getSubmode(); + if (tableIter.value->inheritSubmode()) { + submodeToCheckAgainst = targetSubmode; + } + + if (childIter->second.submode != submodeToCheckAgainst) { + return RETURN_FAILED; + } + } + return RETURN_OK; +} + +void SubsystemBase::executeTable(HybridIterator tableIter, + Submode_t targetSubmode) { + CommandMessage command; + + std::map::iterator iter; + + commandsOutstanding = 0; + + for (; tableIter.value != nullptr; ++tableIter) { + object_id_t object = tableIter.value->getObject(); + if ((iter = childrenMap.find(object)) == childrenMap.end()) { + //illegal table entry, should only happen due to misconfigured mode table + sif::debug << std::hex << getObjectId() << ": invalid mode table entry" + << std::endl; + continue; + } + + Submode_t submodeToCommand = tableIter.value->getSubmode(); + if (tableIter.value->inheritSubmode()) { + submodeToCommand = targetSubmode; + } + + if (healthHelper.healthTable->hasHealth(object)) { + if (healthHelper.healthTable->isFaulty(object)) { + ModeMessage::setModeMessage(&command, + ModeMessage::CMD_MODE_COMMAND, HasModesIF::MODE_OFF, + SUBMODE_NONE); + } else { + if (modeHelper.isForced()) { + ModeMessage::setModeMessage(&command, + ModeMessage::CMD_MODE_COMMAND_FORCED, + tableIter.value->getMode(), submodeToCommand); + } else { + if (healthHelper.healthTable->isCommandable(object)) { + ModeMessage::setModeMessage(&command, + ModeMessage::CMD_MODE_COMMAND, + tableIter.value->getMode(), submodeToCommand); + } else { + continue; + } + } + } + } else { + ModeMessage::setModeMessage(&command, ModeMessage::CMD_MODE_COMMAND, + tableIter.value->getMode(), submodeToCommand); + } + + if ((iter->second.mode == ModeMessage::getMode(&command)) + && (iter->second.submode == ModeMessage::getSubmode(&command)) + && !modeHelper.isForced()) { + continue; //don't send redundant mode commands (produces event spam), but still command if mode is forced to reach lower levels + } + ReturnValue_t result = commandQueue->sendMessage( + iter->second.commandQueue, &command); + if (result == RETURN_OK) { + ++commandsOutstanding; + } + } + +} + +ReturnValue_t SubsystemBase::updateChildMode(MessageQueueId_t queue, + Mode_t mode, Submode_t submode) { + std::map::iterator iter; + + for (iter = childrenMap.begin(); iter != childrenMap.end(); iter++) { + if (iter->second.commandQueue == queue) { + iter->second.mode = mode; + iter->second.submode = submode; + return RETURN_OK; + } + } + return CHILD_NOT_FOUND; +} + +ReturnValue_t SubsystemBase::updateChildChangedHealth(MessageQueueId_t queue, +bool changedHealth) { + for (auto iter = childrenMap.begin(); iter != childrenMap.end(); iter++) { + if (iter->second.commandQueue == queue) { + iter->second.healthChanged = changedHealth; + return RETURN_OK; + } + } + return CHILD_NOT_FOUND; +} + +MessageQueueId_t SubsystemBase::getCommandQueue() const { + return commandQueue->getId(); +} + +ReturnValue_t SubsystemBase::initialize() { + MessageQueueId_t parentQueue = 0; + ReturnValue_t result = SystemObject::initialize(); + + if (result != RETURN_OK) { + return result; + } + + if (parentId != 0) { + SubsystemBase *parent = objectManager->get(parentId); + if (parent == NULL) { + return RETURN_FAILED; + } + parentQueue = parent->getCommandQueue(); + + parent->registerChild(getObjectId()); + } + + result = healthHelper.initialize(parentQueue); + + if (result != RETURN_OK) { + return result; + } + + result = modeHelper.initialize(parentQueue); + + if (result != RETURN_OK) { + return result; + } + + return RETURN_OK; +} + +ReturnValue_t SubsystemBase::performOperation(uint8_t opCode) { + + childrenChangedMode = false; + + checkCommandQueue(); + + performChildOperation(); + + return RETURN_OK; +} + +ReturnValue_t SubsystemBase::handleModeReply(CommandMessage* message) { + switch (message->getCommand()) { + case ModeMessage::REPLY_MODE_INFO: + updateChildMode(message->getSender(), ModeMessage::getMode(message), + ModeMessage::getSubmode(message)); + childrenChangedMode = true; + return RETURN_OK; + case ModeMessage::REPLY_MODE_REPLY: + case ModeMessage::REPLY_WRONG_MODE_REPLY: + updateChildMode(message->getSender(), ModeMessage::getMode(message), + ModeMessage::getSubmode(message)); + childrenChangedMode = true; + commandsOutstanding--; + return RETURN_OK; + case ModeMessage::REPLY_CANT_REACH_MODE: + commandsOutstanding--; + { + for (auto iter = childrenMap.begin(); iter != childrenMap.end(); + iter++) { + if (iter->second.commandQueue == message->getSender()) { + triggerEvent(MODE_CMD_REJECTED, iter->first, + message->getParameter()); + } + } + } + return RETURN_OK; +// case ModeMessage::CMD_MODE_COMMAND: +// handleCommandedMode(message); +// return RETURN_OK; +// case ModeMessage::CMD_MODE_ANNOUNCE: +// triggerEvent(MODE_INFO, mode, submode); +// return RETURN_OK; +// case ModeMessage::CMD_MODE_ANNOUNCE_RECURSIVELY: +// triggerEvent(MODE_INFO, mode, submode); +// commandAllChildren(message); +// return RETURN_OK; + default: + return RETURN_FAILED; + } +} + +ReturnValue_t SubsystemBase::checkTable( + HybridIterator tableIter) { + for (; tableIter.value != NULL; ++tableIter) { + if (childrenMap.find(tableIter.value->getObject()) + == childrenMap.end()) { + return TABLE_CONTAINS_INVALID_OBJECT_ID; + } + } + return RETURN_OK; +} + +void SubsystemBase::replyToCommand(CommandMessage* message) { + commandQueue->reply(message); +} + +void SubsystemBase::setMode(Mode_t newMode, Submode_t newSubmode) { + modeHelper.modeChanged(newMode, newSubmode); + mode = newMode; + submode = newSubmode; + modeChanged(); + announceMode(false); +} + +void SubsystemBase::setMode(Mode_t newMode) { + setMode(newMode, submode); +} + +void SubsystemBase::commandAllChildren(CommandMessage* message) { + std::map::iterator iter; + for (iter = childrenMap.begin(); iter != childrenMap.end(); ++iter) { + commandQueue->sendMessage(iter->second.commandQueue, message); + } +} + +void SubsystemBase::getMode(Mode_t* mode, Submode_t* submode) { + *mode = this->mode; + *submode = this->submode; +} + +void SubsystemBase::setToExternalControl() { + healthHelper.setHealth(EXTERNAL_CONTROL); +} + +void SubsystemBase::announceMode(bool recursive) { + triggerEvent(MODE_INFO, mode, submode); + if (recursive) { + CommandMessage command; + ModeMessage::setModeMessage(&command, + ModeMessage::CMD_MODE_ANNOUNCE_RECURSIVELY, 0, 0); + commandAllChildren(&command); + } +} + +void SubsystemBase::checkCommandQueue() { + ReturnValue_t result; + CommandMessage command; + + for (result = commandQueue->receiveMessage(&command); result == RETURN_OK; + result = commandQueue->receiveMessage(&command)) { + + result = healthHelper.handleHealthCommand(&command); + if (result == RETURN_OK) { + continue; + } + + result = modeHelper.handleModeCommand(&command); + if (result == RETURN_OK) { + continue; + } + + result = handleModeReply(&command); + if (result == RETURN_OK) { + continue; + } + + result = handleCommandMessage(&command); + if (result != RETURN_OK) { + CommandMessage reply; + reply.setReplyRejected(CommandMessage::UNKNOWN_COMMAND, + command.getCommand()); + replyToCommand(&reply); + } + } +} + +ReturnValue_t SubsystemBase::setHealth(HealthState health) { + switch (health) { + case HEALTHY: + case EXTERNAL_CONTROL: + healthHelper.setHealth(health); + return RETURN_OK; + default: + return INVALID_HEALTH_STATE; + } +} + +HasHealthIF::HealthState SubsystemBase::getHealth() { + return healthHelper.getHealth(); +} + +void SubsystemBase::modeChanged() { +} + diff --git a/subsystem/SubsystemBase.h b/subsystem/SubsystemBase.h index 1a050a9a..c0abbe40 100644 --- a/subsystem/SubsystemBase.h +++ b/subsystem/SubsystemBase.h @@ -1,129 +1,129 @@ -#ifndef SUBSYSTEMBASE_H_ -#define SUBSYSTEMBASE_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** - * @defgroup subsystems Subsystem Objects - * Contains all Subsystem and Assemblies - */ -class SubsystemBase: public SystemObject, - public HasModesIF, - public HasHealthIF, - public HasReturnvaluesIF, - public ExecutableObjectIF { -public: - static const uint8_t INTERFACE_ID = CLASS_ID::SUBSYSTEM_BASE; - static const ReturnValue_t CHILD_NOT_FOUND = MAKE_RETURN_CODE(0x01); - static const ReturnValue_t CHILD_INFO_UPDATED = MAKE_RETURN_CODE(0x02); - static const ReturnValue_t CHILD_DOESNT_HAVE_MODES = MAKE_RETURN_CODE(0x03); - static const ReturnValue_t COULD_NOT_INSERT_CHILD = MAKE_RETURN_CODE(0x04); - static const ReturnValue_t TABLE_CONTAINS_INVALID_OBJECT_ID = - MAKE_RETURN_CODE(0x05); - - SubsystemBase(object_id_t setObjectId, object_id_t parent, - Mode_t initialMode = 0, uint16_t commandQueueDepth = 8); - virtual ~SubsystemBase(); - - virtual MessageQueueId_t getCommandQueue() const; - - ReturnValue_t registerChild(object_id_t objectId); - - virtual ReturnValue_t initialize(); - - virtual ReturnValue_t performOperation(uint8_t opCode); - - virtual ReturnValue_t setHealth(HealthState health); - - virtual HasHealthIF::HealthState getHealth(); - -protected: - struct ChildInfo { - MessageQueueId_t commandQueue; - Mode_t mode; - Submode_t submode;bool healthChanged; - }; - - Mode_t mode; - - Submode_t submode; - - bool childrenChangedMode; - - /** - * Always check this against <=0, so you are robust against too many replies - */ - int32_t commandsOutstanding; - - MessageQueueIF* commandQueue; - - HealthHelper healthHelper; - - ModeHelper modeHelper; - - const object_id_t parentId; - - typedef std::map ChildrenMap; - ChildrenMap childrenMap; - - void checkCommandQueue(); - - /** - * We need to know the target Submode, as children are able to inherit the submode - */ - ReturnValue_t checkStateAgainstTable( - HybridIterator tableIter, Submode_t targetSubmode); - - /** - * We need to know the target Submode, as children are able to inherit the submode - * Still, we have a default for all child implementations which do not use submode inheritance - */ - void executeTable(HybridIterator tableIter, - Submode_t targetSubmode = SUBMODE_NONE); - - ReturnValue_t updateChildMode(MessageQueueId_t queue, Mode_t mode, - Submode_t submode); - - ReturnValue_t updateChildChangedHealth(MessageQueueId_t queue, - bool changedHealth = true); - - virtual ReturnValue_t handleModeReply(CommandMessage *message); - - void commandAllChildren(CommandMessage *message); - - ReturnValue_t checkTable(HybridIterator tableIter); - - void replyToCommand(CommandMessage *message); - - void setMode(Mode_t newMode, Submode_t newSubmode); - - void setMode(Mode_t newMode); - - virtual ReturnValue_t handleCommandMessage(CommandMessage *message) = 0; - - virtual void performChildOperation() = 0; - - virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, - uint32_t *msToReachTheMode) = 0; - - virtual void startTransition(Mode_t mode, Submode_t submode) = 0; - - virtual void getMode(Mode_t *mode, Submode_t *submode); - - virtual void setToExternalControl(); - - virtual void announceMode(bool recursive); - - virtual void modeChanged(); -}; - -#endif /* SUBSYSTEMBASE_H_ */ +#ifndef SUBSYSTEMBASE_H_ +#define SUBSYSTEMBASE_H_ + +#include "../container/HybridIterator.h" +#include "../health/HasHealthIF.h" +#include "../health/HealthHelper.h" +#include "../modes/HasModesIF.h" +#include "../objectmanager/SystemObject.h" +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../subsystem/modes/HasModeSequenceIF.h" +#include "../tasks/ExecutableObjectIF.h" +#include "../ipc/MessageQueueIF.h" +#include + +/** + * @defgroup subsystems Subsystem Objects + * Contains all Subsystem and Assemblies + */ +class SubsystemBase: public SystemObject, + public HasModesIF, + public HasHealthIF, + public HasReturnvaluesIF, + public ExecutableObjectIF { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::SUBSYSTEM_BASE; + static const ReturnValue_t CHILD_NOT_FOUND = MAKE_RETURN_CODE(0x01); + static const ReturnValue_t CHILD_INFO_UPDATED = MAKE_RETURN_CODE(0x02); + static const ReturnValue_t CHILD_DOESNT_HAVE_MODES = MAKE_RETURN_CODE(0x03); + static const ReturnValue_t COULD_NOT_INSERT_CHILD = MAKE_RETURN_CODE(0x04); + static const ReturnValue_t TABLE_CONTAINS_INVALID_OBJECT_ID = + MAKE_RETURN_CODE(0x05); + + SubsystemBase(object_id_t setObjectId, object_id_t parent, + Mode_t initialMode = 0, uint16_t commandQueueDepth = 8); + virtual ~SubsystemBase(); + + virtual MessageQueueId_t getCommandQueue() const; + + ReturnValue_t registerChild(object_id_t objectId); + + virtual ReturnValue_t initialize(); + + virtual ReturnValue_t performOperation(uint8_t opCode); + + virtual ReturnValue_t setHealth(HealthState health); + + virtual HasHealthIF::HealthState getHealth(); + +protected: + struct ChildInfo { + MessageQueueId_t commandQueue; + Mode_t mode; + Submode_t submode;bool healthChanged; + }; + + Mode_t mode; + + Submode_t submode; + + bool childrenChangedMode; + + /** + * Always check this against <=0, so you are robust against too many replies + */ + int32_t commandsOutstanding; + + MessageQueueIF* commandQueue; + + HealthHelper healthHelper; + + ModeHelper modeHelper; + + const object_id_t parentId; + + typedef std::map ChildrenMap; + ChildrenMap childrenMap; + + void checkCommandQueue(); + + /** + * We need to know the target Submode, as children are able to inherit the submode + */ + ReturnValue_t checkStateAgainstTable( + HybridIterator tableIter, Submode_t targetSubmode); + + /** + * We need to know the target Submode, as children are able to inherit the submode + * Still, we have a default for all child implementations which do not use submode inheritance + */ + void executeTable(HybridIterator tableIter, + Submode_t targetSubmode = SUBMODE_NONE); + + ReturnValue_t updateChildMode(MessageQueueId_t queue, Mode_t mode, + Submode_t submode); + + ReturnValue_t updateChildChangedHealth(MessageQueueId_t queue, + bool changedHealth = true); + + virtual ReturnValue_t handleModeReply(CommandMessage *message); + + void commandAllChildren(CommandMessage *message); + + ReturnValue_t checkTable(HybridIterator tableIter); + + void replyToCommand(CommandMessage *message); + + void setMode(Mode_t newMode, Submode_t newSubmode); + + void setMode(Mode_t newMode); + + virtual ReturnValue_t handleCommandMessage(CommandMessage *message) = 0; + + virtual void performChildOperation() = 0; + + virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, + uint32_t *msToReachTheMode) = 0; + + virtual void startTransition(Mode_t mode, Submode_t submode) = 0; + + virtual void getMode(Mode_t *mode, Submode_t *submode); + + virtual void setToExternalControl(); + + virtual void announceMode(bool recursive); + + virtual void modeChanged(); +}; + +#endif /* SUBSYSTEMBASE_H_ */ diff --git a/subsystem/modes/HasModeSequenceIF.h b/subsystem/modes/HasModeSequenceIF.h index e03de410..90007d80 100644 --- a/subsystem/modes/HasModeSequenceIF.h +++ b/subsystem/modes/HasModeSequenceIF.h @@ -1,20 +1,20 @@ -#ifndef HASMODESEQUENCEIF_H_ -#define HASMODESEQUENCEIF_H_ - -#include -#include -#include - - -class HasModeSequenceIF { -public: - virtual ~HasModeSequenceIF() { - - } - - virtual MessageQueueId_t getSequenceCommandQueue() const = 0; - -}; - - -#endif /* HASMODESEQUENCEIF_H_ */ +#ifndef HASMODESEQUENCEIF_H_ +#define HASMODESEQUENCEIF_H_ + +#include "../../subsystem/modes/ModeDefinitions.h" +#include "../../subsystem/modes/ModeSequenceMessage.h" +#include "../../subsystem/modes/ModeStoreIF.h" + + +class HasModeSequenceIF { +public: + virtual ~HasModeSequenceIF() { + + } + + virtual MessageQueueId_t getSequenceCommandQueue() const = 0; + +}; + + +#endif /* HASMODESEQUENCEIF_H_ */ diff --git a/subsystem/modes/ModeDefinitions.h b/subsystem/modes/ModeDefinitions.h index 153710af..0514b357 100644 --- a/subsystem/modes/ModeDefinitions.h +++ b/subsystem/modes/ModeDefinitions.h @@ -1,152 +1,152 @@ -#ifndef MODEDEFINITIONS_H_ -#define MODEDEFINITIONS_H_ - -#include -#include -#include -#include -class ModeListEntry: public SerializeIF, public LinkedElement { -public: - ModeListEntry() : - LinkedElement(this), value1(0), value2(0), value3(0), value4( - 0) { - - } - - uint32_t value1; - uint32_t value2; - uint8_t value3; - uint8_t value4; - - virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) const { - - ReturnValue_t result; - - result = SerializeAdapter::serialize(&value1, buffer, size, - maxSize, streamEndianness); - - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - result = SerializeAdapter::serialize(&value2, buffer, size, - maxSize, streamEndianness); - - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - result = SerializeAdapter::serialize(&value3, buffer, size, - maxSize, streamEndianness); - - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - result = SerializeAdapter::serialize(&value4, buffer, size, - maxSize, streamEndianness); - - return result; - - } - - virtual size_t getSerializedSize() const { - return sizeof(value1) + sizeof(value2) + sizeof(value3) + sizeof(value4); - } - - virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - Endianness streamEndianness) { - ReturnValue_t result; - - result = SerializeAdapter::deSerialize(&value1, buffer, size, - streamEndianness); - - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - result = SerializeAdapter::deSerialize(&value2, buffer, size, - streamEndianness); - - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - result = SerializeAdapter::deSerialize(&value3, buffer, size, - streamEndianness); - - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - result = SerializeAdapter::deSerialize(&value4, buffer, size, - streamEndianness); - - return result; - } - - //for Sequences - Mode_t getTableId() const { - return value1; - } - - void setTableId(Mode_t tableId) { - this->value1 = tableId; - } - - uint8_t getWaitSeconds() const { - return value2; - } - - void setWaitSeconds(uint8_t waitSeconds) { - this->value2 = waitSeconds; - } - - bool checkSuccess() const { - return value3 == 1; - } - - void setCheckSuccess(bool checkSuccess) { - this->value3 = checkSuccess; - } - - //for Tables - object_id_t getObject() const { - return value1; - } - - void setObject(object_id_t object) { - this->value1 = object; - } - - Mode_t getMode() const { - return value2; - } - - void setMode(Mode_t mode) { - this->value2 = mode; - } - - Submode_t getSubmode() const { - return value3; - } - - void setSubmode(Submode_t submode) { - this->value3 = submode; - } - - bool inheritSubmode() const { - return value4 == 1; - } - - void setInheritSubmode(bool inherit){ - if (inherit){ - value4 = 1; - } else { - value4 = 0; - } - } - - bool operator==(ModeListEntry other) { - return ((value1 == other.value1) && (value2 == other.value2) - && (value3 == other.value3)); - } -}; - -#endif //MODEDEFINITIONS_H_ +#ifndef MODEDEFINITIONS_H_ +#define MODEDEFINITIONS_H_ + +#include "../../modes/HasModesIF.h" +#include "../../objectmanager/SystemObjectIF.h" +#include "../../serialize/SerializeIF.h" +#include "../../serialize/SerialLinkedListAdapter.h" +class ModeListEntry: public SerializeIF, public LinkedElement { +public: + ModeListEntry() : + LinkedElement(this), value1(0), value2(0), value3(0), value4( + 0) { + + } + + uint32_t value1; + uint32_t value2; + uint8_t value3; + uint8_t value4; + + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + size_t maxSize, Endianness streamEndianness) const { + + ReturnValue_t result; + + result = SerializeAdapter::serialize(&value1, buffer, size, + maxSize, streamEndianness); + + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = SerializeAdapter::serialize(&value2, buffer, size, + maxSize, streamEndianness); + + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = SerializeAdapter::serialize(&value3, buffer, size, + maxSize, streamEndianness); + + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + result = SerializeAdapter::serialize(&value4, buffer, size, + maxSize, streamEndianness); + + return result; + + } + + virtual size_t getSerializedSize() const { + return sizeof(value1) + sizeof(value2) + sizeof(value3) + sizeof(value4); + } + + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + Endianness streamEndianness) { + ReturnValue_t result; + + result = SerializeAdapter::deSerialize(&value1, buffer, size, + streamEndianness); + + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = SerializeAdapter::deSerialize(&value2, buffer, size, + streamEndianness); + + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = SerializeAdapter::deSerialize(&value3, buffer, size, + streamEndianness); + + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = SerializeAdapter::deSerialize(&value4, buffer, size, + streamEndianness); + + return result; + } + + //for Sequences + Mode_t getTableId() const { + return value1; + } + + void setTableId(Mode_t tableId) { + this->value1 = tableId; + } + + uint8_t getWaitSeconds() const { + return value2; + } + + void setWaitSeconds(uint8_t waitSeconds) { + this->value2 = waitSeconds; + } + + bool checkSuccess() const { + return value3 == 1; + } + + void setCheckSuccess(bool checkSuccess) { + this->value3 = checkSuccess; + } + + //for Tables + object_id_t getObject() const { + return value1; + } + + void setObject(object_id_t object) { + this->value1 = object; + } + + Mode_t getMode() const { + return value2; + } + + void setMode(Mode_t mode) { + this->value2 = mode; + } + + Submode_t getSubmode() const { + return value3; + } + + void setSubmode(Submode_t submode) { + this->value3 = submode; + } + + bool inheritSubmode() const { + return value4 == 1; + } + + void setInheritSubmode(bool inherit){ + if (inherit){ + value4 = 1; + } else { + value4 = 0; + } + } + + bool operator==(ModeListEntry other) { + return ((value1 == other.value1) && (value2 == other.value2) + && (value3 == other.value3)); + } +}; + +#endif //MODEDEFINITIONS_H_ diff --git a/subsystem/modes/ModeSequenceMessage.cpp b/subsystem/modes/ModeSequenceMessage.cpp index 31661739..3eb4ebe8 100644 --- a/subsystem/modes/ModeSequenceMessage.cpp +++ b/subsystem/modes/ModeSequenceMessage.cpp @@ -1,89 +1,89 @@ -#include -#include -#include -#include -#include - -void ModeSequenceMessage::setModeSequenceMessage(CommandMessage* message, - Command_t command, Mode_t sequence, store_address_t storeAddress) { - message->setCommand(command); - message->setParameter(storeAddress.raw); - message->setParameter2(sequence); -} - -//void ModeSequenceMessage::setModeSequenceMessage(CommandMessage* message, -// Command_t command, ModeTableId_t table, store_address_t storeAddress) { -// message->setCommand(command); -// message->setParameter(storeAddress.raw); -// message->setParameter2(table); -//} - -void ModeSequenceMessage::setModeSequenceMessage(CommandMessage* message, - Command_t command, Mode_t sequence) { - message->setCommand(command); - message->setParameter2(sequence); -} - -//void ModeSequenceMessage::setModeSequenceMessage(CommandMessage* message, -// Command_t command, ModeTableId_t table) { -// message->setCommand(command); -// message->setParameter2(table); -//} - -void ModeSequenceMessage::setModeSequenceMessage(CommandMessage* message, - Command_t command, store_address_t storeAddress) { - message->setCommand(command); - message->setParameter(storeAddress.raw); -} - -store_address_t ModeSequenceMessage::getStoreAddress( - const CommandMessage* message) { - store_address_t address; - address.raw = message->getParameter(); - return address; -} - -Mode_t ModeSequenceMessage::getSequenceId(const CommandMessage* message) { - return message->getParameter2(); -} - -Mode_t ModeSequenceMessage::getTableId(const CommandMessage* message) { - return message->getParameter2(); -} - - -uint32_t ModeSequenceMessage::getNumber(const CommandMessage* message) { - return message->getParameter2(); -} - -void ModeSequenceMessage::clear(CommandMessage *message) { - switch (message->getCommand()) { - case ADD_SEQUENCE: - case ADD_TABLE: - case SEQUENCE_LIST: - case TABLE_LIST: - case TABLE: - case SEQUENCE:{ - StorageManagerIF *ipcStore = objectManager->get(objects::IPC_STORE); - if (ipcStore != NULL){ - ipcStore->deleteData(ModeSequenceMessage::getStoreAddress(message)); - } - } - /* NO BREAK falls through*/ - case DELETE_SEQUENCE: - case DELETE_TABLE: - case READ_SEQUENCE: - case READ_TABLE: - case LIST_SEQUENCES: - case LIST_TABLES: - case READ_FREE_SEQUENCE_SLOTS: - case FREE_SEQUENCE_SLOTS: - case READ_FREE_TABLE_SLOTS: - case FREE_TABLE_SLOTS: - default: - message->setCommand(CommandMessage::CMD_NONE); - message->setParameter(0); - message->setParameter2(0); - break; - } -} +#include "../../objectmanager/ObjectManagerIF.h" +#include "../../objectmanager/ObjectManagerIF.h" +#include "../../objectmanager/ObjectManagerIF.h" +#include "../../storagemanager/StorageManagerIF.h" +#include "../../subsystem/modes/ModeSequenceMessage.h" + +void ModeSequenceMessage::setModeSequenceMessage(CommandMessage* message, + Command_t command, Mode_t sequence, store_address_t storeAddress) { + message->setCommand(command); + message->setParameter(storeAddress.raw); + message->setParameter2(sequence); +} + +//void ModeSequenceMessage::setModeSequenceMessage(CommandMessage* message, +// Command_t command, ModeTableId_t table, store_address_t storeAddress) { +// message->setCommand(command); +// message->setParameter(storeAddress.raw); +// message->setParameter2(table); +//} + +void ModeSequenceMessage::setModeSequenceMessage(CommandMessage* message, + Command_t command, Mode_t sequence) { + message->setCommand(command); + message->setParameter2(sequence); +} + +//void ModeSequenceMessage::setModeSequenceMessage(CommandMessage* message, +// Command_t command, ModeTableId_t table) { +// message->setCommand(command); +// message->setParameter2(table); +//} + +void ModeSequenceMessage::setModeSequenceMessage(CommandMessage* message, + Command_t command, store_address_t storeAddress) { + message->setCommand(command); + message->setParameter(storeAddress.raw); +} + +store_address_t ModeSequenceMessage::getStoreAddress( + const CommandMessage* message) { + store_address_t address; + address.raw = message->getParameter(); + return address; +} + +Mode_t ModeSequenceMessage::getSequenceId(const CommandMessage* message) { + return message->getParameter2(); +} + +Mode_t ModeSequenceMessage::getTableId(const CommandMessage* message) { + return message->getParameter2(); +} + + +uint32_t ModeSequenceMessage::getNumber(const CommandMessage* message) { + return message->getParameter2(); +} + +void ModeSequenceMessage::clear(CommandMessage *message) { + switch (message->getCommand()) { + case ADD_SEQUENCE: + case ADD_TABLE: + case SEQUENCE_LIST: + case TABLE_LIST: + case TABLE: + case SEQUENCE:{ + StorageManagerIF *ipcStore = objectManager->get(objects::IPC_STORE); + if (ipcStore != NULL){ + ipcStore->deleteData(ModeSequenceMessage::getStoreAddress(message)); + } + } + /* NO BREAK falls through*/ + case DELETE_SEQUENCE: + case DELETE_TABLE: + case READ_SEQUENCE: + case READ_TABLE: + case LIST_SEQUENCES: + case LIST_TABLES: + case READ_FREE_SEQUENCE_SLOTS: + case FREE_SEQUENCE_SLOTS: + case READ_FREE_TABLE_SLOTS: + case FREE_TABLE_SLOTS: + default: + message->setCommand(CommandMessage::CMD_NONE); + message->setParameter(0); + message->setParameter2(0); + break; + } +} diff --git a/subsystem/modes/ModeSequenceMessage.h b/subsystem/modes/ModeSequenceMessage.h index 61d1b628..fcb5b2e7 100644 --- a/subsystem/modes/ModeSequenceMessage.h +++ b/subsystem/modes/ModeSequenceMessage.h @@ -1,48 +1,48 @@ -#ifndef MODESEQUENCEMESSAGE_H_ -#define MODESEQUENCEMESSAGE_H_ - -#include -#include -#include - -class ModeSequenceMessage { -public: - static const uint8_t MESSAGE_ID = messagetypes::MODE_SEQUENCE; - - static const Command_t ADD_SEQUENCE = MAKE_COMMAND_ID(0x01); - static const Command_t ADD_TABLE = MAKE_COMMAND_ID(0x02); - static const Command_t DELETE_SEQUENCE = MAKE_COMMAND_ID(0x03); - static const Command_t DELETE_TABLE = MAKE_COMMAND_ID(0x04); - static const Command_t READ_SEQUENCE = MAKE_COMMAND_ID(0x05); - static const Command_t READ_TABLE = MAKE_COMMAND_ID(0x06); - static const Command_t LIST_SEQUENCES = MAKE_COMMAND_ID(0x07); - static const Command_t LIST_TABLES = MAKE_COMMAND_ID(0x08); - static const Command_t SEQUENCE_LIST = MAKE_COMMAND_ID(0x09); - static const Command_t TABLE_LIST = MAKE_COMMAND_ID(0x0A); - static const Command_t TABLE = MAKE_COMMAND_ID(0x0B); - static const Command_t SEQUENCE = MAKE_COMMAND_ID(0x0C); - static const Command_t READ_FREE_SEQUENCE_SLOTS = MAKE_COMMAND_ID(0x0D); - static const Command_t FREE_SEQUENCE_SLOTS = MAKE_COMMAND_ID(0x0E); - static const Command_t READ_FREE_TABLE_SLOTS = MAKE_COMMAND_ID(0x0F); - static const Command_t FREE_TABLE_SLOTS = MAKE_COMMAND_ID(0x10); - - static void setModeSequenceMessage(CommandMessage *message, - Command_t command, Mode_t sequenceOrTable, - store_address_t storeAddress); - static void setModeSequenceMessage(CommandMessage *message, - Command_t command, Mode_t sequenceOrTable); - static void setModeSequenceMessage(CommandMessage *message, - Command_t command, store_address_t storeAddress); - - static store_address_t getStoreAddress(const CommandMessage *message); - static Mode_t getSequenceId(const CommandMessage *message); - static Mode_t getTableId(const CommandMessage *message); - static uint32_t getNumber(const CommandMessage *message); - - static void clear(CommandMessage *message); - -private: - ModeSequenceMessage(); -}; - -#endif /* MODESEQUENCEMESSAGE_H_ */ +#ifndef MODESEQUENCEMESSAGE_H_ +#define MODESEQUENCEMESSAGE_H_ + +#include "../../ipc/CommandMessage.h" +#include "../../storagemanager/StorageManagerIF.h" +#include "../../subsystem/modes/ModeDefinitions.h" + +class ModeSequenceMessage { +public: + static const uint8_t MESSAGE_ID = messagetypes::MODE_SEQUENCE; + + static const Command_t ADD_SEQUENCE = MAKE_COMMAND_ID(0x01); + static const Command_t ADD_TABLE = MAKE_COMMAND_ID(0x02); + static const Command_t DELETE_SEQUENCE = MAKE_COMMAND_ID(0x03); + static const Command_t DELETE_TABLE = MAKE_COMMAND_ID(0x04); + static const Command_t READ_SEQUENCE = MAKE_COMMAND_ID(0x05); + static const Command_t READ_TABLE = MAKE_COMMAND_ID(0x06); + static const Command_t LIST_SEQUENCES = MAKE_COMMAND_ID(0x07); + static const Command_t LIST_TABLES = MAKE_COMMAND_ID(0x08); + static const Command_t SEQUENCE_LIST = MAKE_COMMAND_ID(0x09); + static const Command_t TABLE_LIST = MAKE_COMMAND_ID(0x0A); + static const Command_t TABLE = MAKE_COMMAND_ID(0x0B); + static const Command_t SEQUENCE = MAKE_COMMAND_ID(0x0C); + static const Command_t READ_FREE_SEQUENCE_SLOTS = MAKE_COMMAND_ID(0x0D); + static const Command_t FREE_SEQUENCE_SLOTS = MAKE_COMMAND_ID(0x0E); + static const Command_t READ_FREE_TABLE_SLOTS = MAKE_COMMAND_ID(0x0F); + static const Command_t FREE_TABLE_SLOTS = MAKE_COMMAND_ID(0x10); + + static void setModeSequenceMessage(CommandMessage *message, + Command_t command, Mode_t sequenceOrTable, + store_address_t storeAddress); + static void setModeSequenceMessage(CommandMessage *message, + Command_t command, Mode_t sequenceOrTable); + static void setModeSequenceMessage(CommandMessage *message, + Command_t command, store_address_t storeAddress); + + static store_address_t getStoreAddress(const CommandMessage *message); + static Mode_t getSequenceId(const CommandMessage *message); + static Mode_t getTableId(const CommandMessage *message); + static uint32_t getNumber(const CommandMessage *message); + + static void clear(CommandMessage *message); + +private: + ModeSequenceMessage(); +}; + +#endif /* MODESEQUENCEMESSAGE_H_ */ diff --git a/subsystem/modes/ModeStore.cpp b/subsystem/modes/ModeStore.cpp index 2aa02087..409a5f0f 100644 --- a/subsystem/modes/ModeStore.cpp +++ b/subsystem/modes/ModeStore.cpp @@ -1,126 +1,126 @@ -#include - -#ifdef USE_MODESTORE - -ModeStore::ModeStore(object_id_t objectId, uint32_t slots) : - SystemObject(objectId), store(slots), emptySlot(store.front()) { - mutex = MutexFactory::instance()->createMutex();; - OSAL::createMutex(objectId + 1, mutex); - clear(); -} - -ModeStore::~ModeStore() { - delete mutex; -} - -uint32_t ModeStore::getFreeSlots() { - OSAL::lockMutex(mutex, OSAL::NO_TIMEOUT); - uint32_t count = 0; - ArrayList::Iterator iter; - for (iter = store.begin(); iter != store.end(); ++iter) { - if (iter->getNext() == emptySlot) { - ++count; - } - } - OSAL::unlockMutex(mutex); - return count; -} - -ReturnValue_t ModeStore::storeArray(ArrayList* sequence, - ModeListEntry** storedFirstEntry) { - if (sequence->size == 0) { - return CANT_STORE_EMPTY; - } - OSAL::lockMutex(mutex, OSAL::NO_TIMEOUT); - *storedFirstEntry = findEmptySlotNoLock(store.front()); - - ModeListEntry* pointer = - *storedFirstEntry; - pointer->setNext(pointer); - - ArrayList::Iterator iter; - for (iter = sequence->begin(); iter != sequence->end(); ++iter) { - //SHOULDDO: I need to check this in detail. What is the idea? Why does it not work? - pointer = pointer->getNext()->value; - if (pointer == NULL) { - deleteListNoLock(*storedFirstEntry); - OSAL::unlockMutex(mutex); - return TOO_MANY_ELEMENTS; - } - pointer->value->value1 = iter->value1; - pointer->value->value2 = iter->value2; - pointer->value->value3 = iter->value3; - pointer->setNext(findEmptySlotNoLock(pointer + 1)); - } - pointer->setNext(NULL); - OSAL::unlockMutex(mutex); - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t ModeStore::deleteList(ModeListEntry* sequence) { - ReturnValue_t result = isValidEntry(sequence); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - OSAL::lockMutex(mutex, OSAL::NO_TIMEOUT); - deleteListNoLock(sequence); - OSAL::unlockMutex(mutex); - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t ModeStore::readList(ModeListEntry* sequence, - ArrayList* into) { - ReturnValue_t result = isValidEntry(sequence); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - OSAL::lockMutex(mutex, OSAL::NO_TIMEOUT); - result = into->insert(*sequence->value); - while ((result == HasReturnvaluesIF::RETURN_OK) && (sequence->getNext() != NULL)) { - result = into->insert(*sequence->value); - sequence = sequence->getNext()->value; - } - OSAL::unlockMutex(mutex); - return result; -} - -void ModeStore::clear() { - OSAL::lockMutex(mutex, OSAL::NO_TIMEOUT); - store.size = store.maxSize(); - ArrayList::Iterator iter; - for (iter = store.begin(); iter != store.end(); ++iter) { - iter->setNext(emptySlot); - } - OSAL::unlockMutex(mutex); -} - -ModeListEntry* ModeStore::findEmptySlotNoLock(ModeListEntry* startFrom) { - ArrayList::Iterator iter( - startFrom); - for (; iter != store.end(); ++iter) { - if (iter.value->getNext() == emptySlot) { - OSAL::unlockMutex(mutex); - return iter.value; - } - } - return NULL; -} - -void ModeStore::deleteListNoLock(ModeListEntry* sequence) { - ModeListEntry* next = sequence; - while (next != NULL) { - next = sequence->getNext()->value; - sequence->setNext(emptySlot); - sequence = next; - } -} - -ReturnValue_t ModeStore::isValidEntry(ModeListEntry* sequence) { - if ((sequence < store.front()) || (sequence > store.back()) - || sequence->getNext() == emptySlot) { - return INVALID_ENTRY; - } - return HasReturnvaluesIF::RETURN_OK; -} - -#endif +#include "../../subsystem/modes/ModeStore.h" + +#ifdef USE_MODESTORE + +ModeStore::ModeStore(object_id_t objectId, uint32_t slots) : + SystemObject(objectId), store(slots), emptySlot(store.front()) { + mutex = MutexFactory::instance()->createMutex();; + OSAL::createMutex(objectId + 1, mutex); + clear(); +} + +ModeStore::~ModeStore() { + delete mutex; +} + +uint32_t ModeStore::getFreeSlots() { + OSAL::lockMutex(mutex, OSAL::NO_TIMEOUT); + uint32_t count = 0; + ArrayList::Iterator iter; + for (iter = store.begin(); iter != store.end(); ++iter) { + if (iter->getNext() == emptySlot) { + ++count; + } + } + OSAL::unlockMutex(mutex); + return count; +} + +ReturnValue_t ModeStore::storeArray(ArrayList* sequence, + ModeListEntry** storedFirstEntry) { + if (sequence->size == 0) { + return CANT_STORE_EMPTY; + } + OSAL::lockMutex(mutex, OSAL::NO_TIMEOUT); + *storedFirstEntry = findEmptySlotNoLock(store.front()); + + ModeListEntry* pointer = + *storedFirstEntry; + pointer->setNext(pointer); + + ArrayList::Iterator iter; + for (iter = sequence->begin(); iter != sequence->end(); ++iter) { + //SHOULDDO: I need to check this in detail. What is the idea? Why does it not work? + pointer = pointer->getNext()->value; + if (pointer == NULL) { + deleteListNoLock(*storedFirstEntry); + OSAL::unlockMutex(mutex); + return TOO_MANY_ELEMENTS; + } + pointer->value->value1 = iter->value1; + pointer->value->value2 = iter->value2; + pointer->value->value3 = iter->value3; + pointer->setNext(findEmptySlotNoLock(pointer + 1)); + } + pointer->setNext(NULL); + OSAL::unlockMutex(mutex); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t ModeStore::deleteList(ModeListEntry* sequence) { + ReturnValue_t result = isValidEntry(sequence); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + OSAL::lockMutex(mutex, OSAL::NO_TIMEOUT); + deleteListNoLock(sequence); + OSAL::unlockMutex(mutex); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t ModeStore::readList(ModeListEntry* sequence, + ArrayList* into) { + ReturnValue_t result = isValidEntry(sequence); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + OSAL::lockMutex(mutex, OSAL::NO_TIMEOUT); + result = into->insert(*sequence->value); + while ((result == HasReturnvaluesIF::RETURN_OK) && (sequence->getNext() != NULL)) { + result = into->insert(*sequence->value); + sequence = sequence->getNext()->value; + } + OSAL::unlockMutex(mutex); + return result; +} + +void ModeStore::clear() { + OSAL::lockMutex(mutex, OSAL::NO_TIMEOUT); + store.size = store.maxSize(); + ArrayList::Iterator iter; + for (iter = store.begin(); iter != store.end(); ++iter) { + iter->setNext(emptySlot); + } + OSAL::unlockMutex(mutex); +} + +ModeListEntry* ModeStore::findEmptySlotNoLock(ModeListEntry* startFrom) { + ArrayList::Iterator iter( + startFrom); + for (; iter != store.end(); ++iter) { + if (iter.value->getNext() == emptySlot) { + OSAL::unlockMutex(mutex); + return iter.value; + } + } + return NULL; +} + +void ModeStore::deleteListNoLock(ModeListEntry* sequence) { + ModeListEntry* next = sequence; + while (next != NULL) { + next = sequence->getNext()->value; + sequence->setNext(emptySlot); + sequence = next; + } +} + +ReturnValue_t ModeStore::isValidEntry(ModeListEntry* sequence) { + if ((sequence < store.front()) || (sequence > store.back()) + || sequence->getNext() == emptySlot) { + return INVALID_ENTRY; + } + return HasReturnvaluesIF::RETURN_OK; +} + +#endif diff --git a/subsystem/modes/ModeStore.h b/subsystem/modes/ModeStore.h index cbc45b5a..cb340443 100644 --- a/subsystem/modes/ModeStore.h +++ b/subsystem/modes/ModeStore.h @@ -1,45 +1,45 @@ -#ifndef MODESTORE_H_ -#define MODESTORE_H_ - -#ifdef USE_MODESTORE - -#include -#include -#include -#include - -class ModeStore: public ModeStoreIF, public SystemObject { -public: - ModeStore(object_id_t objectId, uint32_t slots); - virtual ~ModeStore(); - - virtual ReturnValue_t storeArray(ArrayList *sequence, - ModeListEntry **storedFirstEntry); - - virtual ReturnValue_t deleteList( - ModeListEntry *sequence); - - virtual ReturnValue_t readList( - ModeListEntry *sequence, - ArrayList *into); - - virtual uint32_t getFreeSlots(); - -private: - MutexId_t* mutex; - ArrayList store; - ModeListEntry *emptySlot; - - void clear(); - ModeListEntry* findEmptySlotNoLock( - ModeListEntry* startFrom); - void deleteListNoLock( - ModeListEntry *sequence); - - ReturnValue_t isValidEntry(ModeListEntry *sequence); -}; - -#endif - -#endif /* MODESTORE_H_ */ - +#ifndef MODESTORE_H_ +#define MODESTORE_H_ + +#ifdef USE_MODESTORE + +#include "../../container/ArrayList.h" +#include "../../container/SinglyLinkedList.h" +#include "../../objectmanager/SystemObject.h" +#include "../../subsystem/modes/ModeStoreIF.h" + +class ModeStore: public ModeStoreIF, public SystemObject { +public: + ModeStore(object_id_t objectId, uint32_t slots); + virtual ~ModeStore(); + + virtual ReturnValue_t storeArray(ArrayList *sequence, + ModeListEntry **storedFirstEntry); + + virtual ReturnValue_t deleteList( + ModeListEntry *sequence); + + virtual ReturnValue_t readList( + ModeListEntry *sequence, + ArrayList *into); + + virtual uint32_t getFreeSlots(); + +private: + MutexId_t* mutex; + ArrayList store; + ModeListEntry *emptySlot; + + void clear(); + ModeListEntry* findEmptySlotNoLock( + ModeListEntry* startFrom); + void deleteListNoLock( + ModeListEntry *sequence); + + ReturnValue_t isValidEntry(ModeListEntry *sequence); +}; + +#endif + +#endif /* MODESTORE_H_ */ + diff --git a/subsystem/modes/ModeStoreIF.h b/subsystem/modes/ModeStoreIF.h index 7be7a5a7..b9f2df70 100644 --- a/subsystem/modes/ModeStoreIF.h +++ b/subsystem/modes/ModeStoreIF.h @@ -1,37 +1,37 @@ -#ifndef MODESTOREIF_H_ -#define MODESTOREIF_H_ - -#ifdef USE_MODESTORE - -#include -#include -#include -#include - -class ModeStoreIF { -public: - static const uint8_t INTERFACE_ID = CLASS_ID::MODE_STORE_IF; - static const ReturnValue_t INVALID_ENTRY = MAKE_RETURN_CODE(0x02); - static const ReturnValue_t TOO_MANY_ELEMENTS = MAKE_RETURN_CODE(0x03); - static const ReturnValue_t CANT_STORE_EMPTY = MAKE_RETURN_CODE(0x04); - - virtual ~ModeStoreIF() { - - } - - virtual ReturnValue_t storeArray(ArrayList *sequence, - ModeListEntry **storedFirstEntry) = 0; - - virtual ReturnValue_t deleteList( - ModeListEntry *sequence) = 0; - - virtual ReturnValue_t readList( - ModeListEntry *sequence, - ArrayList *into) = 0; - - virtual uint32_t getFreeSlots() = 0; -}; - -#endif - -#endif /* MODESTOREIF_H_ */ +#ifndef MODESTOREIF_H_ +#define MODESTOREIF_H_ + +#ifdef USE_MODESTORE + +#include "../../container/ArrayList.h" +#include "../../container/SinglyLinkedList.h" +#include "../../returnvalues/HasReturnvaluesIF.h" +#include "../../subsystem/modes/ModeDefinitions.h" + +class ModeStoreIF { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::MODE_STORE_IF; + static const ReturnValue_t INVALID_ENTRY = MAKE_RETURN_CODE(0x02); + static const ReturnValue_t TOO_MANY_ELEMENTS = MAKE_RETURN_CODE(0x03); + static const ReturnValue_t CANT_STORE_EMPTY = MAKE_RETURN_CODE(0x04); + + virtual ~ModeStoreIF() { + + } + + virtual ReturnValue_t storeArray(ArrayList *sequence, + ModeListEntry **storedFirstEntry) = 0; + + virtual ReturnValue_t deleteList( + ModeListEntry *sequence) = 0; + + virtual ReturnValue_t readList( + ModeListEntry *sequence, + ArrayList *into) = 0; + + virtual uint32_t getFreeSlots() = 0; +}; + +#endif + +#endif /* MODESTOREIF_H_ */ diff --git a/tasks/ExecutableObjectIF.h b/tasks/ExecutableObjectIF.h index d716cdfb..902b2e3c 100644 --- a/tasks/ExecutableObjectIF.h +++ b/tasks/ExecutableObjectIF.h @@ -1,53 +1,53 @@ -#ifndef FRAMEWORK_TASKS_EXECUTABLEOBJECTIF_H_ -#define FRAMEWORK_TASKS_EXECUTABLEOBJECTIF_H_ - -class PeriodicTaskIF; - -#include - -#include -/** - * @brief The interface provides a method to execute objects within a task. - * @details The performOperation method, that is required by the interface is - * executed cyclically within a task context. - * @author Bastian Baetz - */ -class ExecutableObjectIF { -public: - /** - * @brief This is the empty virtual destructor as required for C++ interfaces. - */ - virtual ~ExecutableObjectIF() { } - /** - * @brief The performOperation method is executed in a task. - * @details There are no restrictions for calls within this method, so any - * other member of the class can be used. - * @return Currently, the return value is ignored. - */ - virtual ReturnValue_t performOperation(uint8_t operationCode = 0) = 0; - - /** - * @brief Function called during setup assignment of object to task - * @details - * Has to be called from the function that assigns the object to a task and - * enables the object implementation to overwrite this function and get - * a reference to the executing task - * @param task_ Pointer to the taskIF of this task - */ - virtual void setTaskIF(PeriodicTaskIF* task_) {}; - - /** - * This function should be called after the object was assigned to a - * specific task. - * - * Example: Can be used to get task execution frequency. - * The task is created after initialize() and the object ctors have been - * called so the execution frequency can't be cached in initialize() - * @return - */ - virtual ReturnValue_t initializeAfterTaskCreation() { - return HasReturnvaluesIF::RETURN_OK; - } -}; - -#endif /* FRAMEWORK_TASKS_EXECUTABLEOBJECTIF_H_ */ +#ifndef FRAMEWORK_TASKS_EXECUTABLEOBJECTIF_H_ +#define FRAMEWORK_TASKS_EXECUTABLEOBJECTIF_H_ + +class PeriodicTaskIF; + +#include "../returnvalues/HasReturnvaluesIF.h" + +#include +/** + * @brief The interface provides a method to execute objects within a task. + * @details The performOperation method, that is required by the interface is + * executed cyclically within a task context. + * @author Bastian Baetz + */ +class ExecutableObjectIF { +public: + /** + * @brief This is the empty virtual destructor as required for C++ interfaces. + */ + virtual ~ExecutableObjectIF() { } + /** + * @brief The performOperation method is executed in a task. + * @details There are no restrictions for calls within this method, so any + * other member of the class can be used. + * @return Currently, the return value is ignored. + */ + virtual ReturnValue_t performOperation(uint8_t operationCode = 0) = 0; + + /** + * @brief Function called during setup assignment of object to task + * @details + * Has to be called from the function that assigns the object to a task and + * enables the object implementation to overwrite this function and get + * a reference to the executing task + * @param task_ Pointer to the taskIF of this task + */ + virtual void setTaskIF(PeriodicTaskIF* task_) {}; + + /** + * This function should be called after the object was assigned to a + * specific task. + * + * Example: Can be used to get task execution frequency. + * The task is created after initialize() and the object ctors have been + * called so the execution frequency can't be cached in initialize() + * @return + */ + virtual ReturnValue_t initializeAfterTaskCreation() { + return HasReturnvaluesIF::RETURN_OK; + } +}; + +#endif /* FRAMEWORK_TASKS_EXECUTABLEOBJECTIF_H_ */ diff --git a/tasks/FixedSequenceSlot.cpp b/tasks/FixedSequenceSlot.cpp index 4331aada..cccc6371 100644 --- a/tasks/FixedSequenceSlot.cpp +++ b/tasks/FixedSequenceSlot.cpp @@ -1,16 +1,16 @@ -#include -#include -#include - -FixedSequenceSlot::FixedSequenceSlot(object_id_t handlerId, uint32_t setTime, - int8_t setSequenceId, PeriodicTaskIF* executingTask) : - pollingTimeMs(setTime), opcode(setSequenceId) { - handler = objectManager->get(handlerId); - if(executingTask != nullptr) { - handler->setTaskIF(executingTask); - } - handler->initializeAfterTaskCreation(); -} - -FixedSequenceSlot::~FixedSequenceSlot() {} - +#include "../objectmanager/SystemObjectIF.h" +#include "../tasks/FixedSequenceSlot.h" +#include + +FixedSequenceSlot::FixedSequenceSlot(object_id_t handlerId, uint32_t setTime, + int8_t setSequenceId, PeriodicTaskIF* executingTask) : + pollingTimeMs(setTime), opcode(setSequenceId) { + handler = objectManager->get(handlerId); + if(executingTask != nullptr) { + handler->setTaskIF(executingTask); + } + handler->initializeAfterTaskCreation(); +} + +FixedSequenceSlot::~FixedSequenceSlot() {} + diff --git a/tasks/FixedSequenceSlot.h b/tasks/FixedSequenceSlot.h index 72a35c74..e33134de 100644 --- a/tasks/FixedSequenceSlot.h +++ b/tasks/FixedSequenceSlot.h @@ -1,55 +1,55 @@ -#ifndef FRAMEWORK_TASKS_FIXEDSEQUENCESLOT_H_ -#define FRAMEWORK_TASKS_FIXEDSEQUENCESLOT_H_ - -#include -#include -class PeriodicTaskIF; - -/** - * @brief This class is the representation of a single polling sequence - * table entry. - * @details - * The PollingSlot class is the representation of a single polling - * sequence table entry. - * @author baetz - */ -class FixedSequenceSlot { -public: - FixedSequenceSlot( object_id_t handlerId, uint32_t setTimeMs, - int8_t setSequenceId, PeriodicTaskIF* executingTask ); - virtual ~FixedSequenceSlot(); - - /** - * @brief Handler identifies which device handler object is executed in this slot. - */ - ExecutableObjectIF* handler = nullptr; - - /** - * @brief This attribute defines when a device handler object is executed. - * - * @details The pollingTime attribute identifies the time the handler is executed in ms. - * It must be smaller than the period length of the polling sequence. - */ - uint32_t pollingTimeMs; - - /** - * @brief This value defines the type of device communication. - * - * @details The state of this value decides what communication routine is - * called in the PST executable or the device handler object. - */ - uint8_t opcode; - - /** - * @brief Operator overload for the comparison operator to - * allow sorting by polling time. - * @param fixedSequenceSlot - * @return - */ - bool operator <(const FixedSequenceSlot & fixedSequenceSlot) const { - return pollingTimeMs < fixedSequenceSlot.pollingTimeMs; - } -}; - - -#endif /* FIXEDSEQUENCESLOT_H_ */ +#ifndef FRAMEWORK_TASKS_FIXEDSEQUENCESLOT_H_ +#define FRAMEWORK_TASKS_FIXEDSEQUENCESLOT_H_ + +#include "../objectmanager/ObjectManagerIF.h" +#include "../tasks/ExecutableObjectIF.h" +class PeriodicTaskIF; + +/** + * @brief This class is the representation of a single polling sequence + * table entry. + * @details + * The PollingSlot class is the representation of a single polling + * sequence table entry. + * @author baetz + */ +class FixedSequenceSlot { +public: + FixedSequenceSlot( object_id_t handlerId, uint32_t setTimeMs, + int8_t setSequenceId, PeriodicTaskIF* executingTask ); + virtual ~FixedSequenceSlot(); + + /** + * @brief Handler identifies which device handler object is executed in this slot. + */ + ExecutableObjectIF* handler = nullptr; + + /** + * @brief This attribute defines when a device handler object is executed. + * + * @details The pollingTime attribute identifies the time the handler is executed in ms. + * It must be smaller than the period length of the polling sequence. + */ + uint32_t pollingTimeMs; + + /** + * @brief This value defines the type of device communication. + * + * @details The state of this value decides what communication routine is + * called in the PST executable or the device handler object. + */ + uint8_t opcode; + + /** + * @brief Operator overload for the comparison operator to + * allow sorting by polling time. + * @param fixedSequenceSlot + * @return + */ + bool operator <(const FixedSequenceSlot & fixedSequenceSlot) const { + return pollingTimeMs < fixedSequenceSlot.pollingTimeMs; + } +}; + + +#endif /* FIXEDSEQUENCESLOT_H_ */ diff --git a/tasks/FixedSlotSequence.cpp b/tasks/FixedSlotSequence.cpp index 3e542bfc..27dfff2b 100644 --- a/tasks/FixedSlotSequence.cpp +++ b/tasks/FixedSlotSequence.cpp @@ -1,124 +1,124 @@ -#include -#include -#include - -FixedSlotSequence::FixedSlotSequence(uint32_t setLengthMs) : - lengthMs(setLengthMs) { - current = slotList.begin(); -} - -FixedSlotSequence::~FixedSlotSequence() { - // Call the destructor on each list entry. - slotList.clear(); -} - -void FixedSlotSequence::executeAndAdvance() { - current->handler->performOperation(current->opcode); -// if (returnValue != RETURN_OK) { -// this->sendErrorMessage( returnValue ); -// } - //Increment the polling Sequence iterator - this->current++; - //Set it to the beginning, if the list's end is reached. - if (this->current == this->slotList.end()) { - this->current = this->slotList.begin(); - } -} - -uint32_t FixedSlotSequence::getIntervalToNextSlotMs() { - uint32_t oldTime; - SlotListIter slotListIter = current; - // Get the pollingTimeMs of the current slot object. - oldTime = slotListIter->pollingTimeMs; - // Advance to the next object. - slotListIter++; - // Find the next interval which is not 0. - while (slotListIter != slotList.end()) { - if (oldTime != slotListIter->pollingTimeMs) { - return slotListIter->pollingTimeMs - oldTime; - } else { - slotListIter++; - } - } - // If the list end is reached (this is definitely an interval != 0), - // the interval is calculated by subtracting the remaining time of the PST - // and adding the start time of the first handler in the list. - slotListIter = slotList.begin(); - return lengthMs - oldTime + slotListIter->pollingTimeMs; -} - -uint32_t FixedSlotSequence::getIntervalToPreviousSlotMs() { - uint32_t currentTime; - SlotListIter slotListIter = current; - // Get the pollingTimeMs of the current slot object. - currentTime = slotListIter->pollingTimeMs; - - //if it is the first slot, calculate difference to last slot - if (slotListIter == slotList.begin()){ - return lengthMs - (--slotList.end())->pollingTimeMs + currentTime; - } - // get previous slot - slotListIter--; - - return currentTime - slotListIter->pollingTimeMs; -} - -bool FixedSlotSequence::slotFollowsImmediately() { - uint32_t currentTime = current->pollingTimeMs; - SlotListIter fixedSequenceIter = this->current; - // Get the pollingTimeMs of the current slot object. - if (fixedSequenceIter == slotList.begin()) - return false; - fixedSequenceIter--; - if (fixedSequenceIter->pollingTimeMs == currentTime) { - return true; - } else { - return false; - } -} - -uint32_t FixedSlotSequence::getLengthMs() const { - return this->lengthMs; -} - -ReturnValue_t FixedSlotSequence::checkSequence() const { - if(slotList.empty()) { - sif::error << "Fixed Slot Sequence: Slot list is empty!" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - - auto slotIt = slotList.begin(); - uint32_t count = 0; - uint32_t time = 0; - while (slotIt != slotList.end()) { - if (slotIt->handler == nullptr) { - sif::error << "FixedSlotSequene::initialize: ObjectId does not exist!" - << std::endl; - count++; - } else if (slotIt->pollingTimeMs < time) { - sif::error << "FixedSlotSequence::initialize: Time: " - << slotIt->pollingTimeMs - << " is smaller than previous with " << time << std::endl; - count++; - } else { - // All ok, print slot. - //info << "Current slot polling time: " << std::endl; - //info << std::dec << slotIt->pollingTimeMs << std::endl; - } - time = slotIt->pollingTimeMs; - slotIt++; - } - //info << "Number of elements in slot list: " - // << slotList.size() << std::endl; - if (count > 0) { - return HasReturnvaluesIF::RETURN_FAILED; - } - return HasReturnvaluesIF::RETURN_OK; -} - -void FixedSlotSequence::addSlot(object_id_t componentId, uint32_t slotTimeMs, - int8_t executionStep, PeriodicTaskIF* executingTask) { - this->slotList.insert(FixedSequenceSlot(componentId, slotTimeMs, executionStep, - executingTask)); - this->current = slotList.begin(); -} +#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../tasks/FixedSlotSequence.h" +#include + +FixedSlotSequence::FixedSlotSequence(uint32_t setLengthMs) : + lengthMs(setLengthMs) { + current = slotList.begin(); +} + +FixedSlotSequence::~FixedSlotSequence() { + // Call the destructor on each list entry. + slotList.clear(); +} + +void FixedSlotSequence::executeAndAdvance() { + current->handler->performOperation(current->opcode); +// if (returnValue != RETURN_OK) { +// this->sendErrorMessage( returnValue ); +// } + //Increment the polling Sequence iterator + this->current++; + //Set it to the beginning, if the list's end is reached. + if (this->current == this->slotList.end()) { + this->current = this->slotList.begin(); + } +} + +uint32_t FixedSlotSequence::getIntervalToNextSlotMs() { + uint32_t oldTime; + SlotListIter slotListIter = current; + // Get the pollingTimeMs of the current slot object. + oldTime = slotListIter->pollingTimeMs; + // Advance to the next object. + slotListIter++; + // Find the next interval which is not 0. + while (slotListIter != slotList.end()) { + if (oldTime != slotListIter->pollingTimeMs) { + return slotListIter->pollingTimeMs - oldTime; + } else { + slotListIter++; + } + } + // If the list end is reached (this is definitely an interval != 0), + // the interval is calculated by subtracting the remaining time of the PST + // and adding the start time of the first handler in the list. + slotListIter = slotList.begin(); + return lengthMs - oldTime + slotListIter->pollingTimeMs; +} + +uint32_t FixedSlotSequence::getIntervalToPreviousSlotMs() { + uint32_t currentTime; + SlotListIter slotListIter = current; + // Get the pollingTimeMs of the current slot object. + currentTime = slotListIter->pollingTimeMs; + + //if it is the first slot, calculate difference to last slot + if (slotListIter == slotList.begin()){ + return lengthMs - (--slotList.end())->pollingTimeMs + currentTime; + } + // get previous slot + slotListIter--; + + return currentTime - slotListIter->pollingTimeMs; +} + +bool FixedSlotSequence::slotFollowsImmediately() { + uint32_t currentTime = current->pollingTimeMs; + SlotListIter fixedSequenceIter = this->current; + // Get the pollingTimeMs of the current slot object. + if (fixedSequenceIter == slotList.begin()) + return false; + fixedSequenceIter--; + if (fixedSequenceIter->pollingTimeMs == currentTime) { + return true; + } else { + return false; + } +} + +uint32_t FixedSlotSequence::getLengthMs() const { + return this->lengthMs; +} + +ReturnValue_t FixedSlotSequence::checkSequence() const { + if(slotList.empty()) { + sif::error << "Fixed Slot Sequence: Slot list is empty!" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + + auto slotIt = slotList.begin(); + uint32_t count = 0; + uint32_t time = 0; + while (slotIt != slotList.end()) { + if (slotIt->handler == nullptr) { + sif::error << "FixedSlotSequene::initialize: ObjectId does not exist!" + << std::endl; + count++; + } else if (slotIt->pollingTimeMs < time) { + sif::error << "FixedSlotSequence::initialize: Time: " + << slotIt->pollingTimeMs + << " is smaller than previous with " << time << std::endl; + count++; + } else { + // All ok, print slot. + //info << "Current slot polling time: " << std::endl; + //info << std::dec << slotIt->pollingTimeMs << std::endl; + } + time = slotIt->pollingTimeMs; + slotIt++; + } + //info << "Number of elements in slot list: " + // << slotList.size() << std::endl; + if (count > 0) { + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; +} + +void FixedSlotSequence::addSlot(object_id_t componentId, uint32_t slotTimeMs, + int8_t executionStep, PeriodicTaskIF* executingTask) { + this->slotList.insert(FixedSequenceSlot(componentId, slotTimeMs, executionStep, + executingTask)); + this->current = slotList.begin(); +} diff --git a/tasks/FixedSlotSequence.h b/tasks/FixedSlotSequence.h index 61883658..67ce0094 100644 --- a/tasks/FixedSlotSequence.h +++ b/tasks/FixedSlotSequence.h @@ -1,154 +1,154 @@ -#ifndef FRAMEWORK_TASKS_FIXEDSLOTSEQUENCE_H_ -#define FRAMEWORK_TASKS_FIXEDSLOTSEQUENCE_H_ - -#include -#include - -#include - -/** - * @brief This class is the representation of a Polling Sequence Table in software. - * @details - * The FixedSlotSequence object maintains the dynamic execution of - * device handler objects. - * - * The main idea is to create a list of device handlers, to announce all - * handlers to thepolling sequence and to maintain a list of - * polling slot objects. This slot list represents the Polling Sequence Table - * in software. - * - * Each polling slot contains information to indicate when and - * which device handler shall be executed within a given polling period. - * The sequence is then executed by iterating through this slot list. - * Handlers are invoking by calling a certain function stored in the handler list. - */ -class FixedSlotSequence { -public: - using SlotList = std::multiset; - using SlotListIter = std::multiset::iterator; - - /** - * @brief The constructor of the FixedSlotSequence object. - * - * @details The constructor takes two arguments, the period length and the init function. - * - * @param setLength The period length, expressed in ms. - */ - FixedSlotSequence(uint32_t setLengthMs); - - /** - * @brief The destructor of the FixedSlotSequence object. - * - * @details The destructor frees all allocated memory by iterating through the slotList - * and deleting all allocated resources. - */ - virtual ~FixedSlotSequence(); - - /** - * @brief This is a method to add an PollingSlot object to slotList. - * - * @details Here, a polling slot object is added to the slot list. It is appended - * to the end of the list. The list is currently NOT reordered. - * Afterwards, the iterator current is set to the beginning of the list. - * @param Object ID of the object to add - * @param setTime Value between (0 to 1) * slotLengthMs, when a FixedTimeslotTask - * will be called inside the slot period. - * @param setSequenceId ID which can be used to distinguish - * different task operations - * @param - * @param - */ - void addSlot(object_id_t handlerId, uint32_t setTime, int8_t setSequenceId, - PeriodicTaskIF* executingTask); - - /** - * Checks if the current slot shall be executed immediately after the one before. - * This allows to distinguish between grouped and not grouped handlers. - * @return - @c true if the slot has the same polling time as the previous - * - @c false else - */ - bool slotFollowsImmediately(); - - /** - * @brief This method returns the time until the next software - * component is invoked. - * - * @details - * This method is vitally important for the operation of the PST. - * By fetching the polling time of the current slot and that of the - * next one (or the first one, if the list end is reached) - * it calculates and returns the interval in milliseconds within - * which the handler execution shall take place. - * If the next slot has the same time as the current one, it is ignored - * until a slot with different time or the end of the PST is found. - */ - uint32_t getIntervalToNextSlotMs(); - - /** - * @brief This method returns the time difference between the current - * slot and the previous slot - * - * @details - * This method is vitally important for the operation of the PST. - * By fetching the polling time of the current slot and that of the previous - * one (or the last one, if the slot is the first one) it calculates and - * returns the interval in milliseconds that the handler execution shall - * be delayed. - */ - uint32_t getIntervalToPreviousSlotMs(); - - /** - * @brief This method returns the length of this FixedSlotSequence instance. - */ - uint32_t getLengthMs() const; - - /** - * @brief The method to execute the device handler entered in the current - * PollingSlot object. - * - * @details - * Within this method the device handler object to be executed is chosen by - * looking up the handler address of the current slot in the handlerMap. - * Either the device handler's talkToInterface or its listenToInterface - * method is invoked, depending on the isTalking flag of the polling slot. - * After execution the iterator current is increased or, by reaching the - * end of slotList, reset to the beginning. - */ - void executeAndAdvance(); - - /** - * @brief An iterator that indicates the current polling slot to execute. - * - * @details This is an iterator for slotList and always points to the - * polling slot which is executed next. - */ - SlotListIter current; - - /** - * Iterate through slotList and check successful creation. - * Checks if timing is ok (must be ascending) and if all handlers were found. - * @return - */ - ReturnValue_t checkSequence() const; - -protected: - - /** - * @brief This list contains all PollingSlot objects, defining order and - * execution time of the device handler objects. - * - * @details - * The slot list is a std:list object that contains all created - * PollingSlot instances. They are NOT ordered automatically, so by - * adding entries, the correct order needs to be ensured. By iterating - * through this list the polling sequence is executed. Two entries with - * identical polling times are executed immediately one after another. - */ - SlotList slotList; - - uint32_t lengthMs; - - bool isEmpty = false; -}; - -#endif /* FIXEDSLOTSEQUENCE_H_ */ +#ifndef FRAMEWORK_TASKS_FIXEDSLOTSEQUENCE_H_ +#define FRAMEWORK_TASKS_FIXEDSLOTSEQUENCE_H_ + +#include "../objectmanager/SystemObject.h" +#include "../tasks/FixedSequenceSlot.h" + +#include + +/** + * @brief This class is the representation of a Polling Sequence Table in software. + * @details + * The FixedSlotSequence object maintains the dynamic execution of + * device handler objects. + * + * The main idea is to create a list of device handlers, to announce all + * handlers to thepolling sequence and to maintain a list of + * polling slot objects. This slot list represents the Polling Sequence Table + * in software. + * + * Each polling slot contains information to indicate when and + * which device handler shall be executed within a given polling period. + * The sequence is then executed by iterating through this slot list. + * Handlers are invoking by calling a certain function stored in the handler list. + */ +class FixedSlotSequence { +public: + using SlotList = std::multiset; + using SlotListIter = std::multiset::iterator; + + /** + * @brief The constructor of the FixedSlotSequence object. + * + * @details The constructor takes two arguments, the period length and the init function. + * + * @param setLength The period length, expressed in ms. + */ + FixedSlotSequence(uint32_t setLengthMs); + + /** + * @brief The destructor of the FixedSlotSequence object. + * + * @details The destructor frees all allocated memory by iterating through the slotList + * and deleting all allocated resources. + */ + virtual ~FixedSlotSequence(); + + /** + * @brief This is a method to add an PollingSlot object to slotList. + * + * @details Here, a polling slot object is added to the slot list. It is appended + * to the end of the list. The list is currently NOT reordered. + * Afterwards, the iterator current is set to the beginning of the list. + * @param Object ID of the object to add + * @param setTime Value between (0 to 1) * slotLengthMs, when a FixedTimeslotTask + * will be called inside the slot period. + * @param setSequenceId ID which can be used to distinguish + * different task operations + * @param + * @param + */ + void addSlot(object_id_t handlerId, uint32_t setTime, int8_t setSequenceId, + PeriodicTaskIF* executingTask); + + /** + * Checks if the current slot shall be executed immediately after the one before. + * This allows to distinguish between grouped and not grouped handlers. + * @return - @c true if the slot has the same polling time as the previous + * - @c false else + */ + bool slotFollowsImmediately(); + + /** + * @brief This method returns the time until the next software + * component is invoked. + * + * @details + * This method is vitally important for the operation of the PST. + * By fetching the polling time of the current slot and that of the + * next one (or the first one, if the list end is reached) + * it calculates and returns the interval in milliseconds within + * which the handler execution shall take place. + * If the next slot has the same time as the current one, it is ignored + * until a slot with different time or the end of the PST is found. + */ + uint32_t getIntervalToNextSlotMs(); + + /** + * @brief This method returns the time difference between the current + * slot and the previous slot + * + * @details + * This method is vitally important for the operation of the PST. + * By fetching the polling time of the current slot and that of the previous + * one (or the last one, if the slot is the first one) it calculates and + * returns the interval in milliseconds that the handler execution shall + * be delayed. + */ + uint32_t getIntervalToPreviousSlotMs(); + + /** + * @brief This method returns the length of this FixedSlotSequence instance. + */ + uint32_t getLengthMs() const; + + /** + * @brief The method to execute the device handler entered in the current + * PollingSlot object. + * + * @details + * Within this method the device handler object to be executed is chosen by + * looking up the handler address of the current slot in the handlerMap. + * Either the device handler's talkToInterface or its listenToInterface + * method is invoked, depending on the isTalking flag of the polling slot. + * After execution the iterator current is increased or, by reaching the + * end of slotList, reset to the beginning. + */ + void executeAndAdvance(); + + /** + * @brief An iterator that indicates the current polling slot to execute. + * + * @details This is an iterator for slotList and always points to the + * polling slot which is executed next. + */ + SlotListIter current; + + /** + * Iterate through slotList and check successful creation. + * Checks if timing is ok (must be ascending) and if all handlers were found. + * @return + */ + ReturnValue_t checkSequence() const; + +protected: + + /** + * @brief This list contains all PollingSlot objects, defining order and + * execution time of the device handler objects. + * + * @details + * The slot list is a std:list object that contains all created + * PollingSlot instances. They are NOT ordered automatically, so by + * adding entries, the correct order needs to be ensured. By iterating + * through this list the polling sequence is executed. Two entries with + * identical polling times are executed immediately one after another. + */ + SlotList slotList; + + uint32_t lengthMs; + + bool isEmpty = false; +}; + +#endif /* FIXEDSLOTSEQUENCE_H_ */ diff --git a/tasks/FixedTimeslotTaskIF.h b/tasks/FixedTimeslotTaskIF.h index 023b5ee0..3456dae7 100644 --- a/tasks/FixedTimeslotTaskIF.h +++ b/tasks/FixedTimeslotTaskIF.h @@ -1,29 +1,29 @@ -#ifndef FRAMEWORK_TASKS_FIXEDTIMESLOTTASKIF_H_ -#define FRAMEWORK_TASKS_FIXEDTIMESLOTTASKIF_H_ - -#include -#include - -/** - * @brief Following the same principle as the base class IF. - * This is the interface for a Fixed timeslot task - */ -class FixedTimeslotTaskIF : public PeriodicTaskIF { -public: - virtual ~FixedTimeslotTaskIF() {} - - /** - * Add an object with a slot time and the execution step to the task. - * The execution step shall be passed to the object. - * @param componentId - * @param slotTimeMs - * @param executionStep - * @return - */ - virtual ReturnValue_t addSlot(object_id_t componentId, - uint32_t slotTimeMs, int8_t executionStep) = 0; - /** Check whether the sequence is valid */ - virtual ReturnValue_t checkSequence() const = 0; -}; - -#endif /* FRAMEWORK_TASKS_FIXEDTIMESLOTTASKIF_H_ */ +#ifndef FRAMEWORK_TASKS_FIXEDTIMESLOTTASKIF_H_ +#define FRAMEWORK_TASKS_FIXEDTIMESLOTTASKIF_H_ + +#include "../objectmanager/ObjectManagerIF.h" +#include "../tasks/PeriodicTaskIF.h" + +/** + * @brief Following the same principle as the base class IF. + * This is the interface for a Fixed timeslot task + */ +class FixedTimeslotTaskIF : public PeriodicTaskIF { +public: + virtual ~FixedTimeslotTaskIF() {} + + /** + * Add an object with a slot time and the execution step to the task. + * The execution step shall be passed to the object. + * @param componentId + * @param slotTimeMs + * @param executionStep + * @return + */ + virtual ReturnValue_t addSlot(object_id_t componentId, + uint32_t slotTimeMs, int8_t executionStep) = 0; + /** Check whether the sequence is valid */ + virtual ReturnValue_t checkSequence() const = 0; +}; + +#endif /* FRAMEWORK_TASKS_FIXEDTIMESLOTTASKIF_H_ */ diff --git a/tasks/PeriodicTaskIF.h b/tasks/PeriodicTaskIF.h index f54d6155..38cf201b 100644 --- a/tasks/PeriodicTaskIF.h +++ b/tasks/PeriodicTaskIF.h @@ -1,49 +1,49 @@ -#ifndef FRAMEWORK_TASK_PERIODICTASKIF_H_ -#define FRAMEWORK_TASK_PERIODICTASKIF_H_ - -#include -#include -#include -class ExecutableObjectIF; - -/** - * New version of TaskIF - * Follows RAII principles, i.e. there's no create or delete method. - * Minimalistic. -*/ -class PeriodicTaskIF { -public: - static const size_t MINIMUM_STACK_SIZE; - /** - * @brief A virtual destructor as it is mandatory for interfaces. - */ - virtual ~PeriodicTaskIF() { } - /** - * @brief With the startTask method, a created task can be started - * for the first time. - */ - virtual ReturnValue_t startTask() = 0; - - /** - * Add a component (object) to a periodic task. The pointer to the - * task can be set optionally - * @param object - * Add an object to the task. The most important case is to add an - * executable object with a function which will be called regularly - * (see ExecutableObjectIF) - * @param setTaskIF - * Can be used to specify whether the task object pointer is passed - * to the component. - * @return - */ - virtual ReturnValue_t addComponent(object_id_t object) { - return HasReturnvaluesIF::RETURN_FAILED; - }; - - virtual ReturnValue_t sleepFor(uint32_t ms) = 0; - - virtual uint32_t getPeriodMs() const = 0; -}; - - -#endif /* PERIODICTASKIF_H_ */ +#ifndef FRAMEWORK_TASK_PERIODICTASKIF_H_ +#define FRAMEWORK_TASK_PERIODICTASKIF_H_ + +#include "../objectmanager/SystemObjectIF.h" +#include "../timemanager/Clock.h" +#include +class ExecutableObjectIF; + +/** + * New version of TaskIF + * Follows RAII principles, i.e. there's no create or delete method. + * Minimalistic. +*/ +class PeriodicTaskIF { +public: + static const size_t MINIMUM_STACK_SIZE; + /** + * @brief A virtual destructor as it is mandatory for interfaces. + */ + virtual ~PeriodicTaskIF() { } + /** + * @brief With the startTask method, a created task can be started + * for the first time. + */ + virtual ReturnValue_t startTask() = 0; + + /** + * Add a component (object) to a periodic task. The pointer to the + * task can be set optionally + * @param object + * Add an object to the task. The most important case is to add an + * executable object with a function which will be called regularly + * (see ExecutableObjectIF) + * @param setTaskIF + * Can be used to specify whether the task object pointer is passed + * to the component. + * @return + */ + virtual ReturnValue_t addComponent(object_id_t object) { + return HasReturnvaluesIF::RETURN_FAILED; + }; + + virtual ReturnValue_t sleepFor(uint32_t ms) = 0; + + virtual uint32_t getPeriodMs() const = 0; +}; + + +#endif /* PERIODICTASKIF_H_ */ diff --git a/tasks/SemaphoreFactory.h b/tasks/SemaphoreFactory.h index 7f8edaf1..b2f34788 100644 --- a/tasks/SemaphoreFactory.h +++ b/tasks/SemaphoreFactory.h @@ -1,49 +1,49 @@ -#ifndef FRAMEWORK_TASKS_SEMAPHOREFACTORY_H_ -#define FRAMEWORK_TASKS_SEMAPHOREFACTORY_H_ -#include - -/** - * Creates Semaphore. - * This class is a "singleton" interface, i.e. it provides an - * interface, but also is the base class for a singleton. - */ -class SemaphoreFactory { -public: - virtual ~SemaphoreFactory(); - /** - * Returns the single instance of SemaphoreFactory. - * The implementation of #instance is found in its subclasses. - * Thus, we choose link-time variability of the instance. - */ - static SemaphoreFactory* instance(); - - /** - * Create a binary semaphore. - * Creator function for a binary semaphore which may only be acquired once - * @param argument Can be used to pass implementation specific information. - * @return Pointer to newly created semaphore class instance. - */ - SemaphoreIF* createBinarySemaphore(uint32_t arguments = 0); - /** - * Create a counting semaphore. - * Creator functons for a counting semaphore which may be acquired multiple - * times. - * @param count Semaphore can be taken count times. - * @param initCount Initial count value. - * @param argument Can be used to pass implementation specific information. - * @return - */ - SemaphoreIF* createCountingSemaphore(const uint8_t maxCount, - uint8_t initCount, uint32_t arguments = 0); - - void deleteSemaphore(SemaphoreIF* semaphore); - -private: - /** - * External instantiation is not allowed. - */ - SemaphoreFactory(); - static SemaphoreFactory* factoryInstance; -}; - -#endif /* FRAMEWORK_TASKS_SEMAPHOREFACTORY_H_ */ +#ifndef FRAMEWORK_TASKS_SEMAPHOREFACTORY_H_ +#define FRAMEWORK_TASKS_SEMAPHOREFACTORY_H_ +#include "../tasks/SemaphoreIF.h" + +/** + * Creates Semaphore. + * This class is a "singleton" interface, i.e. it provides an + * interface, but also is the base class for a singleton. + */ +class SemaphoreFactory { +public: + virtual ~SemaphoreFactory(); + /** + * Returns the single instance of SemaphoreFactory. + * The implementation of #instance is found in its subclasses. + * Thus, we choose link-time variability of the instance. + */ + static SemaphoreFactory* instance(); + + /** + * Create a binary semaphore. + * Creator function for a binary semaphore which may only be acquired once + * @param argument Can be used to pass implementation specific information. + * @return Pointer to newly created semaphore class instance. + */ + SemaphoreIF* createBinarySemaphore(uint32_t arguments = 0); + /** + * Create a counting semaphore. + * Creator functons for a counting semaphore which may be acquired multiple + * times. + * @param count Semaphore can be taken count times. + * @param initCount Initial count value. + * @param argument Can be used to pass implementation specific information. + * @return + */ + SemaphoreIF* createCountingSemaphore(const uint8_t maxCount, + uint8_t initCount, uint32_t arguments = 0); + + void deleteSemaphore(SemaphoreIF* semaphore); + +private: + /** + * External instantiation is not allowed. + */ + SemaphoreFactory(); + static SemaphoreFactory* factoryInstance; +}; + +#endif /* FRAMEWORK_TASKS_SEMAPHOREFACTORY_H_ */ diff --git a/tasks/SemaphoreIF.h b/tasks/SemaphoreIF.h index 4fc92ebd..3fed4511 100644 --- a/tasks/SemaphoreIF.h +++ b/tasks/SemaphoreIF.h @@ -1,72 +1,72 @@ -#ifndef FRAMEWORK_TASKS_SEMAPHOREIF_H_ -#define FRAMEWORK_TASKS_SEMAPHOREIF_H_ -#include -#include -#include - -/** - * @brief Generic interface for semaphores, which can be used to achieve - * task synchronization. This is a generic interface which can be - * used for both binary semaphores and counting semaphores. - * @details - * A semaphore is a synchronization primitive. - * See: https://en.wikipedia.org/wiki/Semaphore_(programming) - * A semaphore can be used to achieve task synchonization and track the - * availability of resources by using either the binary or the counting - * semaphore types. - * - * If mutual exlcusion of a resource is desired, a mutex should be used, - * which is a special form of a semaphore and has an own interface. - */ -class SemaphoreIF { -public: - virtual~ SemaphoreIF() {}; - /** - * @brief Timeout value used for polling lock attempt. - * @details - * If the lock is not successfull, MUTEX_TIMEOUT will be returned - * immediately. Value needs to be defined in implementation. - */ - static const uint32_t POLLING; - /** - * @brief Timeout value used for permanent blocking lock attempt. - * @details - * The task will be blocked (indefinitely) until the mutex is unlocked. - * Value needs to be defined in implementation. - */ - static const uint32_t BLOCKING; - - static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; - //! Semaphore timeout - static constexpr ReturnValue_t SEMAPHORE_TIMEOUT = MAKE_RETURN_CODE(1); - //! The current semaphore can not be given, because it is not owned - static constexpr ReturnValue_t SEMAPHORE_NOT_OWNED = MAKE_RETURN_CODE(2); - static constexpr ReturnValue_t SEMAPHORE_INVALID = MAKE_RETURN_CODE(3); - - /** - * Generic call to acquire a semaphore. - * If there are no more semaphores to be taken (for a counting semaphore, - * a semaphore may be taken more than once), the taks will block - * for a maximum of timeoutMs while trying to acquire the semaphore. - * This can be used to achieve task synchrnization. - * @param timeoutMs - * @return - c RETURN_OK for successfull acquisition - */ - virtual ReturnValue_t acquire(uint32_t timeoutMs) = 0; - - /** - * Corrensponding call to release a semaphore. - * @return -@c RETURN_OK for successfull release - */ - virtual ReturnValue_t release() = 0; - - /** - * If the semaphore is a counting semaphore then the semaphores current - * count value is returned. If the semaphore is a binary semaphore then 1 - * is returned if the semaphore is available, and 0 is returned if the - * semaphore is not available. - */ - virtual uint8_t getSemaphoreCounter() const = 0; -}; - -#endif /* FRAMEWORK_TASKS_SEMAPHOREIF_H_ */ +#ifndef FRAMEWORK_TASKS_SEMAPHOREIF_H_ +#define FRAMEWORK_TASKS_SEMAPHOREIF_H_ +#include "../returnvalues/FwClassIds.h" +#include "../returnvalues/HasReturnvaluesIF.h" +#include + +/** + * @brief Generic interface for semaphores, which can be used to achieve + * task synchronization. This is a generic interface which can be + * used for both binary semaphores and counting semaphores. + * @details + * A semaphore is a synchronization primitive. + * See: https://en.wikipedia.org/wiki/Semaphore_(programming) + * A semaphore can be used to achieve task synchonization and track the + * availability of resources by using either the binary or the counting + * semaphore types. + * + * If mutual exlcusion of a resource is desired, a mutex should be used, + * which is a special form of a semaphore and has an own interface. + */ +class SemaphoreIF { +public: + virtual~ SemaphoreIF() {}; + /** + * @brief Timeout value used for polling lock attempt. + * @details + * If the lock is not successfull, MUTEX_TIMEOUT will be returned + * immediately. Value needs to be defined in implementation. + */ + static const uint32_t POLLING; + /** + * @brief Timeout value used for permanent blocking lock attempt. + * @details + * The task will be blocked (indefinitely) until the mutex is unlocked. + * Value needs to be defined in implementation. + */ + static const uint32_t BLOCKING; + + static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; + //! Semaphore timeout + static constexpr ReturnValue_t SEMAPHORE_TIMEOUT = MAKE_RETURN_CODE(1); + //! The current semaphore can not be given, because it is not owned + static constexpr ReturnValue_t SEMAPHORE_NOT_OWNED = MAKE_RETURN_CODE(2); + static constexpr ReturnValue_t SEMAPHORE_INVALID = MAKE_RETURN_CODE(3); + + /** + * Generic call to acquire a semaphore. + * If there are no more semaphores to be taken (for a counting semaphore, + * a semaphore may be taken more than once), the taks will block + * for a maximum of timeoutMs while trying to acquire the semaphore. + * This can be used to achieve task synchrnization. + * @param timeoutMs + * @return - c RETURN_OK for successfull acquisition + */ + virtual ReturnValue_t acquire(uint32_t timeoutMs) = 0; + + /** + * Corrensponding call to release a semaphore. + * @return -@c RETURN_OK for successfull release + */ + virtual ReturnValue_t release() = 0; + + /** + * If the semaphore is a counting semaphore then the semaphores current + * count value is returned. If the semaphore is a binary semaphore then 1 + * is returned if the semaphore is available, and 0 is returned if the + * semaphore is not available. + */ + virtual uint8_t getSemaphoreCounter() const = 0; +}; + +#endif /* FRAMEWORK_TASKS_SEMAPHOREIF_H_ */ diff --git a/tasks/TaskFactory.h b/tasks/TaskFactory.h index e1e2f5e2..56b3083e 100644 --- a/tasks/TaskFactory.h +++ b/tasks/TaskFactory.h @@ -1,73 +1,73 @@ -#ifndef FRAMEWORK_TASKS_TASKFACTORY_H_ -#define FRAMEWORK_TASKS_TASKFACTORY_H_ - -#include -#include -#include - -/** - * Singleton Class that produces Tasks. - */ -class TaskFactory { -public: - virtual ~TaskFactory(); - /** - * Returns the single instance of TaskFactory. - * The implementation of #instance is found in its subclasses. - * Thus, we choose link-time variability of the instance. - */ - static TaskFactory* instance(); - - /** - * Generic interface to create a periodic task - * @param name_ Name of the task - * @param taskPriority_ Priority of the task - * @param stackSize_ Stack size if the task - * @param periodInSeconds_ Period in seconds - * @param deadLineMissedFunction_ This function is called if a deadline was - * missed - * @return Pointer to the created periodic task class - */ - PeriodicTaskIF* createPeriodicTask(TaskName name_, - TaskPriority taskPriority_, TaskStackSize stackSize_, - TaskPeriod periodInSeconds_, - TaskDeadlineMissedFunction deadLineMissedFunction_); - - /** - * Generic interface to create a fixed timeslot task - * @param name_ Name of the task - * @param taskPriority_ Priority of the task - * @param stackSize_ Stack size if the task - * @param periodInSeconds_ Period in seconds - * @param deadLineMissedFunction_ This function is called if a deadline was - * missed - * @return Pointer to the created periodic task class - */ - FixedTimeslotTaskIF* createFixedTimeslotTask(TaskName name_, - TaskPriority taskPriority_, TaskStackSize stackSize_, - TaskPeriod periodInSeconds_, - TaskDeadlineMissedFunction deadLineMissedFunction_); - - /** - * Function to be called to delete a task - * @param task The pointer to the task that shall be deleted, - * NULL specifies current Task - * @return Success of deletion - */ - static ReturnValue_t deleteTask(PeriodicTaskIF* task = NULL); - - /** - * Function to be called to delay current task - * @param delay The delay in milliseconds - * @return Success of deletion - */ - static ReturnValue_t delayTask(uint32_t delayMs); -private: - /** - * External instantiation is not allowed. - */ - TaskFactory(); - static TaskFactory* factoryInstance; -}; - -#endif /* FRAMEWORK_TASKS_TASKFACTORY_H_ */ +#ifndef FRAMEWORK_TASKS_TASKFACTORY_H_ +#define FRAMEWORK_TASKS_TASKFACTORY_H_ + +#include +#include "../tasks/FixedTimeslotTaskIF.h" +#include "../tasks/Typedef.h" + +/** + * Singleton Class that produces Tasks. + */ +class TaskFactory { +public: + virtual ~TaskFactory(); + /** + * Returns the single instance of TaskFactory. + * The implementation of #instance is found in its subclasses. + * Thus, we choose link-time variability of the instance. + */ + static TaskFactory* instance(); + + /** + * Generic interface to create a periodic task + * @param name_ Name of the task + * @param taskPriority_ Priority of the task + * @param stackSize_ Stack size if the task + * @param periodInSeconds_ Period in seconds + * @param deadLineMissedFunction_ This function is called if a deadline was + * missed + * @return Pointer to the created periodic task class + */ + PeriodicTaskIF* createPeriodicTask(TaskName name_, + TaskPriority taskPriority_, TaskStackSize stackSize_, + TaskPeriod periodInSeconds_, + TaskDeadlineMissedFunction deadLineMissedFunction_); + + /** + * Generic interface to create a fixed timeslot task + * @param name_ Name of the task + * @param taskPriority_ Priority of the task + * @param stackSize_ Stack size if the task + * @param periodInSeconds_ Period in seconds + * @param deadLineMissedFunction_ This function is called if a deadline was + * missed + * @return Pointer to the created periodic task class + */ + FixedTimeslotTaskIF* createFixedTimeslotTask(TaskName name_, + TaskPriority taskPriority_, TaskStackSize stackSize_, + TaskPeriod periodInSeconds_, + TaskDeadlineMissedFunction deadLineMissedFunction_); + + /** + * Function to be called to delete a task + * @param task The pointer to the task that shall be deleted, + * NULL specifies current Task + * @return Success of deletion + */ + static ReturnValue_t deleteTask(PeriodicTaskIF* task = NULL); + + /** + * Function to be called to delay current task + * @param delay The delay in milliseconds + * @return Success of deletion + */ + static ReturnValue_t delayTask(uint32_t delayMs); +private: + /** + * External instantiation is not allowed. + */ + TaskFactory(); + static TaskFactory* factoryInstance; +}; + +#endif /* FRAMEWORK_TASKS_TASKFACTORY_H_ */ diff --git a/tcdistribution/CCSDSDistributor.cpp b/tcdistribution/CCSDSDistributor.cpp index 24c93730..68f26d2c 100644 --- a/tcdistribution/CCSDSDistributor.cpp +++ b/tcdistribution/CCSDSDistributor.cpp @@ -1,82 +1,82 @@ -#include -#include -#include - -CCSDSDistributor::CCSDSDistributor(uint16_t setDefaultApid, - object_id_t setObjectId): - TcDistributor(setObjectId), defaultApid( setDefaultApid ) { -} - -CCSDSDistributor::~CCSDSDistributor() {} - -TcDistributor::TcMqMapIter CCSDSDistributor::selectDestination() { -// sif::debug << "CCSDSDistributor::selectDestination received: " << -// this->currentMessage.getStorageId().pool_index << ", " << -// this->currentMessage.getStorageId().packet_index << std::endl; - const uint8_t* packet = nullptr; - size_t size = 0; - ReturnValue_t result = this->tcStore->getData(currentMessage.getStorageId(), - &packet, &size ); - if(result != HasReturnvaluesIF::RETURN_OK) { - sif::error << "CCSDSDistributor::selectDestination: Getting data from" - "store failed!" << std::endl; - } - SpacePacketBase currentPacket(packet); - -// sif:: info << "CCSDSDistributor::selectDestination has packet with APID " -// << std::hex << currentPacket.getAPID() << std::dec << std::endl; - TcMqMapIter position = this->queueMap.find(currentPacket.getAPID()); - if ( position != this->queueMap.end() ) { - return position; - } else { - //The APID was not found. Forward packet to main SW-APID anyway to - // create acceptance failure report. - return this->queueMap.find( this->defaultApid ); - } -} - -MessageQueueId_t CCSDSDistributor::getRequestQueue() { - return tcQueue->getId(); -} - -ReturnValue_t CCSDSDistributor::registerApplication( - AcceptsTelecommandsIF* application) { - ReturnValue_t returnValue = RETURN_OK; - bool errorCode = true; - errorCode = this->queueMap.insert( std::pair( application->getIdentifier(), application->getRequestQueue() ) ).second; - if( errorCode == false ) { - returnValue = RETURN_FAILED; - } - return returnValue; -} - -ReturnValue_t CCSDSDistributor::registerApplication(uint16_t apid, - MessageQueueId_t id) { - ReturnValue_t returnValue = RETURN_OK; - bool errorCode = true; - errorCode = this->queueMap.insert( std::pair( apid, id ) ).second; - if( errorCode == false ) { - returnValue = RETURN_FAILED; - } - return returnValue; - -} - -uint16_t CCSDSDistributor::getIdentifier() { - return 0; -} - -ReturnValue_t CCSDSDistributor::initialize() { - ReturnValue_t status = this->TcDistributor::initialize(); - this->tcStore = objectManager->get( objects::TC_STORE ); - if (this->tcStore == NULL) status = RETURN_FAILED; - return status; -} - -ReturnValue_t CCSDSDistributor::callbackAfterSending( - ReturnValue_t queueStatus) { - if (queueStatus != RETURN_OK) { - tcStore->deleteData(currentMessage.getStorageId()); - } - return RETURN_OK; -} +#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../tcdistribution/CCSDSDistributor.h" +#include "../tmtcpacket/SpacePacketBase.h" + +CCSDSDistributor::CCSDSDistributor(uint16_t setDefaultApid, + object_id_t setObjectId): + TcDistributor(setObjectId), defaultApid( setDefaultApid ) { +} + +CCSDSDistributor::~CCSDSDistributor() {} + +TcDistributor::TcMqMapIter CCSDSDistributor::selectDestination() { +// sif::debug << "CCSDSDistributor::selectDestination received: " << +// this->currentMessage.getStorageId().pool_index << ", " << +// this->currentMessage.getStorageId().packet_index << std::endl; + const uint8_t* packet = nullptr; + size_t size = 0; + ReturnValue_t result = this->tcStore->getData(currentMessage.getStorageId(), + &packet, &size ); + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::error << "CCSDSDistributor::selectDestination: Getting data from" + "store failed!" << std::endl; + } + SpacePacketBase currentPacket(packet); + +// sif:: info << "CCSDSDistributor::selectDestination has packet with APID " +// << std::hex << currentPacket.getAPID() << std::dec << std::endl; + TcMqMapIter position = this->queueMap.find(currentPacket.getAPID()); + if ( position != this->queueMap.end() ) { + return position; + } else { + //The APID was not found. Forward packet to main SW-APID anyway to + // create acceptance failure report. + return this->queueMap.find( this->defaultApid ); + } +} + +MessageQueueId_t CCSDSDistributor::getRequestQueue() { + return tcQueue->getId(); +} + +ReturnValue_t CCSDSDistributor::registerApplication( + AcceptsTelecommandsIF* application) { + ReturnValue_t returnValue = RETURN_OK; + bool errorCode = true; + errorCode = this->queueMap.insert( std::pair( application->getIdentifier(), application->getRequestQueue() ) ).second; + if( errorCode == false ) { + returnValue = RETURN_FAILED; + } + return returnValue; +} + +ReturnValue_t CCSDSDistributor::registerApplication(uint16_t apid, + MessageQueueId_t id) { + ReturnValue_t returnValue = RETURN_OK; + bool errorCode = true; + errorCode = this->queueMap.insert( std::pair( apid, id ) ).second; + if( errorCode == false ) { + returnValue = RETURN_FAILED; + } + return returnValue; + +} + +uint16_t CCSDSDistributor::getIdentifier() { + return 0; +} + +ReturnValue_t CCSDSDistributor::initialize() { + ReturnValue_t status = this->TcDistributor::initialize(); + this->tcStore = objectManager->get( objects::TC_STORE ); + if (this->tcStore == NULL) status = RETURN_FAILED; + return status; +} + +ReturnValue_t CCSDSDistributor::callbackAfterSending( + ReturnValue_t queueStatus) { + if (queueStatus != RETURN_OK) { + tcStore->deleteData(currentMessage.getStorageId()); + } + return RETURN_OK; +} diff --git a/tcdistribution/CCSDSDistributor.h b/tcdistribution/CCSDSDistributor.h index 60877753..e54b9fe4 100644 --- a/tcdistribution/CCSDSDistributor.h +++ b/tcdistribution/CCSDSDistributor.h @@ -1,69 +1,69 @@ -#ifndef FRAMEWORK_TCDISTRIBUTION_CCSDSDISTRIBUTOR_H_ -#define FRAMEWORK_TCDISTRIBUTION_CCSDSDISTRIBUTOR_H_ - -#include -#include -#include -#include -#include - -/** - * @brief An instantiation of the CCSDSDistributorIF. - * @details - * It receives Space Packets, and selects a destination depending on the - * APID of the telecommands. - * The Secondary Header (with Service/Subservice) is ignored. - * @ingroup tc_distribution - */ -class CCSDSDistributor : public TcDistributor, - public CCSDSDistributorIF, - public AcceptsTelecommandsIF { -public: - /** - * @brief The constructor sets the default APID and calls the - * TcDistributor ctor with a certain object id. - * @details - * @c tcStore is set in the @c initialize method. - * @param setDefaultApid The default APID, where packets with unknown - * destination are sent to. - */ - CCSDSDistributor(uint16_t setDefaultApid, object_id_t setObjectId); - /** - * The destructor is empty. - */ - virtual ~CCSDSDistributor(); - - MessageQueueId_t getRequestQueue() override; - ReturnValue_t registerApplication( uint16_t apid, - MessageQueueId_t id) override; - ReturnValue_t registerApplication( - AcceptsTelecommandsIF* application) override; - uint16_t getIdentifier(); - ReturnValue_t initialize() override; - -protected: - /** - * This implementation checks if an application with fitting APID has - * registered and forwards the packet to the according message queue. - * If the packet is not found, it returns the queue to @c defaultApid, - * where a Acceptance Failure message should be generated. - * @return Iterator to map entry of found APID or iterator to default APID. - */ - TcMqMapIter selectDestination() override; - /** - * The default APID, where packets with unknown APID are sent to. - */ - uint16_t defaultApid; - /** - * A reference to the TC storage must be maintained, as this class handles - * pure Space Packets and there exists no SpacePacketStored class. - */ - StorageManagerIF* tcStore = nullptr; - /** - * The callback here handles the generation of acceptance - * success/failure messages. - */ - ReturnValue_t callbackAfterSending( ReturnValue_t queueStatus ); -}; - -#endif /* FRAMEWORK_TCDISTRIBUTION_CCSDSDISTRIBUTOR_H_ */ +#ifndef FRAMEWORK_TCDISTRIBUTION_CCSDSDISTRIBUTOR_H_ +#define FRAMEWORK_TCDISTRIBUTION_CCSDSDISTRIBUTOR_H_ + +#include "../objectmanager/ObjectManagerIF.h" +#include "../storagemanager/StorageManagerIF.h" +#include "../tcdistribution/CCSDSDistributorIF.h" +#include "../tcdistribution/TcDistributor.h" +#include "../tmtcservices/AcceptsTelecommandsIF.h" + +/** + * @brief An instantiation of the CCSDSDistributorIF. + * @details + * It receives Space Packets, and selects a destination depending on the + * APID of the telecommands. + * The Secondary Header (with Service/Subservice) is ignored. + * @ingroup tc_distribution + */ +class CCSDSDistributor : public TcDistributor, + public CCSDSDistributorIF, + public AcceptsTelecommandsIF { +public: + /** + * @brief The constructor sets the default APID and calls the + * TcDistributor ctor with a certain object id. + * @details + * @c tcStore is set in the @c initialize method. + * @param setDefaultApid The default APID, where packets with unknown + * destination are sent to. + */ + CCSDSDistributor(uint16_t setDefaultApid, object_id_t setObjectId); + /** + * The destructor is empty. + */ + virtual ~CCSDSDistributor(); + + MessageQueueId_t getRequestQueue() override; + ReturnValue_t registerApplication( uint16_t apid, + MessageQueueId_t id) override; + ReturnValue_t registerApplication( + AcceptsTelecommandsIF* application) override; + uint16_t getIdentifier(); + ReturnValue_t initialize() override; + +protected: + /** + * This implementation checks if an application with fitting APID has + * registered and forwards the packet to the according message queue. + * If the packet is not found, it returns the queue to @c defaultApid, + * where a Acceptance Failure message should be generated. + * @return Iterator to map entry of found APID or iterator to default APID. + */ + TcMqMapIter selectDestination() override; + /** + * The default APID, where packets with unknown APID are sent to. + */ + uint16_t defaultApid; + /** + * A reference to the TC storage must be maintained, as this class handles + * pure Space Packets and there exists no SpacePacketStored class. + */ + StorageManagerIF* tcStore = nullptr; + /** + * The callback here handles the generation of acceptance + * success/failure messages. + */ + ReturnValue_t callbackAfterSending( ReturnValue_t queueStatus ); +}; + +#endif /* FRAMEWORK_TCDISTRIBUTION_CCSDSDISTRIBUTOR_H_ */ diff --git a/tcdistribution/CCSDSDistributorIF.h b/tcdistribution/CCSDSDistributorIF.h index dc1263a9..32198120 100644 --- a/tcdistribution/CCSDSDistributorIF.h +++ b/tcdistribution/CCSDSDistributorIF.h @@ -1,40 +1,40 @@ -#ifndef CCSDSDISTRIBUTORIF_H_ -#define CCSDSDISTRIBUTORIF_H_ - -#include -#include -/** - * This is the Interface to a CCSDS Distributor. - * On a CCSDS Distributor, Applications (in terms of CCSDS) may register themselves, - * either by passing a pointer to themselves (and implementing the CCSDSApplicationIF, - * or by explicitly passing an APID and a MessageQueueId to route the TC's to. - * \ingroup tc_distribution - */ -class CCSDSDistributorIF { -public: - /** - * With this call, a class implementing the CCSDSApplicationIF can register at the - * distributor. - * @param application A pointer to the Application to register. - * @return - \c RETURN_OK on success, - * - \c RETURN_FAILED on failure. - */ - virtual ReturnValue_t registerApplication( AcceptsTelecommandsIF* application ) = 0; - /** - * With this call, other Applications can register to the CCSDS distributor. - * This is done by passing an APID and a MessageQueueId to the method. - * @param apid The APID to register. - * @param id The MessageQueueId of the message queue to send the TC Packets to. - * @return - \c RETURN_OK on success, - * - \c RETURN_FAILED on failure. - */ - virtual ReturnValue_t registerApplication( uint16_t apid, MessageQueueId_t id ) = 0; - /** - * The empty virtual destructor. - */ - virtual ~CCSDSDistributorIF() { - } -}; - - -#endif /* CCSDSDISTRIBUTORIF_H_ */ +#ifndef CCSDSDISTRIBUTORIF_H_ +#define CCSDSDISTRIBUTORIF_H_ + +#include "../tmtcservices/AcceptsTelecommandsIF.h" +#include "../ipc/MessageQueueSenderIF.h" +/** + * This is the Interface to a CCSDS Distributor. + * On a CCSDS Distributor, Applications (in terms of CCSDS) may register themselves, + * either by passing a pointer to themselves (and implementing the CCSDSApplicationIF, + * or by explicitly passing an APID and a MessageQueueId to route the TC's to. + * \ingroup tc_distribution + */ +class CCSDSDistributorIF { +public: + /** + * With this call, a class implementing the CCSDSApplicationIF can register at the + * distributor. + * @param application A pointer to the Application to register. + * @return - \c RETURN_OK on success, + * - \c RETURN_FAILED on failure. + */ + virtual ReturnValue_t registerApplication( AcceptsTelecommandsIF* application ) = 0; + /** + * With this call, other Applications can register to the CCSDS distributor. + * This is done by passing an APID and a MessageQueueId to the method. + * @param apid The APID to register. + * @param id The MessageQueueId of the message queue to send the TC Packets to. + * @return - \c RETURN_OK on success, + * - \c RETURN_FAILED on failure. + */ + virtual ReturnValue_t registerApplication( uint16_t apid, MessageQueueId_t id ) = 0; + /** + * The empty virtual destructor. + */ + virtual ~CCSDSDistributorIF() { + } +}; + + +#endif /* CCSDSDISTRIBUTORIF_H_ */ diff --git a/tcdistribution/PUSDistributor.cpp b/tcdistribution/PUSDistributor.cpp index 5eb50103..fee16f11 100644 --- a/tcdistribution/PUSDistributor.cpp +++ b/tcdistribution/PUSDistributor.cpp @@ -1,92 +1,92 @@ -#include -#include -#include -#include -#include - -PUSDistributor::PUSDistributor(uint16_t setApid, object_id_t setObjectId, - object_id_t setPacketSource) : - TcDistributor(setObjectId), checker(setApid), verifyChannel(), - currentPacket(), tcStatus(RETURN_FAILED), - packetSource(setPacketSource) {} - -PUSDistributor::~PUSDistributor() {} - -TcDistributor::TcMqMapIter PUSDistributor::selectDestination() { - TcMqMapIter queueMapIt = this->queueMap.end(); - this->currentPacket.setStoreAddress(this->currentMessage.getStorageId()); - if (currentPacket.getWholeData() != NULL) { - tcStatus = checker.checkPacket(¤tPacket); -// sif::debug << "PUSDistributor::handlePacket: packetCheck returned with " -// << (int)tcStatus << std::endl; - uint32_t queue_id = currentPacket.getService(); - queueMapIt = this->queueMap.find(queue_id); - } else { - tcStatus = PACKET_LOST; - } - if (queueMapIt == this->queueMap.end()) { - tcStatus = DESTINATION_NOT_FOUND; - } - - if (tcStatus != RETURN_OK) { - sif::debug << "PUSDistributor::handlePacket: Error with " << tcStatus - << ", 0x"<< std::hex << tcStatus << std::dec << std::endl; - return this->queueMap.end(); - } else { - return queueMapIt; - } - -} - -//uint16_t PUSDistributor::createDestination( uint8_t service_id, uint8_t subservice_id ) { -// return ( service_id << 8 ) + subservice_id; -//} - -ReturnValue_t PUSDistributor::registerService(AcceptsTelecommandsIF* service) { - uint16_t serviceId = service->getIdentifier(); - //info << "Service ID: " << (int)serviceId << std::endl; - MessageQueueId_t queue = service->getRequestQueue(); - auto returnPair = queueMap.emplace(serviceId, queue); - if (not returnPair.second) { - //TODO Return Code - sif::error << "PUSDistributor::registerService: Service ID already" - " exists in map." << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - return HasReturnvaluesIF::RETURN_OK; -} - -MessageQueueId_t PUSDistributor::getRequestQueue() { - return tcQueue->getId(); -} - -ReturnValue_t PUSDistributor::callbackAfterSending(ReturnValue_t queueStatus) { - if (queueStatus != RETURN_OK) { - tcStatus = queueStatus; - } - if (tcStatus != RETURN_OK) { - this->verifyChannel.sendFailureReport(TC_VERIFY::ACCEPTANCE_FAILURE, - ¤tPacket, tcStatus); - //A failed packet is deleted immediately after reporting, otherwise it will block memory. - currentPacket.deletePacket(); - return RETURN_FAILED; - } else { - this->verifyChannel.sendSuccessReport(TC_VERIFY::ACCEPTANCE_SUCCESS, - ¤tPacket); - return RETURN_OK; - } -} - -uint16_t PUSDistributor::getIdentifier() { - return checker.getApid(); -} - -ReturnValue_t PUSDistributor::initialize() { - CCSDSDistributorIF* ccsdsDistributor = - objectManager->get(packetSource); - if (ccsdsDistributor == NULL) { - return RETURN_FAILED; - } else { - return ccsdsDistributor->registerApplication(this); - } -} +#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../tcdistribution/CCSDSDistributorIF.h" +#include "../tcdistribution/PUSDistributor.h" +#include "../tmtcpacket/pus/TcPacketStored.h" +#include "../tmtcservices/PusVerificationReport.h" + +PUSDistributor::PUSDistributor(uint16_t setApid, object_id_t setObjectId, + object_id_t setPacketSource) : + TcDistributor(setObjectId), checker(setApid), verifyChannel(), + currentPacket(), tcStatus(RETURN_FAILED), + packetSource(setPacketSource) {} + +PUSDistributor::~PUSDistributor() {} + +TcDistributor::TcMqMapIter PUSDistributor::selectDestination() { + TcMqMapIter queueMapIt = this->queueMap.end(); + this->currentPacket.setStoreAddress(this->currentMessage.getStorageId()); + if (currentPacket.getWholeData() != NULL) { + tcStatus = checker.checkPacket(¤tPacket); +// sif::debug << "PUSDistributor::handlePacket: packetCheck returned with " +// << (int)tcStatus << std::endl; + uint32_t queue_id = currentPacket.getService(); + queueMapIt = this->queueMap.find(queue_id); + } else { + tcStatus = PACKET_LOST; + } + if (queueMapIt == this->queueMap.end()) { + tcStatus = DESTINATION_NOT_FOUND; + } + + if (tcStatus != RETURN_OK) { + sif::debug << "PUSDistributor::handlePacket: Error with " << tcStatus + << ", 0x"<< std::hex << tcStatus << std::dec << std::endl; + return this->queueMap.end(); + } else { + return queueMapIt; + } + +} + +//uint16_t PUSDistributor::createDestination( uint8_t service_id, uint8_t subservice_id ) { +// return ( service_id << 8 ) + subservice_id; +//} + +ReturnValue_t PUSDistributor::registerService(AcceptsTelecommandsIF* service) { + uint16_t serviceId = service->getIdentifier(); + //info << "Service ID: " << (int)serviceId << std::endl; + MessageQueueId_t queue = service->getRequestQueue(); + auto returnPair = queueMap.emplace(serviceId, queue); + if (not returnPair.second) { + //TODO Return Code + sif::error << "PUSDistributor::registerService: Service ID already" + " exists in map." << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; +} + +MessageQueueId_t PUSDistributor::getRequestQueue() { + return tcQueue->getId(); +} + +ReturnValue_t PUSDistributor::callbackAfterSending(ReturnValue_t queueStatus) { + if (queueStatus != RETURN_OK) { + tcStatus = queueStatus; + } + if (tcStatus != RETURN_OK) { + this->verifyChannel.sendFailureReport(TC_VERIFY::ACCEPTANCE_FAILURE, + ¤tPacket, tcStatus); + //A failed packet is deleted immediately after reporting, otherwise it will block memory. + currentPacket.deletePacket(); + return RETURN_FAILED; + } else { + this->verifyChannel.sendSuccessReport(TC_VERIFY::ACCEPTANCE_SUCCESS, + ¤tPacket); + return RETURN_OK; + } +} + +uint16_t PUSDistributor::getIdentifier() { + return checker.getApid(); +} + +ReturnValue_t PUSDistributor::initialize() { + CCSDSDistributorIF* ccsdsDistributor = + objectManager->get(packetSource); + if (ccsdsDistributor == NULL) { + return RETURN_FAILED; + } else { + return ccsdsDistributor->registerApplication(this); + } +} diff --git a/tcdistribution/PUSDistributor.h b/tcdistribution/PUSDistributor.h index 4a22f936..be84de1b 100644 --- a/tcdistribution/PUSDistributor.h +++ b/tcdistribution/PUSDistributor.h @@ -1,77 +1,77 @@ -#ifndef FRAMEWORK_TCDISTRIBUTION_PUSDISTRIBUTOR_H_ -#define FRAMEWORK_TCDISTRIBUTION_PUSDISTRIBUTOR_H_ - -#include -#include -#include -#include -#include -#include - -/** - * This class accepts PUS Telecommands and forwards them to Application - * services. In addition, the class performs a formal packet check and - * sends acceptance success or failure messages. - * @ingroup tc_distribution - */ -class PUSDistributor: public TcDistributor, - public PUSDistributorIF, - public AcceptsTelecommandsIF { -public: - /** - * The ctor passes @c set_apid to the checker class and calls the - * TcDistribution ctor with a certain object id. - * @param setApid The APID of this receiving Application. - * @param setObjectId Object ID of the distributor itself - * @param setPacketSource Object ID of the source of TC packets. - * Must implement CCSDSDistributorIF. - */ - PUSDistributor(uint16_t setApid, object_id_t setObjectId, - object_id_t setPacketSource); - /** - * The destructor is empty. - */ - virtual ~PUSDistributor(); - ReturnValue_t registerService(AcceptsTelecommandsIF* service) override; - MessageQueueId_t getRequestQueue() override; - ReturnValue_t initialize() override; - uint16_t getIdentifier() override; - -protected: - /** - * This attribute contains the class, that performs a formal packet check. - */ - TcPacketCheck checker; - /** - * With this class, verification messages are sent to the - * TC Verification service. - */ - VerificationReporter verifyChannel; - /** - * The currently handled packet is stored here. - */ - TcPacketStored currentPacket; - /** - * With this variable, the current check status is stored to generate - * acceptance messages later. - */ - ReturnValue_t tcStatus; - - const object_id_t packetSource; - /** - * This method reads the packet service, checks if such a service is - * registered and forwards the packet to the destination. - * It also initiates the formal packet check and sending of verification - * messages. - * @return Iterator to map entry of found service id - * or iterator to @c map.end(). - */ - TcMqMapIter selectDestination() override; - /** - * The callback here handles the generation of acceptance - * success/failure messages. - */ - ReturnValue_t callbackAfterSending(ReturnValue_t queueStatus); -}; - -#endif /* FRAMEWORK_TCDISTRIBUTION_PUSDISTRIBUTOR_H_ */ +#ifndef FRAMEWORK_TCDISTRIBUTION_PUSDISTRIBUTOR_H_ +#define FRAMEWORK_TCDISTRIBUTION_PUSDISTRIBUTOR_H_ + +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../tcdistribution/PUSDistributorIF.h" +#include "../tcdistribution/TcDistributor.h" +#include "../tcdistribution/TcPacketCheck.h" +#include "../tmtcservices/AcceptsTelecommandsIF.h" +#include "../tmtcservices/VerificationReporter.h" + +/** + * This class accepts PUS Telecommands and forwards them to Application + * services. In addition, the class performs a formal packet check and + * sends acceptance success or failure messages. + * @ingroup tc_distribution + */ +class PUSDistributor: public TcDistributor, + public PUSDistributorIF, + public AcceptsTelecommandsIF { +public: + /** + * The ctor passes @c set_apid to the checker class and calls the + * TcDistribution ctor with a certain object id. + * @param setApid The APID of this receiving Application. + * @param setObjectId Object ID of the distributor itself + * @param setPacketSource Object ID of the source of TC packets. + * Must implement CCSDSDistributorIF. + */ + PUSDistributor(uint16_t setApid, object_id_t setObjectId, + object_id_t setPacketSource); + /** + * The destructor is empty. + */ + virtual ~PUSDistributor(); + ReturnValue_t registerService(AcceptsTelecommandsIF* service) override; + MessageQueueId_t getRequestQueue() override; + ReturnValue_t initialize() override; + uint16_t getIdentifier() override; + +protected: + /** + * This attribute contains the class, that performs a formal packet check. + */ + TcPacketCheck checker; + /** + * With this class, verification messages are sent to the + * TC Verification service. + */ + VerificationReporter verifyChannel; + /** + * The currently handled packet is stored here. + */ + TcPacketStored currentPacket; + /** + * With this variable, the current check status is stored to generate + * acceptance messages later. + */ + ReturnValue_t tcStatus; + + const object_id_t packetSource; + /** + * This method reads the packet service, checks if such a service is + * registered and forwards the packet to the destination. + * It also initiates the formal packet check and sending of verification + * messages. + * @return Iterator to map entry of found service id + * or iterator to @c map.end(). + */ + TcMqMapIter selectDestination() override; + /** + * The callback here handles the generation of acceptance + * success/failure messages. + */ + ReturnValue_t callbackAfterSending(ReturnValue_t queueStatus); +}; + +#endif /* FRAMEWORK_TCDISTRIBUTION_PUSDISTRIBUTOR_H_ */ diff --git a/tcdistribution/PUSDistributorIF.h b/tcdistribution/PUSDistributorIF.h index bb101137..7967a74e 100644 --- a/tcdistribution/PUSDistributorIF.h +++ b/tcdistribution/PUSDistributorIF.h @@ -1,26 +1,26 @@ -#ifndef PUSDISTRIBUTORIF_H_ -#define PUSDISTRIBUTORIF_H_ - -#include -#include -/** - * This interface allows PUS Services to register themselves at a PUS Distributor. - * \ingroup tc_distribution - */ -class PUSDistributorIF { -public: - /** - * The empty virtual destructor. - */ - virtual ~PUSDistributorIF() { - } -/** - * With this method, Services can register themselves at the PUS Distributor. - * @param service A pointer to the registering Service. - * @return - \c RETURN_OK on success, - * - \c RETURN_FAILED on failure. - */ - virtual ReturnValue_t registerService( AcceptsTelecommandsIF* service ) = 0; -}; - -#endif /* PUSDISTRIBUTORIF_H_ */ +#ifndef PUSDISTRIBUTORIF_H_ +#define PUSDISTRIBUTORIF_H_ + +#include "../tmtcservices/AcceptsTelecommandsIF.h" +#include "../ipc/MessageQueueSenderIF.h" +/** + * This interface allows PUS Services to register themselves at a PUS Distributor. + * \ingroup tc_distribution + */ +class PUSDistributorIF { +public: + /** + * The empty virtual destructor. + */ + virtual ~PUSDistributorIF() { + } +/** + * With this method, Services can register themselves at the PUS Distributor. + * @param service A pointer to the registering Service. + * @return - \c RETURN_OK on success, + * - \c RETURN_FAILED on failure. + */ + virtual ReturnValue_t registerService( AcceptsTelecommandsIF* service ) = 0; +}; + +#endif /* PUSDISTRIBUTORIF_H_ */ diff --git a/tcdistribution/TcDistributor.cpp b/tcdistribution/TcDistributor.cpp index 0190cc97..45a20fd9 100644 --- a/tcdistribution/TcDistributor.cpp +++ b/tcdistribution/TcDistributor.cpp @@ -1,54 +1,54 @@ -#include -#include -#include -#include -#include - -TcDistributor::TcDistributor(object_id_t set_object_id) : - SystemObject(set_object_id), tcQueue(NULL) { - tcQueue = QueueFactory::instance()->createMessageQueue(DISTRIBUTER_MAX_PACKETS); -} - -TcDistributor::~TcDistributor() { - QueueFactory::instance()->deleteMessageQueue(tcQueue); -} - -ReturnValue_t TcDistributor::performOperation(uint8_t opCode) { - ReturnValue_t status = RETURN_OK; - for (status = tcQueue->receiveMessage(¤tMessage); status == RETURN_OK; - status = tcQueue->receiveMessage(¤tMessage)) { - status = handlePacket(); - } - if (status == MessageQueueIF::EMPTY) { - return RETURN_OK; - } else { - return status; - } -} - -ReturnValue_t TcDistributor::handlePacket() { - - TcMqMapIter queueMapIt = this->selectDestination(); - ReturnValue_t returnValue = RETURN_FAILED; - if (queueMapIt != this->queueMap.end()) { - returnValue = this->tcQueue->sendMessage(queueMapIt->second, - &this->currentMessage); - } - return this->callbackAfterSending(returnValue); -} - -void TcDistributor::print() { - sif::debug << "Distributor content is: " << std::endl << "ID\t| message queue id" - << std::endl; - for (TcMqMapIter it = this->queueMap.begin(); it != this->queueMap.end(); - it++) { - sif::debug << it->first << "\t| 0x" << std::hex << it->second << std::dec - << std::endl; - } - sif::debug << std::dec; - -} - -ReturnValue_t TcDistributor::callbackAfterSending(ReturnValue_t queueStatus) { - return RETURN_OK; -} +#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../tcdistribution/TcDistributor.h" +#include "../tmtcservices/TmTcMessage.h" +#include "../ipc/QueueFactory.h" + +TcDistributor::TcDistributor(object_id_t set_object_id) : + SystemObject(set_object_id), tcQueue(NULL) { + tcQueue = QueueFactory::instance()->createMessageQueue(DISTRIBUTER_MAX_PACKETS); +} + +TcDistributor::~TcDistributor() { + QueueFactory::instance()->deleteMessageQueue(tcQueue); +} + +ReturnValue_t TcDistributor::performOperation(uint8_t opCode) { + ReturnValue_t status = RETURN_OK; + for (status = tcQueue->receiveMessage(¤tMessage); status == RETURN_OK; + status = tcQueue->receiveMessage(¤tMessage)) { + status = handlePacket(); + } + if (status == MessageQueueIF::EMPTY) { + return RETURN_OK; + } else { + return status; + } +} + +ReturnValue_t TcDistributor::handlePacket() { + + TcMqMapIter queueMapIt = this->selectDestination(); + ReturnValue_t returnValue = RETURN_FAILED; + if (queueMapIt != this->queueMap.end()) { + returnValue = this->tcQueue->sendMessage(queueMapIt->second, + &this->currentMessage); + } + return this->callbackAfterSending(returnValue); +} + +void TcDistributor::print() { + sif::debug << "Distributor content is: " << std::endl << "ID\t| message queue id" + << std::endl; + for (TcMqMapIter it = this->queueMap.begin(); it != this->queueMap.end(); + it++) { + sif::debug << it->first << "\t| 0x" << std::hex << it->second << std::dec + << std::endl; + } + sif::debug << std::dec; + +} + +ReturnValue_t TcDistributor::callbackAfterSending(ReturnValue_t queueStatus) { + return RETURN_OK; +} diff --git a/tcdistribution/TcDistributor.h b/tcdistribution/TcDistributor.h index 73425302..987f2eaa 100644 --- a/tcdistribution/TcDistributor.h +++ b/tcdistribution/TcDistributor.h @@ -1,120 +1,120 @@ -#ifndef FRAMEWORK_TMTCSERVICES_TCDISTRIBUTOR_H_ -#define FRAMEWORK_TMTCSERVICES_TCDISTRIBUTOR_H_ - -#include -#include -#include -#include -#include -#include -#include -#include - -/** - * @defgroup tc_distribution Telecommand Distribution - * All classes associated with Routing and Distribution of Telecommands - * belong to this group. - */ - - -/** - * This is the base class to implement distributors for Space Packets. - * Typically, the distribution is required to forward Telecommand packets - * over the satellite applications and services. The class receives - * Space Packets over a message queue and holds a map that links other - * message queue ids to some identifier. The process of unpacking the - * destination information from the packet is handled by the child class - * implementations. - * @ingroup tc_distribution - */ -class TcDistributor : public SystemObject, - public ExecutableObjectIF, - public HasReturnvaluesIF { -public: - using TcMessageQueueMap = std::map; - using TcMqMapIter = std::map::iterator; - - static const uint8_t INTERFACE_ID = CLASS_ID::PACKET_DISTRIBUTION; - static const ReturnValue_t PACKET_LOST = MAKE_RETURN_CODE( 1 ); - static const ReturnValue_t DESTINATION_NOT_FOUND = MAKE_RETURN_CODE( 2 ); - /** - * Within the default constructor, the SystemObject id is set and the - * message queue is initialized. - * Filling the map is under control of the child classes. - * @param set_object_id This id is assigned to the distributor - * implementation. - */ - TcDistributor( object_id_t set_object_id ); - /** - * The destructor is empty, the message queues are not in the vicinity of - * this class. - */ - virtual ~TcDistributor(); - /** - * The method is called cyclically and fetches new incoming packets from - * the message queue. - * In case a new packet is found, it calls the handlePacket method to deal - * with distribution. - * @return The error code of the message queue call. - */ - ReturnValue_t performOperation(uint8_t opCode); - /** - * A simple debug print, that prints all distribution information stored in - * queueMap. - */ - void print(); - -protected: - /** - * This is the receiving queue for incoming Telecommands. - * The child classes must make its queue id public. - */ - MessageQueueIF* tcQueue; - /** - * The last received incoming packet information is stored in this - * member. - * As different child classes unpack the incoming packet differently - * (i.e. as a CCSDS Space Packet or as a PUS Telecommand Packet), it - * is not tried to unpack the packet information within this class. - */ - TmTcMessage currentMessage; - /** - * The map that links certain packet information to a destination. - * The packet information may be the APID of the packet or the service - * identifier. Filling of the map is under control of the different child - * classes. - */ - TcMessageQueueMap queueMap; - /** - * This method shall unpack the routing information from the incoming - * packet and select the map entry which represents the packet's target. - * @return An iterator to the map element to forward to or queuMap.end(). - */ - virtual TcMqMapIter selectDestination() = 0; - /** - * The handlePacket method calls the child class's selectDestination method - * and forwards the packet to its destination, if found. - * @return The message queue return value or \c RETURN_FAILED, in case no - * destination was found. - */ - ReturnValue_t handlePacket(); - /** - * This method gives the child class a chance to perform some kind of operation - * after the parent tried to forward the message. - * A typically application would be sending success/failure messages. - * The default implementation just returns \c RETURN_OK. - * @param queueStatus The status of the message queue after an attempt to send the TC. - * @return - \c RETURN_OK on success - * - \c RETURN_FAILED on failure - */ - virtual ReturnValue_t callbackAfterSending( ReturnValue_t queueStatus ); - -private: - /** - * This constant sets the maximum number of packets distributed per call. - */ - static const uint8_t DISTRIBUTER_MAX_PACKETS = 128; -}; - - -#endif /* TCDISTRIBUTOR_H_ */ +#ifndef FRAMEWORK_TMTCSERVICES_TCDISTRIBUTOR_H_ +#define FRAMEWORK_TMTCSERVICES_TCDISTRIBUTOR_H_ + +#include "../objectmanager/ObjectManagerIF.h" +#include "../objectmanager/SystemObject.h" +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../storagemanager/StorageManagerIF.h" +#include "../tasks/ExecutableObjectIF.h" +#include "../tmtcservices/TmTcMessage.h" +#include "../ipc/MessageQueueIF.h" +#include + +/** + * @defgroup tc_distribution Telecommand Distribution + * All classes associated with Routing and Distribution of Telecommands + * belong to this group. + */ + + +/** + * This is the base class to implement distributors for Space Packets. + * Typically, the distribution is required to forward Telecommand packets + * over the satellite applications and services. The class receives + * Space Packets over a message queue and holds a map that links other + * message queue ids to some identifier. The process of unpacking the + * destination information from the packet is handled by the child class + * implementations. + * @ingroup tc_distribution + */ +class TcDistributor : public SystemObject, + public ExecutableObjectIF, + public HasReturnvaluesIF { +public: + using TcMessageQueueMap = std::map; + using TcMqMapIter = std::map::iterator; + + static const uint8_t INTERFACE_ID = CLASS_ID::PACKET_DISTRIBUTION; + static const ReturnValue_t PACKET_LOST = MAKE_RETURN_CODE( 1 ); + static const ReturnValue_t DESTINATION_NOT_FOUND = MAKE_RETURN_CODE( 2 ); + /** + * Within the default constructor, the SystemObject id is set and the + * message queue is initialized. + * Filling the map is under control of the child classes. + * @param set_object_id This id is assigned to the distributor + * implementation. + */ + TcDistributor( object_id_t set_object_id ); + /** + * The destructor is empty, the message queues are not in the vicinity of + * this class. + */ + virtual ~TcDistributor(); + /** + * The method is called cyclically and fetches new incoming packets from + * the message queue. + * In case a new packet is found, it calls the handlePacket method to deal + * with distribution. + * @return The error code of the message queue call. + */ + ReturnValue_t performOperation(uint8_t opCode); + /** + * A simple debug print, that prints all distribution information stored in + * queueMap. + */ + void print(); + +protected: + /** + * This is the receiving queue for incoming Telecommands. + * The child classes must make its queue id public. + */ + MessageQueueIF* tcQueue; + /** + * The last received incoming packet information is stored in this + * member. + * As different child classes unpack the incoming packet differently + * (i.e. as a CCSDS Space Packet or as a PUS Telecommand Packet), it + * is not tried to unpack the packet information within this class. + */ + TmTcMessage currentMessage; + /** + * The map that links certain packet information to a destination. + * The packet information may be the APID of the packet or the service + * identifier. Filling of the map is under control of the different child + * classes. + */ + TcMessageQueueMap queueMap; + /** + * This method shall unpack the routing information from the incoming + * packet and select the map entry which represents the packet's target. + * @return An iterator to the map element to forward to or queuMap.end(). + */ + virtual TcMqMapIter selectDestination() = 0; + /** + * The handlePacket method calls the child class's selectDestination method + * and forwards the packet to its destination, if found. + * @return The message queue return value or \c RETURN_FAILED, in case no + * destination was found. + */ + ReturnValue_t handlePacket(); + /** + * This method gives the child class a chance to perform some kind of operation + * after the parent tried to forward the message. + * A typically application would be sending success/failure messages. + * The default implementation just returns \c RETURN_OK. + * @param queueStatus The status of the message queue after an attempt to send the TC. + * @return - \c RETURN_OK on success + * - \c RETURN_FAILED on failure + */ + virtual ReturnValue_t callbackAfterSending( ReturnValue_t queueStatus ); + +private: + /** + * This constant sets the maximum number of packets distributed per call. + */ + static const uint8_t DISTRIBUTER_MAX_PACKETS = 128; +}; + + +#endif /* TCDISTRIBUTOR_H_ */ diff --git a/tcdistribution/TcPacketCheck.cpp b/tcdistribution/TcPacketCheck.cpp index 90a1167f..98dfaeb8 100644 --- a/tcdistribution/TcPacketCheck.cpp +++ b/tcdistribution/TcPacketCheck.cpp @@ -1,37 +1,37 @@ -#include -#include -#include -#include -#include - -TcPacketCheck::TcPacketCheck( uint16_t set_apid ) : apid(set_apid) { -} - -ReturnValue_t TcPacketCheck::checkPacket( TcPacketStored* current_packet ) { - uint16_t calculated_crc = CRC::crc16ccitt( current_packet->getWholeData(), current_packet->getFullSize() ); - if ( calculated_crc != 0 ) { - return INCORRECT_CHECKSUM; - } - bool condition = !(current_packet->hasSecondaryHeader()) || - current_packet->getPacketVersionNumber() != CCSDS_VERSION_NUMBER || - !(current_packet->isTelecommand()); - if ( condition ) { - return INCORRECT_PRIMARY_HEADER; - } - if ( current_packet->getAPID() != this->apid ) - return ILLEGAL_APID; - - if ( !current_packet->isSizeCorrect() ) { - return INCOMPLETE_PACKET; - } - condition = (current_packet->getSecondaryHeaderFlag() != CCSDS_SECONDARY_HEADER_FLAG) || - (current_packet->getPusVersionNumber() != PUS_VERSION_NUMBER); - if ( condition ) { - return INCORRECT_SECONDARY_HEADER; - } - return RETURN_OK; -} - -uint16_t TcPacketCheck::getApid() const { - return apid; -} +#include "../globalfunctions/CRC.h" +#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../storagemanager/StorageManagerIF.h" +#include "../tcdistribution/TcPacketCheck.h" +#include "../tmtcservices/VerificationCodes.h" + +TcPacketCheck::TcPacketCheck( uint16_t set_apid ) : apid(set_apid) { +} + +ReturnValue_t TcPacketCheck::checkPacket( TcPacketStored* current_packet ) { + uint16_t calculated_crc = CRC::crc16ccitt( current_packet->getWholeData(), current_packet->getFullSize() ); + if ( calculated_crc != 0 ) { + return INCORRECT_CHECKSUM; + } + bool condition = !(current_packet->hasSecondaryHeader()) || + current_packet->getPacketVersionNumber() != CCSDS_VERSION_NUMBER || + !(current_packet->isTelecommand()); + if ( condition ) { + return INCORRECT_PRIMARY_HEADER; + } + if ( current_packet->getAPID() != this->apid ) + return ILLEGAL_APID; + + if ( !current_packet->isSizeCorrect() ) { + return INCOMPLETE_PACKET; + } + condition = (current_packet->getSecondaryHeaderFlag() != CCSDS_SECONDARY_HEADER_FLAG) || + (current_packet->getPusVersionNumber() != PUS_VERSION_NUMBER); + if ( condition ) { + return INCORRECT_SECONDARY_HEADER; + } + return RETURN_OK; +} + +uint16_t TcPacketCheck::getApid() const { + return apid; +} diff --git a/tcdistribution/TcPacketCheck.h b/tcdistribution/TcPacketCheck.h index 88810ed7..9fe1db72 100644 --- a/tcdistribution/TcPacketCheck.h +++ b/tcdistribution/TcPacketCheck.h @@ -1,59 +1,59 @@ -#ifndef TCPACKETCHECK_H_ -#define TCPACKETCHECK_H_ - -#include -#include -#include -/** - * This class performs a formal packet check for incoming PUS Telecommand Packets. - * Currently, it only checks if the APID and CRC are correct. - * \ingroup tc_distribution - */ -class TcPacketCheck : public HasReturnvaluesIF { -protected: - /** - * Describes the version number a packet must have to pass. - */ - static const uint8_t CCSDS_VERSION_NUMBER = 0; - /** - * Describes the secondary header a packet must have to pass. - */ - static const uint8_t CCSDS_SECONDARY_HEADER_FLAG = 0; - /** - * Describes the TC Packet PUS Version Number a packet must have to pass. - */ - static const uint8_t PUS_VERSION_NUMBER = 1; - /** - * The packet id each correct packet should have. - * It is composed of the APID and some static fields. - */ - uint16_t apid; -public: - static const uint8_t INTERFACE_ID = CLASS_ID::TC_PACKET_CHECK; - static const ReturnValue_t ILLEGAL_APID = MAKE_RETURN_CODE( 0 ); - static const ReturnValue_t INCOMPLETE_PACKET = MAKE_RETURN_CODE( 1 ); - static const ReturnValue_t INCORRECT_CHECKSUM = MAKE_RETURN_CODE( 2 ); - static const ReturnValue_t ILLEGAL_PACKET_TYPE = MAKE_RETURN_CODE( 3 ); - static const ReturnValue_t ILLEGAL_PACKET_SUBTYPE = MAKE_RETURN_CODE( 4 ); - static const ReturnValue_t INCORRECT_PRIMARY_HEADER = MAKE_RETURN_CODE( 5 ); - static const ReturnValue_t INCORRECT_SECONDARY_HEADER = MAKE_RETURN_CODE( 6 ); - /** - * The constructor only sets the APID attribute. - * @param set_apid The APID to set. - */ - TcPacketCheck( uint16_t set_apid ); - /** - * This is the actual method to formally check a certain Telecommand Packet. - * The packet's Application Data can not be checked here. - * @param current_packet The packt to check - * @return - \c RETURN_OK on success. - * - \c INCORRECT_CHECKSUM if checksum is invalid. - * - \c ILLEGAL_APID if APID does not match. - */ - ReturnValue_t checkPacket( TcPacketStored* current_packet ); - - uint16_t getApid() const; -}; - - -#endif /* TCPACKETCHECK_H_ */ +#ifndef TCPACKETCHECK_H_ +#define TCPACKETCHECK_H_ + +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../tmtcpacket/pus/TcPacketStored.h" +#include "../tmtcservices/PusVerificationReport.h" +/** + * This class performs a formal packet check for incoming PUS Telecommand Packets. + * Currently, it only checks if the APID and CRC are correct. + * \ingroup tc_distribution + */ +class TcPacketCheck : public HasReturnvaluesIF { +protected: + /** + * Describes the version number a packet must have to pass. + */ + static const uint8_t CCSDS_VERSION_NUMBER = 0; + /** + * Describes the secondary header a packet must have to pass. + */ + static const uint8_t CCSDS_SECONDARY_HEADER_FLAG = 0; + /** + * Describes the TC Packet PUS Version Number a packet must have to pass. + */ + static const uint8_t PUS_VERSION_NUMBER = 1; + /** + * The packet id each correct packet should have. + * It is composed of the APID and some static fields. + */ + uint16_t apid; +public: + static const uint8_t INTERFACE_ID = CLASS_ID::TC_PACKET_CHECK; + static const ReturnValue_t ILLEGAL_APID = MAKE_RETURN_CODE( 0 ); + static const ReturnValue_t INCOMPLETE_PACKET = MAKE_RETURN_CODE( 1 ); + static const ReturnValue_t INCORRECT_CHECKSUM = MAKE_RETURN_CODE( 2 ); + static const ReturnValue_t ILLEGAL_PACKET_TYPE = MAKE_RETURN_CODE( 3 ); + static const ReturnValue_t ILLEGAL_PACKET_SUBTYPE = MAKE_RETURN_CODE( 4 ); + static const ReturnValue_t INCORRECT_PRIMARY_HEADER = MAKE_RETURN_CODE( 5 ); + static const ReturnValue_t INCORRECT_SECONDARY_HEADER = MAKE_RETURN_CODE( 6 ); + /** + * The constructor only sets the APID attribute. + * @param set_apid The APID to set. + */ + TcPacketCheck( uint16_t set_apid ); + /** + * This is the actual method to formally check a certain Telecommand Packet. + * The packet's Application Data can not be checked here. + * @param current_packet The packt to check + * @return - \c RETURN_OK on success. + * - \c INCORRECT_CHECKSUM if checksum is invalid. + * - \c ILLEGAL_APID if APID does not match. + */ + ReturnValue_t checkPacket( TcPacketStored* current_packet ); + + uint16_t getApid() const; +}; + + +#endif /* TCPACKETCHECK_H_ */ diff --git a/thermal/AbstractTemperatureSensor.cpp b/thermal/AbstractTemperatureSensor.cpp index 41230f59..5d821367 100644 --- a/thermal/AbstractTemperatureSensor.cpp +++ b/thermal/AbstractTemperatureSensor.cpp @@ -1,70 +1,70 @@ -#include "AbstractTemperatureSensor.h" -#include - -AbstractTemperatureSensor::AbstractTemperatureSensor(object_id_t setObjectid, - ThermalModuleIF *thermalModule) : - SystemObject(setObjectid), commandQueue(NULL), healthHelper(this, - setObjectid), parameterHelper(this) { - if (thermalModule != NULL) { - thermalModule->registerSensor(this); - } - commandQueue = QueueFactory::instance()->createMessageQueue(); -} - -AbstractTemperatureSensor::~AbstractTemperatureSensor() { - QueueFactory::instance()->deleteMessageQueue(commandQueue); -} - -MessageQueueId_t AbstractTemperatureSensor::getCommandQueue() const { - return commandQueue->getId(); -} - -ReturnValue_t AbstractTemperatureSensor::initialize() { - ReturnValue_t result = SystemObject::initialize(); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - result = healthHelper.initialize(); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - result = parameterHelper.initialize(); - return result; -} - -ReturnValue_t AbstractTemperatureSensor::performOperation(uint8_t opCode) { - handleCommandQueue(); - doChildOperation(); - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t AbstractTemperatureSensor::performHealthOp() { - handleCommandQueue(); - return HasReturnvaluesIF::RETURN_OK; -} - -void AbstractTemperatureSensor::handleCommandQueue() { - CommandMessage command; - ReturnValue_t result = commandQueue->receiveMessage(&command); - if (result == HasReturnvaluesIF::RETURN_OK) { - result = healthHelper.handleHealthCommand(&command); - if (result == HasReturnvaluesIF::RETURN_OK) { - return; - } - result = parameterHelper.handleParameterMessage(&command); - if (result == HasReturnvaluesIF::RETURN_OK) { - return; - } - command.setToUnknownCommand(); - commandQueue->reply(&command); - } -} - -ReturnValue_t AbstractTemperatureSensor::setHealth(HealthState health) { - healthHelper.setHealth(health); - return HasReturnvaluesIF::RETURN_OK; -} - -HasHealthIF::HealthState AbstractTemperatureSensor::getHealth() { - return healthHelper.getHealth(); -} +#include "AbstractTemperatureSensor.h" +#include "../ipc/QueueFactory.h" + +AbstractTemperatureSensor::AbstractTemperatureSensor(object_id_t setObjectid, + ThermalModuleIF *thermalModule) : + SystemObject(setObjectid), commandQueue(NULL), healthHelper(this, + setObjectid), parameterHelper(this) { + if (thermalModule != NULL) { + thermalModule->registerSensor(this); + } + commandQueue = QueueFactory::instance()->createMessageQueue(); +} + +AbstractTemperatureSensor::~AbstractTemperatureSensor() { + QueueFactory::instance()->deleteMessageQueue(commandQueue); +} + +MessageQueueId_t AbstractTemperatureSensor::getCommandQueue() const { + return commandQueue->getId(); +} + +ReturnValue_t AbstractTemperatureSensor::initialize() { + ReturnValue_t result = SystemObject::initialize(); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = healthHelper.initialize(); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = parameterHelper.initialize(); + return result; +} + +ReturnValue_t AbstractTemperatureSensor::performOperation(uint8_t opCode) { + handleCommandQueue(); + doChildOperation(); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t AbstractTemperatureSensor::performHealthOp() { + handleCommandQueue(); + return HasReturnvaluesIF::RETURN_OK; +} + +void AbstractTemperatureSensor::handleCommandQueue() { + CommandMessage command; + ReturnValue_t result = commandQueue->receiveMessage(&command); + if (result == HasReturnvaluesIF::RETURN_OK) { + result = healthHelper.handleHealthCommand(&command); + if (result == HasReturnvaluesIF::RETURN_OK) { + return; + } + result = parameterHelper.handleParameterMessage(&command); + if (result == HasReturnvaluesIF::RETURN_OK) { + return; + } + command.setToUnknownCommand(); + commandQueue->reply(&command); + } +} + +ReturnValue_t AbstractTemperatureSensor::setHealth(HealthState health) { + healthHelper.setHealth(health); + return HasReturnvaluesIF::RETURN_OK; +} + +HasHealthIF::HealthState AbstractTemperatureSensor::getHealth() { + return healthHelper.getHealth(); +} diff --git a/thermal/AbstractTemperatureSensor.h b/thermal/AbstractTemperatureSensor.h index 4b869365..462b41f2 100644 --- a/thermal/AbstractTemperatureSensor.h +++ b/thermal/AbstractTemperatureSensor.h @@ -1,64 +1,64 @@ -#ifndef ABSTRACTSENSOR_H_ -#define ABSTRACTSENSOR_H_ - -#include -#include -#include -#include -#include -#include -#include "ThermalModuleIF.h" -#include "tcsDefinitions.h" - -/** - * @defgroup thermal Thermal Components - * @brief Contains all components related to thermal tasks (sensors, heaters) - */ - -/** - * @brief Base class for Temperature Sensor, implements all important interfaces. - * Please use the TemperatureSensor class to implement the actual sensors. - * @ingroup thermal - */ -class AbstractTemperatureSensor: public HasHealthIF, - public SystemObject, - public ExecutableObjectIF, - public ReceivesParameterMessagesIF { -public: - - static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::T_SENSORS; - static const Event TEMP_SENSOR_HIGH = MAKE_EVENT(0, SEVERITY::LOW); - static const Event TEMP_SENSOR_LOW = MAKE_EVENT(1, SEVERITY::LOW); - static const Event TEMP_SENSOR_GRADIENT = MAKE_EVENT(2, SEVERITY::LOW); - - static constexpr float ZERO_KELVIN_C = -273.15; - AbstractTemperatureSensor(object_id_t setObjectid, - ThermalModuleIF *thermalModule); - virtual ~AbstractTemperatureSensor(); - - virtual MessageQueueId_t getCommandQueue() const; - - ReturnValue_t initialize(); - - ReturnValue_t performHealthOp(); - - ReturnValue_t performOperation(uint8_t opCode); - - virtual float getTemperature() = 0; - virtual bool isValid() = 0; - - virtual void resetOldState() = 0; - - ReturnValue_t setHealth(HealthState health); - HasHealthIF::HealthState getHealth(); -protected: - MessageQueueIF* commandQueue; - HealthHelper healthHelper; - ParameterHelper parameterHelper; - - virtual void doChildOperation() = 0; - - void handleCommandQueue(); -}; - -#endif /* ABSTRACTSENSOR_H_ */ +#ifndef ABSTRACTSENSOR_H_ +#define ABSTRACTSENSOR_H_ + +#include "../health/HasHealthIF.h" +#include "../health/HealthHelper.h" +#include "../objectmanager/SystemObject.h" +#include "../tasks/ExecutableObjectIF.h" +#include "../parameters/ParameterHelper.h" +#include "../ipc/MessageQueueIF.h" +#include "ThermalModuleIF.h" +#include "tcsDefinitions.h" + +/** + * @defgroup thermal Thermal Components + * @brief Contains all components related to thermal tasks (sensors, heaters) + */ + +/** + * @brief Base class for Temperature Sensor, implements all important interfaces. + * Please use the TemperatureSensor class to implement the actual sensors. + * @ingroup thermal + */ +class AbstractTemperatureSensor: public HasHealthIF, + public SystemObject, + public ExecutableObjectIF, + public ReceivesParameterMessagesIF { +public: + + static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::T_SENSORS; + static const Event TEMP_SENSOR_HIGH = MAKE_EVENT(0, SEVERITY::LOW); + static const Event TEMP_SENSOR_LOW = MAKE_EVENT(1, SEVERITY::LOW); + static const Event TEMP_SENSOR_GRADIENT = MAKE_EVENT(2, SEVERITY::LOW); + + static constexpr float ZERO_KELVIN_C = -273.15; + AbstractTemperatureSensor(object_id_t setObjectid, + ThermalModuleIF *thermalModule); + virtual ~AbstractTemperatureSensor(); + + virtual MessageQueueId_t getCommandQueue() const; + + ReturnValue_t initialize(); + + ReturnValue_t performHealthOp(); + + ReturnValue_t performOperation(uint8_t opCode); + + virtual float getTemperature() = 0; + virtual bool isValid() = 0; + + virtual void resetOldState() = 0; + + ReturnValue_t setHealth(HealthState health); + HasHealthIF::HealthState getHealth(); +protected: + MessageQueueIF* commandQueue; + HealthHelper healthHelper; + ParameterHelper parameterHelper; + + virtual void doChildOperation() = 0; + + void handleCommandQueue(); +}; + +#endif /* ABSTRACTSENSOR_H_ */ diff --git a/thermal/AcceptsThermalMessagesIF.h b/thermal/AcceptsThermalMessagesIF.h index 28c62af6..9fe03499 100644 --- a/thermal/AcceptsThermalMessagesIF.h +++ b/thermal/AcceptsThermalMessagesIF.h @@ -6,7 +6,7 @@ #ifndef FRAMEWORK_THERMAL_ACCEPTSTHERMALMESSAGESIF_H_ #define FRAMEWORK_THERMAL_ACCEPTSTHERMALMESSAGESIF_H_ -#include +#include "../ipc/MessageQueueSenderIF.h" class AcceptsThermalMessagesIF { public: diff --git a/thermal/CoreComponent.h b/thermal/CoreComponent.h index a0736c71..87a6972e 100644 --- a/thermal/CoreComponent.h +++ b/thermal/CoreComponent.h @@ -1,96 +1,96 @@ -#ifndef MISSION_CONTROLLERS_TCS_CORECOMPONENT_H_ -#define MISSION_CONTROLLERS_TCS_CORECOMPONENT_H_ - -#include -#include -#include -#include -#include -#include - -// TODO: Documentaiton, how to use this? only use Thermal Component, which inherits core component? -class CoreComponent: public ThermalComponentIF { -public: - struct Parameters { - float lowerOpLimit; - float upperOpLimit; - float heaterOn; - float hysteresis; - float heaterSwitchoff; - }; - - static const uint16_t COMPONENT_TEMP_CONFIRMATION = 5; - - CoreComponent(object_id_t reportingObjectId, uint8_t domainId, uint32_t temperaturePoolId, - uint32_t targetStatePoolId, uint32_t currentStatePoolId, - uint32_t requestPoolId, GlobDataSet *dataSet, - AbstractTemperatureSensor *sensor, - AbstractTemperatureSensor *firstRedundantSensor, - AbstractTemperatureSensor *secondRedundantSensor, - ThermalModuleIF *thermalModule, Parameters parameters, - Priority priority, StateRequest initialTargetState = - ThermalComponentIF::STATE_REQUEST_OPERATIONAL); - - virtual ~CoreComponent(); - - virtual HeaterRequest performOperation(uint8_t opCode); - - void markStateIgnored(); - - object_id_t getObjectId(); - - uint8_t getDomainId() const; - - virtual float getLowerOpLimit(); - - ReturnValue_t setTargetState(int8_t newState); - - virtual void setOutputInvalid(); - - virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, - ParameterWrapper *parameterWrapper, - const ParameterWrapper *newValues, uint16_t startAtIndex); - -protected: - - AbstractTemperatureSensor *sensor; - AbstractTemperatureSensor *firstRedundantSensor; - AbstractTemperatureSensor *secondRedundantSensor; - ThermalModuleIF *thermalModule; - - gp_float_t temperature; - gp_int8_t targetState; - gp_int8_t currentState; - gp_uint8_t heaterRequest; - - bool isHeating; - - bool isSafeComponent; - - float minTemp; - - float maxTemp; - - Parameters parameters; - - ThermalMonitor temperatureMonitor; - - const uint8_t domainId; - - virtual float getTemperature(); - virtual State getState(float temperature, Parameters parameters, - int8_t targetState); - - virtual void checkLimits(State state); - - virtual HeaterRequest getHeaterRequest(int8_t targetState, - float temperature, Parameters parameters); - - virtual State getIgnoredState(int8_t state); - - void updateMinMaxTemp(); - - virtual Parameters getParameters(); -}; - -#endif /* MISSION_CONTROLLERS_TCS_CORECOMPONENT_H_ */ +#ifndef MISSION_CONTROLLERS_TCS_CORECOMPONENT_H_ +#define MISSION_CONTROLLERS_TCS_CORECOMPONENT_H_ + +#include "../datapoolglob/GlobalDataSet.h" +#include "../datapoolglob/GlobalPoolVariable.h" +#include "../thermal/ThermalComponentIF.h" +#include "../thermal/AbstractTemperatureSensor.h" +#include "../thermal/ThermalModule.h" +#include "../thermal/ThermalMonitor.h" + +// TODO: Documentaiton, how to use this? only use Thermal Component, which inherits core component? +class CoreComponent: public ThermalComponentIF { +public: + struct Parameters { + float lowerOpLimit; + float upperOpLimit; + float heaterOn; + float hysteresis; + float heaterSwitchoff; + }; + + static const uint16_t COMPONENT_TEMP_CONFIRMATION = 5; + + CoreComponent(object_id_t reportingObjectId, uint8_t domainId, uint32_t temperaturePoolId, + uint32_t targetStatePoolId, uint32_t currentStatePoolId, + uint32_t requestPoolId, GlobDataSet *dataSet, + AbstractTemperatureSensor *sensor, + AbstractTemperatureSensor *firstRedundantSensor, + AbstractTemperatureSensor *secondRedundantSensor, + ThermalModuleIF *thermalModule, Parameters parameters, + Priority priority, StateRequest initialTargetState = + ThermalComponentIF::STATE_REQUEST_OPERATIONAL); + + virtual ~CoreComponent(); + + virtual HeaterRequest performOperation(uint8_t opCode); + + void markStateIgnored(); + + object_id_t getObjectId(); + + uint8_t getDomainId() const; + + virtual float getLowerOpLimit(); + + ReturnValue_t setTargetState(int8_t newState); + + virtual void setOutputInvalid(); + + virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, + ParameterWrapper *parameterWrapper, + const ParameterWrapper *newValues, uint16_t startAtIndex); + +protected: + + AbstractTemperatureSensor *sensor; + AbstractTemperatureSensor *firstRedundantSensor; + AbstractTemperatureSensor *secondRedundantSensor; + ThermalModuleIF *thermalModule; + + gp_float_t temperature; + gp_int8_t targetState; + gp_int8_t currentState; + gp_uint8_t heaterRequest; + + bool isHeating; + + bool isSafeComponent; + + float minTemp; + + float maxTemp; + + Parameters parameters; + + ThermalMonitor temperatureMonitor; + + const uint8_t domainId; + + virtual float getTemperature(); + virtual State getState(float temperature, Parameters parameters, + int8_t targetState); + + virtual void checkLimits(State state); + + virtual HeaterRequest getHeaterRequest(int8_t targetState, + float temperature, Parameters parameters); + + virtual State getIgnoredState(int8_t state); + + void updateMinMaxTemp(); + + virtual Parameters getParameters(); +}; + +#endif /* MISSION_CONTROLLERS_TCS_CORECOMPONENT_H_ */ diff --git a/thermal/Heater.cpp b/thermal/Heater.cpp index b1cf38f2..94dd91b5 100644 --- a/thermal/Heater.cpp +++ b/thermal/Heater.cpp @@ -1,350 +1,350 @@ -#include -#include "Heater.h" - -#include -#include - -Heater::Heater(uint32_t objectId, uint8_t switch0, uint8_t switch1) : - HealthDevice(objectId, 0), internalState(STATE_OFF), powerSwitcher( - NULL), pcduQueueId(0), switch0(switch0), switch1(switch1), wasOn( - false), timedOut(false), reactedToBeingFaulty(false), passive( - false), eventQueue(NULL), heaterOnCountdown(10800000)/*about two orbits*/, parameterHelper( - this), lastAction(CLEAR) { - eventQueue = QueueFactory::instance()->createMessageQueue(); -} - -Heater::~Heater() { - QueueFactory::instance()->deleteMessageQueue(eventQueue); -} - -ReturnValue_t Heater::set() { - passive = false; - //wait for clear before doing anything - if (internalState == STATE_WAIT) { - return HasReturnvaluesIF::RETURN_OK; - } - if (healthHelper.healthTable->isHealthy(getObjectId())) { - doAction(SET); - if ((internalState == STATE_OFF) || (internalState == STATE_PASSIVE)){ - return HasReturnvaluesIF::RETURN_FAILED; - } else { - return HasReturnvaluesIF::RETURN_OK; - } - } else { - if (healthHelper.healthTable->isFaulty(getObjectId())) { - if (!reactedToBeingFaulty) { - reactedToBeingFaulty = true; - doAction(CLEAR); - } - } - return HasReturnvaluesIF::RETURN_FAILED; - } -} - -void Heater::clear(bool passive) { - this->passive = passive; - //Force switching off - if (internalState == STATE_WAIT) { - internalState = STATE_ON; - } - if (healthHelper.healthTable->isHealthy(getObjectId())) { - doAction(CLEAR); - } else if (healthHelper.healthTable->isFaulty(getObjectId())) { - if (!reactedToBeingFaulty) { - reactedToBeingFaulty = true; - doAction(CLEAR); - } - } -} - -void Heater::doAction(Action action) { - //only act if we are not in the right state or in a transition - if (action == SET) { - if ((internalState == STATE_OFF) || (internalState == STATE_PASSIVE) - || (internalState == STATE_EXTERNAL_CONTROL)) { - switchCountdown.setTimeout(powerSwitcher->getSwitchDelayMs()); - internalState = STATE_WAIT_FOR_SWITCHES_ON; - powerSwitcher->sendSwitchCommand(switch0, PowerSwitchIF::SWITCH_ON); - powerSwitcher->sendSwitchCommand(switch1, PowerSwitchIF::SWITCH_ON); - } - } else { //clear - if ((internalState == STATE_ON) || (internalState == STATE_FAULTY) - || (internalState == STATE_EXTERNAL_CONTROL)) { - internalState = STATE_WAIT_FOR_SWITCHES_OFF; - switchCountdown.setTimeout(powerSwitcher->getSwitchDelayMs()); - powerSwitcher->sendSwitchCommand(switch0, - PowerSwitchIF::SWITCH_OFF); - powerSwitcher->sendSwitchCommand(switch1, - PowerSwitchIF::SWITCH_OFF); - } - } -} - -void Heater::setPowerSwitcher(PowerSwitchIF* powerSwitch) { - this->powerSwitcher = powerSwitch; -} - -ReturnValue_t Heater::performOperation(uint8_t opCode) { - handleQueue(); - handleEventQueue(); - - if (!healthHelper.healthTable->isFaulty(getObjectId())) { - reactedToBeingFaulty = false; - } - - switch (internalState) { - case STATE_ON: - if ((powerSwitcher->getSwitchState(switch0) == PowerSwitchIF::SWITCH_OFF) - || (powerSwitcher->getSwitchState(switch1) - == PowerSwitchIF::SWITCH_OFF)) { - //switch went off on its own - //trigger event. FDIR can confirm if it is caused by MniOps and decide on the action - //do not trigger FD events when under external control - if (healthHelper.getHealth() != EXTERNAL_CONTROL) { - triggerEvent(PowerSwitchIF::SWITCH_WENT_OFF); - } else { - internalState = STATE_EXTERNAL_CONTROL; - } - } - break; - case STATE_OFF: - //check if heater is on, ie both switches are on - //if so, just command it to off, to resolve the situation or force a switch stayed on event - //But, only do anything if not already faulty (state off is the stable point for being faulty) - if ((!healthHelper.healthTable->isFaulty(getObjectId())) - && (powerSwitcher->getSwitchState(switch0) - == PowerSwitchIF::SWITCH_ON) - && (powerSwitcher->getSwitchState(switch1) - == PowerSwitchIF::SWITCH_ON)) { - //do not trigger FD events when under external control - if (healthHelper.getHealth() != EXTERNAL_CONTROL) { - internalState = STATE_WAIT_FOR_SWITCHES_OFF; - switchCountdown.setTimeout(powerSwitcher->getSwitchDelayMs()); - powerSwitcher->sendSwitchCommand(switch0, - PowerSwitchIF::SWITCH_OFF); - powerSwitcher->sendSwitchCommand(switch1, - PowerSwitchIF::SWITCH_OFF); - } else { - internalState = STATE_EXTERNAL_CONTROL; - } - } - break; - case STATE_PASSIVE: - break; - case STATE_WAIT_FOR_SWITCHES_ON: - if (switchCountdown.hasTimedOut()) { - if ((powerSwitcher->getSwitchState(switch0) - == PowerSwitchIF::SWITCH_OFF) - || (powerSwitcher->getSwitchState(switch1) - == PowerSwitchIF::SWITCH_OFF)) { - triggerEvent(HEATER_STAYED_OFF); - internalState = STATE_WAIT_FOR_FDIR; //wait before retrying or anything - } else { - triggerEvent(HEATER_ON); - internalState = STATE_ON; - } - } - break; - case STATE_WAIT_FOR_SWITCHES_OFF: - if (switchCountdown.hasTimedOut()) { - //only check for both being on (ie heater still on) - if ((powerSwitcher->getSwitchState(switch0) - == PowerSwitchIF::SWITCH_ON) - && (powerSwitcher->getSwitchState(switch1) - == PowerSwitchIF::SWITCH_ON)) { - if (healthHelper.healthTable->isFaulty(getObjectId())) { - if (passive) { - internalState = STATE_PASSIVE; - } else { - internalState = STATE_OFF; //just accept it - } - triggerEvent(HEATER_ON); //but throw an event to make it more visible - break; - } - triggerEvent(HEATER_STAYED_ON); - internalState = STATE_WAIT_FOR_FDIR; //wait before retrying or anything - } else { - triggerEvent(HEATER_OFF); - if (passive) { - internalState = STATE_PASSIVE; - } else { - internalState = STATE_OFF; - } - } - } - break; - default: - break; - } - - if ((powerSwitcher->getSwitchState(switch0) == PowerSwitchIF::SWITCH_ON) - && (powerSwitcher->getSwitchState(switch1) - == PowerSwitchIF::SWITCH_ON)) { - if (wasOn) { - if (heaterOnCountdown.hasTimedOut()) { - //SHOULDDO this means if a heater fails in single mode, the timeout will start again - //I am not sure if this is a bug, but atm I have no idea how to fix this and think - //it will be ok. whatcouldpossiblygowrong™ - if (!timedOut) { - triggerEvent(HEATER_TIMEOUT); - timedOut = true; - } - } - } else { - wasOn = true; - heaterOnCountdown.resetTimer(); - timedOut = false; - } - } else { - wasOn = false; - } - - return HasReturnvaluesIF::RETURN_OK; -} - -void Heater::setSwitch(uint8_t number, ReturnValue_t state, - uint32_t* uptimeOfSwitching) { - if (powerSwitcher == NULL) { - return; - } - if (powerSwitcher->getSwitchState(number) == state) { - *uptimeOfSwitching = INVALID_UPTIME; - } else { - if ((*uptimeOfSwitching == INVALID_UPTIME)) { - powerSwitcher->sendSwitchCommand(number, state); - Clock::getUptime(uptimeOfSwitching); - } else { - uint32_t currentUptime; - Clock::getUptime(¤tUptime); - if (currentUptime - *uptimeOfSwitching - > powerSwitcher->getSwitchDelayMs()) { - *uptimeOfSwitching = INVALID_UPTIME; - if (healthHelper.healthTable->isHealthy(getObjectId())) { - if (state == PowerSwitchIF::SWITCH_ON) { - triggerEvent(HEATER_STAYED_OFF); - } else { - triggerEvent(HEATER_STAYED_ON); - } - } - //SHOULDDO MiniOps during switch timeout leads to a faulty switch - } - } - } -} - -MessageQueueId_t Heater::getCommandQueue() const { - return commandQueue->getId(); -} - -ReturnValue_t Heater::initialize() { - ReturnValue_t result = SystemObject::initialize(); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - EventManagerIF* manager = objectManager->get( - objects::EVENT_MANAGER); - if (manager == NULL) { - return HasReturnvaluesIF::RETURN_FAILED; - } - result = manager->registerListener(eventQueue->getId()); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - ConfirmsFailuresIF* pcdu = objectManager->get( - DeviceHandlerFailureIsolation::powerConfirmationId); - if (pcdu == NULL) { - return HasReturnvaluesIF::RETURN_FAILED; - } - pcduQueueId = pcdu->getEventReceptionQueue(); - - result = manager->subscribeToAllEventsFrom(eventQueue->getId(), - getObjectId()); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - result = parameterHelper.initialize(); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - result = healthHelper.initialize(); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - return HasReturnvaluesIF::RETURN_OK; -} - -void Heater::handleQueue() { - CommandMessage command; - ReturnValue_t result = commandQueue->receiveMessage(&command); - if (result == HasReturnvaluesIF::RETURN_OK) { - result = healthHelper.handleHealthCommand(&command); - if (result == HasReturnvaluesIF::RETURN_OK) { - return; - } - parameterHelper.handleParameterMessage(&command); - } -} - -ReturnValue_t Heater::getParameter(uint8_t domainId, uint16_t parameterId, - ParameterWrapper* parameterWrapper, const ParameterWrapper* newValues, - uint16_t startAtIndex) { - if (domainId != DOMAIN_ID_BASE) { - return INVALID_DOMAIN_ID; - } - switch (parameterId) { - case 0: - parameterWrapper->set(heaterOnCountdown.timeout); - break; - default: - return INVALID_MATRIX_ID; - } - return HasReturnvaluesIF::RETURN_OK; -} - -void Heater::handleEventQueue() { - EventMessage event; - for (ReturnValue_t result = eventQueue->receiveMessage(&event); - result == HasReturnvaluesIF::RETURN_OK; - result = eventQueue->receiveMessage(&event)) { - switch (event.getMessageId()) { - case EventMessage::EVENT_MESSAGE: - switch (event.getEvent()) { - case Fuse::FUSE_WENT_OFF: - case HEATER_STAYED_OFF: - case HEATER_STAYED_ON://Setting it faulty does not help, but we need to reach a stable state and can check for being faulty before throwing this event again. - if (healthHelper.healthTable->isCommandable(getObjectId())) { - healthHelper.setHealth(HasHealthIF::FAULTY); - internalState = STATE_FAULTY; - } - break; - case PowerSwitchIF::SWITCH_WENT_OFF: - internalState = STATE_WAIT; - event.setMessageId(EventMessage::CONFIRMATION_REQUEST); - if (pcduQueueId != 0) { - eventQueue->sendMessage(pcduQueueId, &event); - } else { - healthHelper.setHealth(HasHealthIF::FAULTY); - internalState = STATE_FAULTY; - } - break; - default: - return; - } - break; - case EventMessage::YOUR_FAULT: - healthHelper.setHealth(HasHealthIF::FAULTY); - internalState = STATE_FAULTY; - break; - case EventMessage::MY_FAULT: - //do nothing, we are already in STATE_WAIT and wait for a clear() - break; - default: - return; - } - } -} +#include "../devicehandlers/DeviceHandlerFailureIsolation.h" +#include "Heater.h" + +#include "../power/Fuse.h" +#include "../ipc/QueueFactory.h" + +Heater::Heater(uint32_t objectId, uint8_t switch0, uint8_t switch1) : + HealthDevice(objectId, 0), internalState(STATE_OFF), powerSwitcher( + NULL), pcduQueueId(0), switch0(switch0), switch1(switch1), wasOn( + false), timedOut(false), reactedToBeingFaulty(false), passive( + false), eventQueue(NULL), heaterOnCountdown(10800000)/*about two orbits*/, parameterHelper( + this), lastAction(CLEAR) { + eventQueue = QueueFactory::instance()->createMessageQueue(); +} + +Heater::~Heater() { + QueueFactory::instance()->deleteMessageQueue(eventQueue); +} + +ReturnValue_t Heater::set() { + passive = false; + //wait for clear before doing anything + if (internalState == STATE_WAIT) { + return HasReturnvaluesIF::RETURN_OK; + } + if (healthHelper.healthTable->isHealthy(getObjectId())) { + doAction(SET); + if ((internalState == STATE_OFF) || (internalState == STATE_PASSIVE)){ + return HasReturnvaluesIF::RETURN_FAILED; + } else { + return HasReturnvaluesIF::RETURN_OK; + } + } else { + if (healthHelper.healthTable->isFaulty(getObjectId())) { + if (!reactedToBeingFaulty) { + reactedToBeingFaulty = true; + doAction(CLEAR); + } + } + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +void Heater::clear(bool passive) { + this->passive = passive; + //Force switching off + if (internalState == STATE_WAIT) { + internalState = STATE_ON; + } + if (healthHelper.healthTable->isHealthy(getObjectId())) { + doAction(CLEAR); + } else if (healthHelper.healthTable->isFaulty(getObjectId())) { + if (!reactedToBeingFaulty) { + reactedToBeingFaulty = true; + doAction(CLEAR); + } + } +} + +void Heater::doAction(Action action) { + //only act if we are not in the right state or in a transition + if (action == SET) { + if ((internalState == STATE_OFF) || (internalState == STATE_PASSIVE) + || (internalState == STATE_EXTERNAL_CONTROL)) { + switchCountdown.setTimeout(powerSwitcher->getSwitchDelayMs()); + internalState = STATE_WAIT_FOR_SWITCHES_ON; + powerSwitcher->sendSwitchCommand(switch0, PowerSwitchIF::SWITCH_ON); + powerSwitcher->sendSwitchCommand(switch1, PowerSwitchIF::SWITCH_ON); + } + } else { //clear + if ((internalState == STATE_ON) || (internalState == STATE_FAULTY) + || (internalState == STATE_EXTERNAL_CONTROL)) { + internalState = STATE_WAIT_FOR_SWITCHES_OFF; + switchCountdown.setTimeout(powerSwitcher->getSwitchDelayMs()); + powerSwitcher->sendSwitchCommand(switch0, + PowerSwitchIF::SWITCH_OFF); + powerSwitcher->sendSwitchCommand(switch1, + PowerSwitchIF::SWITCH_OFF); + } + } +} + +void Heater::setPowerSwitcher(PowerSwitchIF* powerSwitch) { + this->powerSwitcher = powerSwitch; +} + +ReturnValue_t Heater::performOperation(uint8_t opCode) { + handleQueue(); + handleEventQueue(); + + if (!healthHelper.healthTable->isFaulty(getObjectId())) { + reactedToBeingFaulty = false; + } + + switch (internalState) { + case STATE_ON: + if ((powerSwitcher->getSwitchState(switch0) == PowerSwitchIF::SWITCH_OFF) + || (powerSwitcher->getSwitchState(switch1) + == PowerSwitchIF::SWITCH_OFF)) { + //switch went off on its own + //trigger event. FDIR can confirm if it is caused by MniOps and decide on the action + //do not trigger FD events when under external control + if (healthHelper.getHealth() != EXTERNAL_CONTROL) { + triggerEvent(PowerSwitchIF::SWITCH_WENT_OFF); + } else { + internalState = STATE_EXTERNAL_CONTROL; + } + } + break; + case STATE_OFF: + //check if heater is on, ie both switches are on + //if so, just command it to off, to resolve the situation or force a switch stayed on event + //But, only do anything if not already faulty (state off is the stable point for being faulty) + if ((!healthHelper.healthTable->isFaulty(getObjectId())) + && (powerSwitcher->getSwitchState(switch0) + == PowerSwitchIF::SWITCH_ON) + && (powerSwitcher->getSwitchState(switch1) + == PowerSwitchIF::SWITCH_ON)) { + //do not trigger FD events when under external control + if (healthHelper.getHealth() != EXTERNAL_CONTROL) { + internalState = STATE_WAIT_FOR_SWITCHES_OFF; + switchCountdown.setTimeout(powerSwitcher->getSwitchDelayMs()); + powerSwitcher->sendSwitchCommand(switch0, + PowerSwitchIF::SWITCH_OFF); + powerSwitcher->sendSwitchCommand(switch1, + PowerSwitchIF::SWITCH_OFF); + } else { + internalState = STATE_EXTERNAL_CONTROL; + } + } + break; + case STATE_PASSIVE: + break; + case STATE_WAIT_FOR_SWITCHES_ON: + if (switchCountdown.hasTimedOut()) { + if ((powerSwitcher->getSwitchState(switch0) + == PowerSwitchIF::SWITCH_OFF) + || (powerSwitcher->getSwitchState(switch1) + == PowerSwitchIF::SWITCH_OFF)) { + triggerEvent(HEATER_STAYED_OFF); + internalState = STATE_WAIT_FOR_FDIR; //wait before retrying or anything + } else { + triggerEvent(HEATER_ON); + internalState = STATE_ON; + } + } + break; + case STATE_WAIT_FOR_SWITCHES_OFF: + if (switchCountdown.hasTimedOut()) { + //only check for both being on (ie heater still on) + if ((powerSwitcher->getSwitchState(switch0) + == PowerSwitchIF::SWITCH_ON) + && (powerSwitcher->getSwitchState(switch1) + == PowerSwitchIF::SWITCH_ON)) { + if (healthHelper.healthTable->isFaulty(getObjectId())) { + if (passive) { + internalState = STATE_PASSIVE; + } else { + internalState = STATE_OFF; //just accept it + } + triggerEvent(HEATER_ON); //but throw an event to make it more visible + break; + } + triggerEvent(HEATER_STAYED_ON); + internalState = STATE_WAIT_FOR_FDIR; //wait before retrying or anything + } else { + triggerEvent(HEATER_OFF); + if (passive) { + internalState = STATE_PASSIVE; + } else { + internalState = STATE_OFF; + } + } + } + break; + default: + break; + } + + if ((powerSwitcher->getSwitchState(switch0) == PowerSwitchIF::SWITCH_ON) + && (powerSwitcher->getSwitchState(switch1) + == PowerSwitchIF::SWITCH_ON)) { + if (wasOn) { + if (heaterOnCountdown.hasTimedOut()) { + //SHOULDDO this means if a heater fails in single mode, the timeout will start again + //I am not sure if this is a bug, but atm I have no idea how to fix this and think + //it will be ok. whatcouldpossiblygowrong™ + if (!timedOut) { + triggerEvent(HEATER_TIMEOUT); + timedOut = true; + } + } + } else { + wasOn = true; + heaterOnCountdown.resetTimer(); + timedOut = false; + } + } else { + wasOn = false; + } + + return HasReturnvaluesIF::RETURN_OK; +} + +void Heater::setSwitch(uint8_t number, ReturnValue_t state, + uint32_t* uptimeOfSwitching) { + if (powerSwitcher == NULL) { + return; + } + if (powerSwitcher->getSwitchState(number) == state) { + *uptimeOfSwitching = INVALID_UPTIME; + } else { + if ((*uptimeOfSwitching == INVALID_UPTIME)) { + powerSwitcher->sendSwitchCommand(number, state); + Clock::getUptime(uptimeOfSwitching); + } else { + uint32_t currentUptime; + Clock::getUptime(¤tUptime); + if (currentUptime - *uptimeOfSwitching + > powerSwitcher->getSwitchDelayMs()) { + *uptimeOfSwitching = INVALID_UPTIME; + if (healthHelper.healthTable->isHealthy(getObjectId())) { + if (state == PowerSwitchIF::SWITCH_ON) { + triggerEvent(HEATER_STAYED_OFF); + } else { + triggerEvent(HEATER_STAYED_ON); + } + } + //SHOULDDO MiniOps during switch timeout leads to a faulty switch + } + } + } +} + +MessageQueueId_t Heater::getCommandQueue() const { + return commandQueue->getId(); +} + +ReturnValue_t Heater::initialize() { + ReturnValue_t result = SystemObject::initialize(); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + EventManagerIF* manager = objectManager->get( + objects::EVENT_MANAGER); + if (manager == NULL) { + return HasReturnvaluesIF::RETURN_FAILED; + } + result = manager->registerListener(eventQueue->getId()); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + ConfirmsFailuresIF* pcdu = objectManager->get( + DeviceHandlerFailureIsolation::powerConfirmationId); + if (pcdu == NULL) { + return HasReturnvaluesIF::RETURN_FAILED; + } + pcduQueueId = pcdu->getEventReceptionQueue(); + + result = manager->subscribeToAllEventsFrom(eventQueue->getId(), + getObjectId()); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + result = parameterHelper.initialize(); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + result = healthHelper.initialize(); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + return HasReturnvaluesIF::RETURN_OK; +} + +void Heater::handleQueue() { + CommandMessage command; + ReturnValue_t result = commandQueue->receiveMessage(&command); + if (result == HasReturnvaluesIF::RETURN_OK) { + result = healthHelper.handleHealthCommand(&command); + if (result == HasReturnvaluesIF::RETURN_OK) { + return; + } + parameterHelper.handleParameterMessage(&command); + } +} + +ReturnValue_t Heater::getParameter(uint8_t domainId, uint16_t parameterId, + ParameterWrapper* parameterWrapper, const ParameterWrapper* newValues, + uint16_t startAtIndex) { + if (domainId != DOMAIN_ID_BASE) { + return INVALID_DOMAIN_ID; + } + switch (parameterId) { + case 0: + parameterWrapper->set(heaterOnCountdown.timeout); + break; + default: + return INVALID_MATRIX_ID; + } + return HasReturnvaluesIF::RETURN_OK; +} + +void Heater::handleEventQueue() { + EventMessage event; + for (ReturnValue_t result = eventQueue->receiveMessage(&event); + result == HasReturnvaluesIF::RETURN_OK; + result = eventQueue->receiveMessage(&event)) { + switch (event.getMessageId()) { + case EventMessage::EVENT_MESSAGE: + switch (event.getEvent()) { + case Fuse::FUSE_WENT_OFF: + case HEATER_STAYED_OFF: + case HEATER_STAYED_ON://Setting it faulty does not help, but we need to reach a stable state and can check for being faulty before throwing this event again. + if (healthHelper.healthTable->isCommandable(getObjectId())) { + healthHelper.setHealth(HasHealthIF::FAULTY); + internalState = STATE_FAULTY; + } + break; + case PowerSwitchIF::SWITCH_WENT_OFF: + internalState = STATE_WAIT; + event.setMessageId(EventMessage::CONFIRMATION_REQUEST); + if (pcduQueueId != 0) { + eventQueue->sendMessage(pcduQueueId, &event); + } else { + healthHelper.setHealth(HasHealthIF::FAULTY); + internalState = STATE_FAULTY; + } + break; + default: + return; + } + break; + case EventMessage::YOUR_FAULT: + healthHelper.setHealth(HasHealthIF::FAULTY); + internalState = STATE_FAULTY; + break; + case EventMessage::MY_FAULT: + //do nothing, we are already in STATE_WAIT and wait for a clear() + break; + default: + return; + } + } +} diff --git a/thermal/Heater.h b/thermal/Heater.h index 41004e03..8121a774 100644 --- a/thermal/Heater.h +++ b/thermal/Heater.h @@ -1,90 +1,90 @@ -#ifndef FRAMEWORK_THERMAL_HEATER_H_ -#define FRAMEWORK_THERMAL_HEATER_H_ - -#include -#include -#include -#include -#include -#include -//class RedundantHeater; - -class Heater: public HealthDevice, public ReceivesParameterMessagesIF { - friend class RedundantHeater; -public: - - static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::HEATER; - static const Event HEATER_ON = MAKE_EVENT(0, SEVERITY::INFO); - static const Event HEATER_OFF = MAKE_EVENT(1, SEVERITY::INFO); - static const Event HEATER_TIMEOUT = MAKE_EVENT(2, SEVERITY::LOW); - static const Event HEATER_STAYED_ON = MAKE_EVENT(3, SEVERITY::LOW); - static const Event HEATER_STAYED_OFF = MAKE_EVENT(4, SEVERITY::LOW); - - Heater(uint32_t objectId, uint8_t switch0, uint8_t switch1); - virtual ~Heater(); - - ReturnValue_t performOperation(uint8_t opCode); - - ReturnValue_t initialize(); - - ReturnValue_t set(); - void clear(bool passive); - - void setPowerSwitcher(PowerSwitchIF *powerSwitch); - - MessageQueueId_t getCommandQueue() const; - - ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, - ParameterWrapper *parameterWrapper, - const ParameterWrapper *newValues, uint16_t startAtIndex); - -protected: - static const uint32_t INVALID_UPTIME = 0; - - enum InternalState { - STATE_ON, - STATE_OFF, - STATE_PASSIVE, - STATE_WAIT_FOR_SWITCHES_ON, - STATE_WAIT_FOR_SWITCHES_OFF, - STATE_WAIT_FOR_FDIR, //used to avoid doing anything until fdir decided what to do - STATE_FAULTY, - STATE_WAIT, //used when waiting for system to recover from miniops - STATE_EXTERNAL_CONTROL //entered when under external control and a fdir reaction would be triggered. This is useful when leaving external control into an unknown state - //if no fdir reaction is triggered under external control the state is still ok and no need for any special treatment is needed - } internalState; - - PowerSwitchIF *powerSwitcher; - MessageQueueId_t pcduQueueId; - - uint8_t switch0; - uint8_t switch1; - - bool wasOn; - - bool timedOut; - - bool reactedToBeingFaulty; - - bool passive; - - MessageQueueIF* eventQueue; - Countdown heaterOnCountdown; - Countdown switchCountdown; - ParameterHelper parameterHelper; - - enum Action { - SET, CLEAR - } lastAction; - - void doAction(Action action); - - void setSwitch(uint8_t number, ReturnValue_t state, - uint32_t *upTimeOfSwitching); - - void handleQueue(); - - void handleEventQueue(); -}; - -#endif /* FRAMEWORK_THERMAL_HEATER_H_ */ +#ifndef FRAMEWORK_THERMAL_HEATER_H_ +#define FRAMEWORK_THERMAL_HEATER_H_ + +#include "../devicehandlers/HealthDevice.h" +#include "../parameters/ParameterHelper.h" +#include "../power/PowerSwitchIF.h" +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../timemanager/Countdown.h" +#include +//class RedundantHeater; + +class Heater: public HealthDevice, public ReceivesParameterMessagesIF { + friend class RedundantHeater; +public: + + static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::HEATER; + static const Event HEATER_ON = MAKE_EVENT(0, SEVERITY::INFO); + static const Event HEATER_OFF = MAKE_EVENT(1, SEVERITY::INFO); + static const Event HEATER_TIMEOUT = MAKE_EVENT(2, SEVERITY::LOW); + static const Event HEATER_STAYED_ON = MAKE_EVENT(3, SEVERITY::LOW); + static const Event HEATER_STAYED_OFF = MAKE_EVENT(4, SEVERITY::LOW); + + Heater(uint32_t objectId, uint8_t switch0, uint8_t switch1); + virtual ~Heater(); + + ReturnValue_t performOperation(uint8_t opCode); + + ReturnValue_t initialize(); + + ReturnValue_t set(); + void clear(bool passive); + + void setPowerSwitcher(PowerSwitchIF *powerSwitch); + + MessageQueueId_t getCommandQueue() const; + + ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, + ParameterWrapper *parameterWrapper, + const ParameterWrapper *newValues, uint16_t startAtIndex); + +protected: + static const uint32_t INVALID_UPTIME = 0; + + enum InternalState { + STATE_ON, + STATE_OFF, + STATE_PASSIVE, + STATE_WAIT_FOR_SWITCHES_ON, + STATE_WAIT_FOR_SWITCHES_OFF, + STATE_WAIT_FOR_FDIR, //used to avoid doing anything until fdir decided what to do + STATE_FAULTY, + STATE_WAIT, //used when waiting for system to recover from miniops + STATE_EXTERNAL_CONTROL //entered when under external control and a fdir reaction would be triggered. This is useful when leaving external control into an unknown state + //if no fdir reaction is triggered under external control the state is still ok and no need for any special treatment is needed + } internalState; + + PowerSwitchIF *powerSwitcher; + MessageQueueId_t pcduQueueId; + + uint8_t switch0; + uint8_t switch1; + + bool wasOn; + + bool timedOut; + + bool reactedToBeingFaulty; + + bool passive; + + MessageQueueIF* eventQueue; + Countdown heaterOnCountdown; + Countdown switchCountdown; + ParameterHelper parameterHelper; + + enum Action { + SET, CLEAR + } lastAction; + + void doAction(Action action); + + void setSwitch(uint8_t number, ReturnValue_t state, + uint32_t *upTimeOfSwitching); + + void handleQueue(); + + void handleEventQueue(); +}; + +#endif /* FRAMEWORK_THERMAL_HEATER_H_ */ diff --git a/thermal/RedundantHeater.h b/thermal/RedundantHeater.h index 55d402d7..4a82de07 100644 --- a/thermal/RedundantHeater.h +++ b/thermal/RedundantHeater.h @@ -1,50 +1,50 @@ -#ifndef REDUNDANTHEATER_H_ -#define REDUNDANTHEATER_H_ - -#include - -class RedundantHeater { -public: - - struct Parameters { - Parameters(uint32_t objectIdHeater0, uint32_t objectIdHeater1, - uint8_t switch0Heater0, uint8_t switch1Heater0, - uint8_t switch0Heater1, uint8_t switch1Heater1) : - objectIdHeater0(objectIdHeater0), objectIdHeater1(objectIdHeater1), - switch0Heater0(switch0Heater0),switch1Heater0(switch1Heater0), - switch0Heater1(switch0Heater1), switch1Heater1(switch1Heater1) { - } - - Parameters() : - objectIdHeater0(0), objectIdHeater1(0), switch0Heater0(0), - switch1Heater0(0), switch0Heater1(0), switch1Heater1(0) { - } - - uint32_t objectIdHeater0; - uint32_t objectIdHeater1; - uint8_t switch0Heater0; - uint8_t switch1Heater0; - uint8_t switch0Heater1; - uint8_t switch1Heater1; - }; - - RedundantHeater(Parameters parameters); - virtual ~RedundantHeater(); - - void performOperation(uint8_t opCode); - - void triggerHeaterEvent(Event event); - - void set(bool on, bool both, bool passive = false); - - void setPowerSwitcher(PowerSwitchIF *powerSwitch); - -protected: - - Heater heater0; - Heater heater1; - -}; - -#endif /* REDUNDANTHEATER_H_ */ - +#ifndef REDUNDANTHEATER_H_ +#define REDUNDANTHEATER_H_ + +#include "../thermal/Heater.h" + +class RedundantHeater { +public: + + struct Parameters { + Parameters(uint32_t objectIdHeater0, uint32_t objectIdHeater1, + uint8_t switch0Heater0, uint8_t switch1Heater0, + uint8_t switch0Heater1, uint8_t switch1Heater1) : + objectIdHeater0(objectIdHeater0), objectIdHeater1(objectIdHeater1), + switch0Heater0(switch0Heater0),switch1Heater0(switch1Heater0), + switch0Heater1(switch0Heater1), switch1Heater1(switch1Heater1) { + } + + Parameters() : + objectIdHeater0(0), objectIdHeater1(0), switch0Heater0(0), + switch1Heater0(0), switch0Heater1(0), switch1Heater1(0) { + } + + uint32_t objectIdHeater0; + uint32_t objectIdHeater1; + uint8_t switch0Heater0; + uint8_t switch1Heater0; + uint8_t switch0Heater1; + uint8_t switch1Heater1; + }; + + RedundantHeater(Parameters parameters); + virtual ~RedundantHeater(); + + void performOperation(uint8_t opCode); + + void triggerHeaterEvent(Event event); + + void set(bool on, bool both, bool passive = false); + + void setPowerSwitcher(PowerSwitchIF *powerSwitch); + +protected: + + Heater heater0; + Heater heater1; + +}; + +#endif /* REDUNDANTHEATER_H_ */ + diff --git a/thermal/TemperatureSensor.h b/thermal/TemperatureSensor.h index 27885b8b..cf2dffd4 100644 --- a/thermal/TemperatureSensor.h +++ b/thermal/TemperatureSensor.h @@ -1,222 +1,222 @@ -#ifndef TEMPERATURESENSOR_H_ -#define TEMPERATURESENSOR_H_ - -#include -#include -#include -#include - -/** - * @brief This building block handles non-linear value conversion and - * range checks for analog temperature sensors. - * @details This class can be used to perform all necessary tasks for temperature sensors. - * A sensor can be instantiated by calling the constructor. - * The temperature is calculated from an input value with - * the calculateOutputTemperature() function. Range checking and - * limit monitoring is performed automatically. - * The inputType specifies the type of the raw input while the - * limitType specifies the type of the upper and lower limit to check against. - * @ingroup thermal - */ - -template -class TemperatureSensor: public AbstractTemperatureSensor { -public: - /** - * This structure contains parameters required for range checking - * and the conversion from the input value to the output temperature. - * a, b and c can be any parameters required to calculate the output - * temperature from the input value, depending on the formula used. - * - * The parameters a,b and c are used in the calculateOutputTemperature() call. - * - * The lower and upper limits can be specified in any type, for example float for C values - * or any other type for raw values. - */ - struct Parameters { - float a; - float b; - float c; - limitType lowerLimit; - limitType upperLimit; - float maxGradient; - }; - - /** - * Forward declaration for explicit instantiation of used parameters. - */ - struct UsedParameters { - UsedParameters(Parameters parameters) : - a(parameters.a), b(parameters.b), c(parameters.c), - gradient(parameters.maxGradient) {} - float a; - float b; - float c; - float gradient; - }; - - /** - * Instantiate Temperature Sensor Object. - * @param setObjectid objectId of the sensor object - * @param inputValue Input value which is converted to a temperature - * @param poolVariable Pool Variable to store the temperature value - * @param vectorIndex Vector Index for the sensor monitor - * @param parameters Calculation parameters, temperature limits, gradient limit - * @param datapoolId Datapool ID of the output temperature - * @param outputSet Output dataset for the output temperature to fetch it with read() - * @param thermalModule respective thermal module, if it has one - */ - TemperatureSensor(object_id_t setObjectid, - inputType *inputValue, PoolVariableIF *poolVariable, - uint8_t vectorIndex, uint32_t datapoolId, Parameters parameters = {0, 0, 0, 0, 0, 0}, - GlobDataSet *outputSet = NULL, ThermalModuleIF *thermalModule = NULL) : - AbstractTemperatureSensor(setObjectid, thermalModule), parameters(parameters), - inputValue(inputValue), poolVariable(poolVariable), - outputTemperature(datapoolId, outputSet, PoolVariableIF::VAR_WRITE), - sensorMonitor(setObjectid, DOMAIN_ID_SENSOR, - GlobalDataPool::poolIdAndPositionToPid(poolVariable->getDataPoolId(), vectorIndex), - DEFAULT_CONFIRMATION_COUNT, parameters.lowerLimit, parameters.upperLimit, - TEMP_SENSOR_LOW, TEMP_SENSOR_HIGH), - oldTemperature(20), uptimeOfOldTemperature( { INVALID_TEMPERATURE, 0 }) { - } - - -protected: - /** - * This formula is used to calculate the temperature from an input value - * with an arbitrary type. - * A default implementation is provided but can be replaced depending - * on the required calculation. - * @param inputTemperature - * @return - */ - virtual float calculateOutputTemperature(inputType inputValue) { - return parameters.a * inputValue * inputValue - + parameters.b * inputValue + parameters.c; - } - - -private: - void setInvalid() { - outputTemperature = INVALID_TEMPERATURE; - outputTemperature.setValid(false); - uptimeOfOldTemperature.tv_sec = INVALID_UPTIME; - sensorMonitor.setToInvalid(); - } -protected: - static const int32_t INVALID_UPTIME = 0; - - UsedParameters parameters; - - inputType * inputValue; - - PoolVariableIF *poolVariable; - - gp_float_t outputTemperature; - - LimitMonitor sensorMonitor; - - float oldTemperature; - timeval uptimeOfOldTemperature; - - void doChildOperation() { - if (!poolVariable->isValid() - || !healthHelper.healthTable->isHealthy(getObjectId())) { - setInvalid(); - return; - } - - outputTemperature = calculateOutputTemperature(*inputValue); - outputTemperature.setValid(PoolVariableIF::VALID); - - timeval uptime; - Clock::getUptime(&uptime); - - if (uptimeOfOldTemperature.tv_sec != INVALID_UPTIME) { - //In theory, we could use an AbsValueMonitor to monitor the gradient. - //But this would require storing the maxGradient in DP and quite some overhead. - //The concept of delta limits is a bit strange anyway. - float deltaTime; - float deltaTemp; - - deltaTime = (uptime.tv_sec + uptime.tv_usec / 1000000.) - - (uptimeOfOldTemperature.tv_sec - + uptimeOfOldTemperature.tv_usec / 1000000.); - deltaTemp = oldTemperature - outputTemperature; - if (deltaTemp < 0) { - deltaTemp = -deltaTemp; - } - if (parameters.gradient < deltaTemp / deltaTime) { - triggerEvent(TEMP_SENSOR_GRADIENT); - //Don't set invalid, as we did not recognize it as invalid with full authority, let FDIR handle it - } - } - - //Check is done against raw limits. SHOULDDO: Why? Using �C would be more easy to handle. - sensorMonitor.doCheck(outputTemperature.value); - - if (sensorMonitor.isOutOfLimits()) { - uptimeOfOldTemperature.tv_sec = INVALID_UPTIME; - outputTemperature.setValid(PoolVariableIF::INVALID); - outputTemperature = INVALID_TEMPERATURE; - } else { - oldTemperature = outputTemperature; - uptimeOfOldTemperature = uptime; - } - } - -public: - float getTemperature() { - return outputTemperature; - } - - bool isValid() { - return outputTemperature.isValid(); - } - - static const uint16_t ADDRESS_A = 0; - static const uint16_t ADDRESS_B = 1; - static const uint16_t ADDRESS_C = 2; - static const uint16_t ADDRESS_GRADIENT = 3; - - static const uint16_t DEFAULT_CONFIRMATION_COUNT = 1; //!< Changed due to issue with later temperature checking even tough the sensor monitor was confirming already (Was 10 before with comment = Correlates to a 10s confirmation time. Chosen rather large, should not be so bad for components and helps survive glitches.) - - static const uint8_t DOMAIN_ID_SENSOR = 1; - - virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, - ParameterWrapper *parameterWrapper, - const ParameterWrapper *newValues, uint16_t startAtIndex) { - ReturnValue_t result = sensorMonitor.getParameter(domainId, parameterId, - parameterWrapper, newValues, startAtIndex); - if (result != INVALID_DOMAIN_ID) { - return result; - } - if (domainId != this->DOMAIN_ID_BASE) { - return INVALID_DOMAIN_ID; - } - switch (parameterId) { - case ADDRESS_A: - parameterWrapper->set(parameters.a); - break; - case ADDRESS_B: - parameterWrapper->set(parameters.b); - break; - case ADDRESS_C: - parameterWrapper->set(parameters.c); - break; - case ADDRESS_GRADIENT: - parameterWrapper->set(parameters.gradient); - break; - default: - return INVALID_MATRIX_ID; - } - return HasReturnvaluesIF::RETURN_OK; - } - - virtual void resetOldState() { - sensorMonitor.setToUnchecked(); - } - -}; - -#endif /* TEMPERATURESENSOR_H_ */ +#ifndef TEMPERATURESENSOR_H_ +#define TEMPERATURESENSOR_H_ + +#include "../thermal/AbstractTemperatureSensor.h" +#include "../datapoolglob/GlobalDataSet.h" +#include "../datapoolglob/GlobalPoolVariable.h" +#include "../monitoring/LimitMonitor.h" + +/** + * @brief This building block handles non-linear value conversion and + * range checks for analog temperature sensors. + * @details This class can be used to perform all necessary tasks for temperature sensors. + * A sensor can be instantiated by calling the constructor. + * The temperature is calculated from an input value with + * the calculateOutputTemperature() function. Range checking and + * limit monitoring is performed automatically. + * The inputType specifies the type of the raw input while the + * limitType specifies the type of the upper and lower limit to check against. + * @ingroup thermal + */ + +template +class TemperatureSensor: public AbstractTemperatureSensor { +public: + /** + * This structure contains parameters required for range checking + * and the conversion from the input value to the output temperature. + * a, b and c can be any parameters required to calculate the output + * temperature from the input value, depending on the formula used. + * + * The parameters a,b and c are used in the calculateOutputTemperature() call. + * + * The lower and upper limits can be specified in any type, for example float for C values + * or any other type for raw values. + */ + struct Parameters { + float a; + float b; + float c; + limitType lowerLimit; + limitType upperLimit; + float maxGradient; + }; + + /** + * Forward declaration for explicit instantiation of used parameters. + */ + struct UsedParameters { + UsedParameters(Parameters parameters) : + a(parameters.a), b(parameters.b), c(parameters.c), + gradient(parameters.maxGradient) {} + float a; + float b; + float c; + float gradient; + }; + + /** + * Instantiate Temperature Sensor Object. + * @param setObjectid objectId of the sensor object + * @param inputValue Input value which is converted to a temperature + * @param poolVariable Pool Variable to store the temperature value + * @param vectorIndex Vector Index for the sensor monitor + * @param parameters Calculation parameters, temperature limits, gradient limit + * @param datapoolId Datapool ID of the output temperature + * @param outputSet Output dataset for the output temperature to fetch it with read() + * @param thermalModule respective thermal module, if it has one + */ + TemperatureSensor(object_id_t setObjectid, + inputType *inputValue, PoolVariableIF *poolVariable, + uint8_t vectorIndex, uint32_t datapoolId, Parameters parameters = {0, 0, 0, 0, 0, 0}, + GlobDataSet *outputSet = NULL, ThermalModuleIF *thermalModule = NULL) : + AbstractTemperatureSensor(setObjectid, thermalModule), parameters(parameters), + inputValue(inputValue), poolVariable(poolVariable), + outputTemperature(datapoolId, outputSet, PoolVariableIF::VAR_WRITE), + sensorMonitor(setObjectid, DOMAIN_ID_SENSOR, + GlobalDataPool::poolIdAndPositionToPid(poolVariable->getDataPoolId(), vectorIndex), + DEFAULT_CONFIRMATION_COUNT, parameters.lowerLimit, parameters.upperLimit, + TEMP_SENSOR_LOW, TEMP_SENSOR_HIGH), + oldTemperature(20), uptimeOfOldTemperature( { INVALID_TEMPERATURE, 0 }) { + } + + +protected: + /** + * This formula is used to calculate the temperature from an input value + * with an arbitrary type. + * A default implementation is provided but can be replaced depending + * on the required calculation. + * @param inputTemperature + * @return + */ + virtual float calculateOutputTemperature(inputType inputValue) { + return parameters.a * inputValue * inputValue + + parameters.b * inputValue + parameters.c; + } + + +private: + void setInvalid() { + outputTemperature = INVALID_TEMPERATURE; + outputTemperature.setValid(false); + uptimeOfOldTemperature.tv_sec = INVALID_UPTIME; + sensorMonitor.setToInvalid(); + } +protected: + static const int32_t INVALID_UPTIME = 0; + + UsedParameters parameters; + + inputType * inputValue; + + PoolVariableIF *poolVariable; + + gp_float_t outputTemperature; + + LimitMonitor sensorMonitor; + + float oldTemperature; + timeval uptimeOfOldTemperature; + + void doChildOperation() { + if (!poolVariable->isValid() + || !healthHelper.healthTable->isHealthy(getObjectId())) { + setInvalid(); + return; + } + + outputTemperature = calculateOutputTemperature(*inputValue); + outputTemperature.setValid(PoolVariableIF::VALID); + + timeval uptime; + Clock::getUptime(&uptime); + + if (uptimeOfOldTemperature.tv_sec != INVALID_UPTIME) { + //In theory, we could use an AbsValueMonitor to monitor the gradient. + //But this would require storing the maxGradient in DP and quite some overhead. + //The concept of delta limits is a bit strange anyway. + float deltaTime; + float deltaTemp; + + deltaTime = (uptime.tv_sec + uptime.tv_usec / 1000000.) + - (uptimeOfOldTemperature.tv_sec + + uptimeOfOldTemperature.tv_usec / 1000000.); + deltaTemp = oldTemperature - outputTemperature; + if (deltaTemp < 0) { + deltaTemp = -deltaTemp; + } + if (parameters.gradient < deltaTemp / deltaTime) { + triggerEvent(TEMP_SENSOR_GRADIENT); + //Don't set invalid, as we did not recognize it as invalid with full authority, let FDIR handle it + } + } + + //Check is done against raw limits. SHOULDDO: Why? Using �C would be more easy to handle. + sensorMonitor.doCheck(outputTemperature.value); + + if (sensorMonitor.isOutOfLimits()) { + uptimeOfOldTemperature.tv_sec = INVALID_UPTIME; + outputTemperature.setValid(PoolVariableIF::INVALID); + outputTemperature = INVALID_TEMPERATURE; + } else { + oldTemperature = outputTemperature; + uptimeOfOldTemperature = uptime; + } + } + +public: + float getTemperature() { + return outputTemperature; + } + + bool isValid() { + return outputTemperature.isValid(); + } + + static const uint16_t ADDRESS_A = 0; + static const uint16_t ADDRESS_B = 1; + static const uint16_t ADDRESS_C = 2; + static const uint16_t ADDRESS_GRADIENT = 3; + + static const uint16_t DEFAULT_CONFIRMATION_COUNT = 1; //!< Changed due to issue with later temperature checking even tough the sensor monitor was confirming already (Was 10 before with comment = Correlates to a 10s confirmation time. Chosen rather large, should not be so bad for components and helps survive glitches.) + + static const uint8_t DOMAIN_ID_SENSOR = 1; + + virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, + ParameterWrapper *parameterWrapper, + const ParameterWrapper *newValues, uint16_t startAtIndex) { + ReturnValue_t result = sensorMonitor.getParameter(domainId, parameterId, + parameterWrapper, newValues, startAtIndex); + if (result != INVALID_DOMAIN_ID) { + return result; + } + if (domainId != this->DOMAIN_ID_BASE) { + return INVALID_DOMAIN_ID; + } + switch (parameterId) { + case ADDRESS_A: + parameterWrapper->set(parameters.a); + break; + case ADDRESS_B: + parameterWrapper->set(parameters.b); + break; + case ADDRESS_C: + parameterWrapper->set(parameters.c); + break; + case ADDRESS_GRADIENT: + parameterWrapper->set(parameters.gradient); + break; + default: + return INVALID_MATRIX_ID; + } + return HasReturnvaluesIF::RETURN_OK; + } + + virtual void resetOldState() { + sensorMonitor.setToUnchecked(); + } + +}; + +#endif /* TEMPERATURESENSOR_H_ */ diff --git a/thermal/ThermalComponentIF.h b/thermal/ThermalComponentIF.h index ad8dbd0a..f5f49ba1 100644 --- a/thermal/ThermalComponentIF.h +++ b/thermal/ThermalComponentIF.h @@ -1,114 +1,114 @@ -#ifndef THERMALCOMPONENTIF_H_ -#define THERMALCOMPONENTIF_H_ - -#include -#include -#include -#include - -class ThermalComponentIF : public HasParametersIF { -public: - - static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::TCS_1; - static const Event COMPONENT_TEMP_LOW = MAKE_EVENT(1, SEVERITY::LOW); - static const Event COMPONENT_TEMP_HIGH = MAKE_EVENT(2, SEVERITY::LOW); - static const Event COMPONENT_TEMP_OOL_LOW = MAKE_EVENT(3, SEVERITY::LOW); - static const Event COMPONENT_TEMP_OOL_HIGH = MAKE_EVENT(4, SEVERITY::LOW); - static const Event TEMP_NOT_IN_OP_RANGE = MAKE_EVENT(5, SEVERITY::LOW); //!< Is thrown when a device should start-up, but the temperature is out of OP range. P1: thermalState of the component, P2: 0 - - static const uint8_t INTERFACE_ID = CLASS_ID::THERMAL_COMPONENT_IF; - static const ReturnValue_t INVALID_TARGET_STATE = MAKE_RETURN_CODE(1); - static const ReturnValue_t ABOVE_OPERATIONAL_LIMIT = MAKE_RETURN_CODE(0xF1); - static const ReturnValue_t BELOW_OPERATIONAL_LIMIT = MAKE_RETURN_CODE(0xF2); - - enum State { - OUT_OF_RANGE_LOW = -2, - NON_OPERATIONAL_LOW = -1, - OPERATIONAL = 0, - NON_OPERATIONAL_HIGH = 1, - OUT_OF_RANGE_HIGH = 2, - OUT_OF_RANGE_LOW_IGNORED = OUT_OF_RANGE_LOW - 10, - NON_OPERATIONAL_LOW_IGNORED = NON_OPERATIONAL_LOW - 10, - OPERATIONAL_IGNORED = OPERATIONAL + 10, - NON_OPERATIONAL_HIGH_IGNORED = NON_OPERATIONAL_HIGH + 10, - OUT_OF_RANGE_HIGH_IGNORED = OUT_OF_RANGE_HIGH + 10, - UNKNOWN = 20 - }; - - enum StateRequest { - STATE_REQUEST_HEATING = 4, - STATE_REQUEST_IGNORE = 3, - STATE_REQUEST_OPERATIONAL = 1, - STATE_REQUEST_NON_OPERATIONAL = 0 - }; - - /** - * The elements are ordered by priority, lowest have highest priority - */ - enum Priority { - SAFE = 0, //!< SAFE - IDLE, //!< IDLE - PAYLOAD, //!< PAYLOAD - NUMBER_OF_PRIORITIES //!< MAX_PRIORITY - }; - - /** - * The elements are ordered by priority, lowest have highest priority - */ - enum HeaterRequest { - HEATER_REQUEST_EMERGENCY_OFF = 0, //!< REQUEST_EMERGENCY_OFF - HEATER_REQUEST_EMERGENCY_ON, //!< REQUEST_EMERGENCY_ON - HEATER_REQUEST_OFF, //!< REQUEST_OFF - HEATER_REQUEST_ON, //!< REQUEST_ON - HEATER_DONT_CARE //!< DONT_CARE - }; - - virtual ~ThermalComponentIF() { - - } - - virtual HeaterRequest performOperation(uint8_t opCode) = 0; - - virtual object_id_t getObjectId() = 0; - - virtual uint8_t getDomainId() const = 0; - - virtual void markStateIgnored() = 0; - - virtual float getLowerOpLimit() = 0; - - virtual ReturnValue_t setTargetState(int8_t state) = 0; - - virtual void setOutputInvalid() = 0; - - static bool isOperational(int8_t state) { - return ((state == OPERATIONAL) || (state == OPERATIONAL_IGNORED)); - } - - static bool isOutOfRange(State state) { - return ((state == OUT_OF_RANGE_HIGH) - || (state == OUT_OF_RANGE_HIGH_IGNORED) - || (state == OUT_OF_RANGE_LOW) - || (state == OUT_OF_RANGE_LOW_IGNORED) || (state == UNKNOWN)); - } - - static bool isNonOperational(State state) { - return !isOutOfRange(state); - } - - static bool isIgnoredState(State state) { - switch (state) { - case OUT_OF_RANGE_LOW_IGNORED: - case OUT_OF_RANGE_HIGH_IGNORED: - case NON_OPERATIONAL_LOW_IGNORED: - case NON_OPERATIONAL_HIGH_IGNORED: - case OPERATIONAL_IGNORED: - case UNKNOWN: - return true; - default: - return false; - } - } -}; - -#endif /* THERMALCOMPONENTIF_H_ */ +#ifndef THERMALCOMPONENTIF_H_ +#define THERMALCOMPONENTIF_H_ + +#include "../events/Event.h" +#include "../parameters/HasParametersIF.h" +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../objectmanager/SystemObjectIF.h" + +class ThermalComponentIF : public HasParametersIF { +public: + + static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::TCS_1; + static const Event COMPONENT_TEMP_LOW = MAKE_EVENT(1, SEVERITY::LOW); + static const Event COMPONENT_TEMP_HIGH = MAKE_EVENT(2, SEVERITY::LOW); + static const Event COMPONENT_TEMP_OOL_LOW = MAKE_EVENT(3, SEVERITY::LOW); + static const Event COMPONENT_TEMP_OOL_HIGH = MAKE_EVENT(4, SEVERITY::LOW); + static const Event TEMP_NOT_IN_OP_RANGE = MAKE_EVENT(5, SEVERITY::LOW); //!< Is thrown when a device should start-up, but the temperature is out of OP range. P1: thermalState of the component, P2: 0 + + static const uint8_t INTERFACE_ID = CLASS_ID::THERMAL_COMPONENT_IF; + static const ReturnValue_t INVALID_TARGET_STATE = MAKE_RETURN_CODE(1); + static const ReturnValue_t ABOVE_OPERATIONAL_LIMIT = MAKE_RETURN_CODE(0xF1); + static const ReturnValue_t BELOW_OPERATIONAL_LIMIT = MAKE_RETURN_CODE(0xF2); + + enum State { + OUT_OF_RANGE_LOW = -2, + NON_OPERATIONAL_LOW = -1, + OPERATIONAL = 0, + NON_OPERATIONAL_HIGH = 1, + OUT_OF_RANGE_HIGH = 2, + OUT_OF_RANGE_LOW_IGNORED = OUT_OF_RANGE_LOW - 10, + NON_OPERATIONAL_LOW_IGNORED = NON_OPERATIONAL_LOW - 10, + OPERATIONAL_IGNORED = OPERATIONAL + 10, + NON_OPERATIONAL_HIGH_IGNORED = NON_OPERATIONAL_HIGH + 10, + OUT_OF_RANGE_HIGH_IGNORED = OUT_OF_RANGE_HIGH + 10, + UNKNOWN = 20 + }; + + enum StateRequest { + STATE_REQUEST_HEATING = 4, + STATE_REQUEST_IGNORE = 3, + STATE_REQUEST_OPERATIONAL = 1, + STATE_REQUEST_NON_OPERATIONAL = 0 + }; + + /** + * The elements are ordered by priority, lowest have highest priority + */ + enum Priority { + SAFE = 0, //!< SAFE + IDLE, //!< IDLE + PAYLOAD, //!< PAYLOAD + NUMBER_OF_PRIORITIES //!< MAX_PRIORITY + }; + + /** + * The elements are ordered by priority, lowest have highest priority + */ + enum HeaterRequest { + HEATER_REQUEST_EMERGENCY_OFF = 0, //!< REQUEST_EMERGENCY_OFF + HEATER_REQUEST_EMERGENCY_ON, //!< REQUEST_EMERGENCY_ON + HEATER_REQUEST_OFF, //!< REQUEST_OFF + HEATER_REQUEST_ON, //!< REQUEST_ON + HEATER_DONT_CARE //!< DONT_CARE + }; + + virtual ~ThermalComponentIF() { + + } + + virtual HeaterRequest performOperation(uint8_t opCode) = 0; + + virtual object_id_t getObjectId() = 0; + + virtual uint8_t getDomainId() const = 0; + + virtual void markStateIgnored() = 0; + + virtual float getLowerOpLimit() = 0; + + virtual ReturnValue_t setTargetState(int8_t state) = 0; + + virtual void setOutputInvalid() = 0; + + static bool isOperational(int8_t state) { + return ((state == OPERATIONAL) || (state == OPERATIONAL_IGNORED)); + } + + static bool isOutOfRange(State state) { + return ((state == OUT_OF_RANGE_HIGH) + || (state == OUT_OF_RANGE_HIGH_IGNORED) + || (state == OUT_OF_RANGE_LOW) + || (state == OUT_OF_RANGE_LOW_IGNORED) || (state == UNKNOWN)); + } + + static bool isNonOperational(State state) { + return !isOutOfRange(state); + } + + static bool isIgnoredState(State state) { + switch (state) { + case OUT_OF_RANGE_LOW_IGNORED: + case OUT_OF_RANGE_HIGH_IGNORED: + case NON_OPERATIONAL_LOW_IGNORED: + case NON_OPERATIONAL_HIGH_IGNORED: + case OPERATIONAL_IGNORED: + case UNKNOWN: + return true; + default: + return false; + } + } +}; + +#endif /* THERMALCOMPONENTIF_H_ */ diff --git a/thermal/ThermalModule.cpp b/thermal/ThermalModule.cpp index 9dc1f237..7ee6b96b 100644 --- a/thermal/ThermalModule.cpp +++ b/thermal/ThermalModule.cpp @@ -1,288 +1,288 @@ -#include -#include -#include "ThermalModule.h" - -#include "AbstractTemperatureSensor.h" - -ThermalModule::ThermalModule(uint32_t moduleTemperaturePoolId, - uint32_t currentStatePoolId, uint32_t targetStatePoolId, - GlobDataSet *dataSet, Parameters parameters, - RedundantHeater::Parameters heaterParameters) : - oldStrategy(ACTIVE_SINGLE), survivalTargetTemp(0), targetTemp(0), heating( - false), parameters(parameters), moduleTemperature( - moduleTemperaturePoolId, dataSet, PoolVariableIF::VAR_WRITE), currentState( - currentStatePoolId, dataSet, PoolVariableIF::VAR_WRITE), targetState( - targetStatePoolId, dataSet, PoolVariableIF::VAR_READ) { - heater = new RedundantHeater(heaterParameters); -} - -ThermalModule::ThermalModule(uint32_t moduleTemperaturePoolId, GlobDataSet* dataSet) : - oldStrategy(ACTIVE_SINGLE), survivalTargetTemp(0), targetTemp(0), heating( - false), parameters( { 0, 0 }), moduleTemperature( - moduleTemperaturePoolId, dataSet, PoolVariableIF::VAR_WRITE), heater( - NULL), currentState(PoolVariableIF::INVALID, dataSet, - PoolVariableIF::VAR_WRITE), targetState(PoolVariableIF::INVALID, - dataSet, PoolVariableIF::VAR_READ) { -} - -ThermalModule::~ThermalModule() { - delete heater; -} - -void ThermalModule::performOperation(uint8_t opCode) { - if (heater != NULL) { - heater->performOperation(0); - } -} - -void ThermalModule::performMode(Strategy strategy) { - calculateTemperature(); - - bool safeOnly = (strategy == ACTIVE_SURVIVAL); - ThermalComponentIF::HeaterRequest componentHeaterRequest = - letComponentsPerformAndDeciceIfWeNeedToHeat(safeOnly); - - if (heater == NULL) { - informComponentsAboutHeaterState(false, NONE); - return; - } - - bool heating = calculateModuleHeaterRequestAndSetModuleStatus(strategy); - - if (componentHeaterRequest != ThermalComponentIF::HEATER_DONT_CARE) { - //Components overwrite the module request. - heating = ((componentHeaterRequest - == ThermalComponentIF::HEATER_REQUEST_ON) - || (componentHeaterRequest - == ThermalComponentIF::HEATER_REQUEST_EMERGENCY_ON)); - } - - bool dual = (strategy == ACTIVE_DUAL); - - if (strategy == PASSIVE) { - informComponentsAboutHeaterState(false, NONE); - if (oldStrategy != PASSIVE) { - heater->set(false, false, true); - } - } else { - if (safeOnly) { - informComponentsAboutHeaterState(heating, SAFE); - } else { - informComponentsAboutHeaterState(heating, ALL); - } - heater->set(heating, dual); - } - oldStrategy = strategy; -} - -float ThermalModule::getTemperature() { - return moduleTemperature; -} - -void ThermalModule::registerSensor(AbstractTemperatureSensor * sensor) { - sensors.push_back(sensor); -} - -void ThermalModule::registerComponent(ThermalComponentIF* component, - ThermalComponentIF::Priority priority) { - components.push_back(ComponentData( { component, priority, ThermalComponentIF::HEATER_DONT_CARE })); -} - -void ThermalModule::calculateTemperature() { - uint32_t numberOfValidSensors = 0; - moduleTemperature = 0; - std::list::iterator iter = sensors.begin(); - for (; iter != sensors.end(); iter++) { - if ((*iter)->isValid()) { - moduleTemperature = moduleTemperature + (*iter)->getTemperature(); - numberOfValidSensors++; - } - } - if (numberOfValidSensors != 0) { - moduleTemperature = moduleTemperature / numberOfValidSensors; - moduleTemperature.setValid(PoolVariableIF::VALID); - } else { - moduleTemperature = INVALID_TEMPERATURE; - moduleTemperature.setValid(PoolVariableIF::INVALID); - } -} - -ThermalComponentIF* ThermalModule::findComponent(object_id_t objectId) { - std::list::iterator iter = components.begin(); - for (; iter != components.end(); iter++) { - if (iter->component->getObjectId() == objectId) { - return iter->component; - } - } - return NULL; -} - -ThermalComponentIF::HeaterRequest ThermalModule::letComponentsPerformAndDeciceIfWeNeedToHeat( - bool safeOnly) { - ThermalComponentIF::HeaterRequest heaterRequests[ThermalComponentIF::NUMBER_OF_PRIORITIES]; - - survivalTargetTemp = -999; - targetTemp = -999; - - for (uint8_t i = 0; i < ThermalComponentIF::NUMBER_OF_PRIORITIES; i++) { - heaterRequests[i] = ThermalComponentIF::HEATER_DONT_CARE; - } - - std::list::iterator iter = components.begin(); - for (; iter != components.end(); iter++) { - updateTargetTemperatures(iter->component, - iter->priority == ThermalComponentIF::SAFE); - ThermalComponentIF::HeaterRequest request = - iter->component->performOperation(0); - iter->request = request; - if (request != ThermalComponentIF::HEATER_DONT_CARE) { - if (request < heaterRequests[iter->priority]) { - heaterRequests[iter->priority] = request; - } - } - } - - if (!safeOnly) { - for (uint8_t i = ThermalComponentIF::NUMBER_OF_PRIORITIES - 1; i > 0; - i--) { - if (heaterRequests[i - 1] == ThermalComponentIF::HEATER_DONT_CARE) { - heaterRequests[i - 1] = heaterRequests[i]; - } - } - } - return heaterRequests[0]; -} - -void ThermalModule::informComponentsAboutHeaterState(bool heaterIsOn, - Informee whomToInform) { - std::list::iterator iter = components.begin(); - for (; iter != components.end(); iter++) { - switch (whomToInform) { - case ALL: - break; - case SAFE: - if (!(iter->priority == ThermalComponentIF::SAFE)) { - iter->component->markStateIgnored(); - continue; - } - break; - case NONE: - iter->component->markStateIgnored(); - continue; - } - - if (heaterIsOn) { - if ((iter->request - == ThermalComponentIF::HEATER_REQUEST_EMERGENCY_OFF) - || (iter->request == ThermalComponentIF::HEATER_REQUEST_OFF)) { - iter->component->markStateIgnored(); - } - } else { - if ((iter->request - == ThermalComponentIF::HEATER_REQUEST_EMERGENCY_ON) - || (iter->request == ThermalComponentIF::HEATER_REQUEST_ON)) { - iter->component->markStateIgnored(); - } - } - } -} - -void ThermalModule::initialize(PowerSwitchIF* powerSwitch) { - if (heater != NULL) { - heater->setPowerSwitcher(powerSwitch); - } - - std::list::iterator iter = components.begin(); - for (; iter != components.end(); iter++) { - float componentLowerOpLimit = iter->component->getLowerOpLimit(); - if (iter->priority == ThermalComponentIF::SAFE) { - if (componentLowerOpLimit > survivalTargetTemp) { - survivalTargetTemp = componentLowerOpLimit; - } - } else { - if (componentLowerOpLimit > targetTemp) { - targetTemp = componentLowerOpLimit; - } - } - } - if (survivalTargetTemp > targetTemp) { - targetTemp = survivalTargetTemp; - } -} - -bool ThermalModule::calculateModuleHeaterRequestAndSetModuleStatus( - Strategy strategy) { - currentState.setValid(PoolVariableIF::VALID); - if (moduleTemperature == INVALID_TEMPERATURE) { - currentState = UNKNOWN; - return false; - } - - float limit = targetTemp; - bool heaterRequest = false; - if (strategy == ACTIVE_SURVIVAL) { - limit = survivalTargetTemp; - } - - if (moduleTemperature >= limit) { - currentState = OPERATIONAL; - } else { - currentState = NON_OPERATIONAL; - } - - limit += parameters.heaterOn; - - if (heating) { - limit += parameters.hysteresis; - } - - if (targetState == STATE_REQUEST_HEATING) { - if (moduleTemperature < limit) { - heaterRequest = true; - } else { - heaterRequest = false; - } - } - - heating = heaterRequest; - - return heaterRequest; -} - -void ThermalModule::setHeating(bool on) { - GlobDataSet mySet; - gp_int8_t writableTargetState(targetState.getDataPoolId(), - &mySet, PoolVariableIF::VAR_WRITE); - if (on) { - writableTargetState = STATE_REQUEST_HEATING; - } else { - writableTargetState = STATE_REQUEST_PASSIVE; - } - mySet.commit(PoolVariableIF::VALID); -} - -void ThermalModule::updateTargetTemperatures(ThermalComponentIF* component, - bool isSafe) { - if (isSafe) { - if (component->getLowerOpLimit() > survivalTargetTemp) { - survivalTargetTemp = component->getLowerOpLimit(); - } - } else { - if (component->getLowerOpLimit() > targetTemp) { - targetTemp = component->getLowerOpLimit(); - } - } -} - -void ThermalModule::setOutputInvalid() { - moduleTemperature = INVALID_TEMPERATURE; - moduleTemperature.setValid(PoolVariableIF::INVALID); - currentState.setValid(PoolVariableIF::INVALID); - std::list::iterator iter = components.begin(); - for (; iter != components.end(); iter++) { - iter->component->setOutputInvalid(); - } - if (heater != NULL) { - heater->set(false,true); - } -} +#include "../monitoring/LimitViolationReporter.h" +#include "../monitoring/MonitoringMessageContent.h" +#include "ThermalModule.h" + +#include "AbstractTemperatureSensor.h" + +ThermalModule::ThermalModule(uint32_t moduleTemperaturePoolId, + uint32_t currentStatePoolId, uint32_t targetStatePoolId, + GlobDataSet *dataSet, Parameters parameters, + RedundantHeater::Parameters heaterParameters) : + oldStrategy(ACTIVE_SINGLE), survivalTargetTemp(0), targetTemp(0), heating( + false), parameters(parameters), moduleTemperature( + moduleTemperaturePoolId, dataSet, PoolVariableIF::VAR_WRITE), currentState( + currentStatePoolId, dataSet, PoolVariableIF::VAR_WRITE), targetState( + targetStatePoolId, dataSet, PoolVariableIF::VAR_READ) { + heater = new RedundantHeater(heaterParameters); +} + +ThermalModule::ThermalModule(uint32_t moduleTemperaturePoolId, GlobDataSet* dataSet) : + oldStrategy(ACTIVE_SINGLE), survivalTargetTemp(0), targetTemp(0), heating( + false), parameters( { 0, 0 }), moduleTemperature( + moduleTemperaturePoolId, dataSet, PoolVariableIF::VAR_WRITE), heater( + NULL), currentState(PoolVariableIF::INVALID, dataSet, + PoolVariableIF::VAR_WRITE), targetState(PoolVariableIF::INVALID, + dataSet, PoolVariableIF::VAR_READ) { +} + +ThermalModule::~ThermalModule() { + delete heater; +} + +void ThermalModule::performOperation(uint8_t opCode) { + if (heater != NULL) { + heater->performOperation(0); + } +} + +void ThermalModule::performMode(Strategy strategy) { + calculateTemperature(); + + bool safeOnly = (strategy == ACTIVE_SURVIVAL); + ThermalComponentIF::HeaterRequest componentHeaterRequest = + letComponentsPerformAndDeciceIfWeNeedToHeat(safeOnly); + + if (heater == NULL) { + informComponentsAboutHeaterState(false, NONE); + return; + } + + bool heating = calculateModuleHeaterRequestAndSetModuleStatus(strategy); + + if (componentHeaterRequest != ThermalComponentIF::HEATER_DONT_CARE) { + //Components overwrite the module request. + heating = ((componentHeaterRequest + == ThermalComponentIF::HEATER_REQUEST_ON) + || (componentHeaterRequest + == ThermalComponentIF::HEATER_REQUEST_EMERGENCY_ON)); + } + + bool dual = (strategy == ACTIVE_DUAL); + + if (strategy == PASSIVE) { + informComponentsAboutHeaterState(false, NONE); + if (oldStrategy != PASSIVE) { + heater->set(false, false, true); + } + } else { + if (safeOnly) { + informComponentsAboutHeaterState(heating, SAFE); + } else { + informComponentsAboutHeaterState(heating, ALL); + } + heater->set(heating, dual); + } + oldStrategy = strategy; +} + +float ThermalModule::getTemperature() { + return moduleTemperature; +} + +void ThermalModule::registerSensor(AbstractTemperatureSensor * sensor) { + sensors.push_back(sensor); +} + +void ThermalModule::registerComponent(ThermalComponentIF* component, + ThermalComponentIF::Priority priority) { + components.push_back(ComponentData( { component, priority, ThermalComponentIF::HEATER_DONT_CARE })); +} + +void ThermalModule::calculateTemperature() { + uint32_t numberOfValidSensors = 0; + moduleTemperature = 0; + std::list::iterator iter = sensors.begin(); + for (; iter != sensors.end(); iter++) { + if ((*iter)->isValid()) { + moduleTemperature = moduleTemperature + (*iter)->getTemperature(); + numberOfValidSensors++; + } + } + if (numberOfValidSensors != 0) { + moduleTemperature = moduleTemperature / numberOfValidSensors; + moduleTemperature.setValid(PoolVariableIF::VALID); + } else { + moduleTemperature = INVALID_TEMPERATURE; + moduleTemperature.setValid(PoolVariableIF::INVALID); + } +} + +ThermalComponentIF* ThermalModule::findComponent(object_id_t objectId) { + std::list::iterator iter = components.begin(); + for (; iter != components.end(); iter++) { + if (iter->component->getObjectId() == objectId) { + return iter->component; + } + } + return NULL; +} + +ThermalComponentIF::HeaterRequest ThermalModule::letComponentsPerformAndDeciceIfWeNeedToHeat( + bool safeOnly) { + ThermalComponentIF::HeaterRequest heaterRequests[ThermalComponentIF::NUMBER_OF_PRIORITIES]; + + survivalTargetTemp = -999; + targetTemp = -999; + + for (uint8_t i = 0; i < ThermalComponentIF::NUMBER_OF_PRIORITIES; i++) { + heaterRequests[i] = ThermalComponentIF::HEATER_DONT_CARE; + } + + std::list::iterator iter = components.begin(); + for (; iter != components.end(); iter++) { + updateTargetTemperatures(iter->component, + iter->priority == ThermalComponentIF::SAFE); + ThermalComponentIF::HeaterRequest request = + iter->component->performOperation(0); + iter->request = request; + if (request != ThermalComponentIF::HEATER_DONT_CARE) { + if (request < heaterRequests[iter->priority]) { + heaterRequests[iter->priority] = request; + } + } + } + + if (!safeOnly) { + for (uint8_t i = ThermalComponentIF::NUMBER_OF_PRIORITIES - 1; i > 0; + i--) { + if (heaterRequests[i - 1] == ThermalComponentIF::HEATER_DONT_CARE) { + heaterRequests[i - 1] = heaterRequests[i]; + } + } + } + return heaterRequests[0]; +} + +void ThermalModule::informComponentsAboutHeaterState(bool heaterIsOn, + Informee whomToInform) { + std::list::iterator iter = components.begin(); + for (; iter != components.end(); iter++) { + switch (whomToInform) { + case ALL: + break; + case SAFE: + if (!(iter->priority == ThermalComponentIF::SAFE)) { + iter->component->markStateIgnored(); + continue; + } + break; + case NONE: + iter->component->markStateIgnored(); + continue; + } + + if (heaterIsOn) { + if ((iter->request + == ThermalComponentIF::HEATER_REQUEST_EMERGENCY_OFF) + || (iter->request == ThermalComponentIF::HEATER_REQUEST_OFF)) { + iter->component->markStateIgnored(); + } + } else { + if ((iter->request + == ThermalComponentIF::HEATER_REQUEST_EMERGENCY_ON) + || (iter->request == ThermalComponentIF::HEATER_REQUEST_ON)) { + iter->component->markStateIgnored(); + } + } + } +} + +void ThermalModule::initialize(PowerSwitchIF* powerSwitch) { + if (heater != NULL) { + heater->setPowerSwitcher(powerSwitch); + } + + std::list::iterator iter = components.begin(); + for (; iter != components.end(); iter++) { + float componentLowerOpLimit = iter->component->getLowerOpLimit(); + if (iter->priority == ThermalComponentIF::SAFE) { + if (componentLowerOpLimit > survivalTargetTemp) { + survivalTargetTemp = componentLowerOpLimit; + } + } else { + if (componentLowerOpLimit > targetTemp) { + targetTemp = componentLowerOpLimit; + } + } + } + if (survivalTargetTemp > targetTemp) { + targetTemp = survivalTargetTemp; + } +} + +bool ThermalModule::calculateModuleHeaterRequestAndSetModuleStatus( + Strategy strategy) { + currentState.setValid(PoolVariableIF::VALID); + if (moduleTemperature == INVALID_TEMPERATURE) { + currentState = UNKNOWN; + return false; + } + + float limit = targetTemp; + bool heaterRequest = false; + if (strategy == ACTIVE_SURVIVAL) { + limit = survivalTargetTemp; + } + + if (moduleTemperature >= limit) { + currentState = OPERATIONAL; + } else { + currentState = NON_OPERATIONAL; + } + + limit += parameters.heaterOn; + + if (heating) { + limit += parameters.hysteresis; + } + + if (targetState == STATE_REQUEST_HEATING) { + if (moduleTemperature < limit) { + heaterRequest = true; + } else { + heaterRequest = false; + } + } + + heating = heaterRequest; + + return heaterRequest; +} + +void ThermalModule::setHeating(bool on) { + GlobDataSet mySet; + gp_int8_t writableTargetState(targetState.getDataPoolId(), + &mySet, PoolVariableIF::VAR_WRITE); + if (on) { + writableTargetState = STATE_REQUEST_HEATING; + } else { + writableTargetState = STATE_REQUEST_PASSIVE; + } + mySet.commit(PoolVariableIF::VALID); +} + +void ThermalModule::updateTargetTemperatures(ThermalComponentIF* component, + bool isSafe) { + if (isSafe) { + if (component->getLowerOpLimit() > survivalTargetTemp) { + survivalTargetTemp = component->getLowerOpLimit(); + } + } else { + if (component->getLowerOpLimit() > targetTemp) { + targetTemp = component->getLowerOpLimit(); + } + } +} + +void ThermalModule::setOutputInvalid() { + moduleTemperature = INVALID_TEMPERATURE; + moduleTemperature.setValid(PoolVariableIF::INVALID); + currentState.setValid(PoolVariableIF::INVALID); + std::list::iterator iter = components.begin(); + for (; iter != components.end(); iter++) { + iter->component->setOutputInvalid(); + } + if (heater != NULL) { + heater->set(false,true); + } +} diff --git a/thermal/ThermalModule.h b/thermal/ThermalModule.h index 21414f15..46692640 100644 --- a/thermal/ThermalModule.h +++ b/thermal/ThermalModule.h @@ -1,95 +1,95 @@ -#ifndef THERMALMODULE_H_ -#define THERMALMODULE_H_ - -#include -#include -#include -#include -#include "ThermalModuleIF.h" -#include -#include "tcsDefinitions.h" -#include "RedundantHeater.h" -class PowerSwitchIF; - -/** - * @brief Allows creation of different thermal control domains within a system. - */ -class ThermalModule: public ThermalModuleIF { - friend class ThermalController; -public: - struct Parameters { - float heaterOn; - float hysteresis; - }; - - ThermalModule(uint32_t moduleTemperaturePoolId, uint32_t currentStatePoolId, - uint32_t targetStatePoolId, GlobDataSet *dataSet, Parameters parameters, - RedundantHeater::Parameters heaterParameters); - - ThermalModule(uint32_t moduleTemperaturePoolId, GlobDataSet *dataSet); - - virtual ~ThermalModule(); - - void performOperation(uint8_t opCode); - - void performMode(Strategy strategy); - - float getTemperature(); - - void registerSensor(AbstractTemperatureSensor *sensor); - - void registerComponent(ThermalComponentIF *component, - ThermalComponentIF::Priority priority); - - ThermalComponentIF *findComponent(object_id_t objectId); - - void initialize(PowerSwitchIF* powerSwitch); - - void setHeating(bool on); - - virtual void setOutputInvalid(); - -protected: - enum Informee { - ALL, SAFE, NONE - }; - - struct ComponentData { - ThermalComponentIF *component; - ThermalComponentIF::Priority priority; - ThermalComponentIF::HeaterRequest request; - }; - - Strategy oldStrategy; - - float survivalTargetTemp; - - float targetTemp; - - bool heating; - - Parameters parameters; - - gp_float_t moduleTemperature; - - RedundantHeater *heater; - - gp_int8_t currentState; - gp_int8_t targetState; - - std::list sensors; - std::list components; - - void calculateTemperature(); - - ThermalComponentIF::HeaterRequest letComponentsPerformAndDeciceIfWeNeedToHeat(bool safeOnly); - - void informComponentsAboutHeaterState(bool heaterIsOn, - Informee whomToInform); - - bool calculateModuleHeaterRequestAndSetModuleStatus(Strategy strategy); - - void updateTargetTemperatures(ThermalComponentIF *component, bool isSafe); -}; - -#endif /* THERMALMODULE_H_ */ +#ifndef THERMALMODULE_H_ +#define THERMALMODULE_H_ + +#include "../datapoolglob/GlobalDataSet.h" +#include "../datapoolglob/GlobalPoolVariable.h" +#include "../devicehandlers/HealthDevice.h" +#include "../events/EventReportingProxyIF.h" +#include "ThermalModuleIF.h" +#include +#include "tcsDefinitions.h" +#include "RedundantHeater.h" +class PowerSwitchIF; + +/** + * @brief Allows creation of different thermal control domains within a system. + */ +class ThermalModule: public ThermalModuleIF { + friend class ThermalController; +public: + struct Parameters { + float heaterOn; + float hysteresis; + }; + + ThermalModule(uint32_t moduleTemperaturePoolId, uint32_t currentStatePoolId, + uint32_t targetStatePoolId, GlobDataSet *dataSet, Parameters parameters, + RedundantHeater::Parameters heaterParameters); + + ThermalModule(uint32_t moduleTemperaturePoolId, GlobDataSet *dataSet); + + virtual ~ThermalModule(); + + void performOperation(uint8_t opCode); + + void performMode(Strategy strategy); + + float getTemperature(); + + void registerSensor(AbstractTemperatureSensor *sensor); + + void registerComponent(ThermalComponentIF *component, + ThermalComponentIF::Priority priority); + + ThermalComponentIF *findComponent(object_id_t objectId); + + void initialize(PowerSwitchIF* powerSwitch); + + void setHeating(bool on); + + virtual void setOutputInvalid(); + +protected: + enum Informee { + ALL, SAFE, NONE + }; + + struct ComponentData { + ThermalComponentIF *component; + ThermalComponentIF::Priority priority; + ThermalComponentIF::HeaterRequest request; + }; + + Strategy oldStrategy; + + float survivalTargetTemp; + + float targetTemp; + + bool heating; + + Parameters parameters; + + gp_float_t moduleTemperature; + + RedundantHeater *heater; + + gp_int8_t currentState; + gp_int8_t targetState; + + std::list sensors; + std::list components; + + void calculateTemperature(); + + ThermalComponentIF::HeaterRequest letComponentsPerformAndDeciceIfWeNeedToHeat(bool safeOnly); + + void informComponentsAboutHeaterState(bool heaterIsOn, + Informee whomToInform); + + bool calculateModuleHeaterRequestAndSetModuleStatus(Strategy strategy); + + void updateTargetTemperatures(ThermalComponentIF *component, bool isSafe); +}; + +#endif /* THERMALMODULE_H_ */ diff --git a/thermal/ThermalMonitor.cpp b/thermal/ThermalMonitor.cpp index 773fa084..af0413bf 100644 --- a/thermal/ThermalMonitor.cpp +++ b/thermal/ThermalMonitor.cpp @@ -1,68 +1,68 @@ -#include -#include -#include -ThermalMonitor::~ThermalMonitor() { -} - -void ThermalMonitor::sendTransitionEvent(float currentValue, - ReturnValue_t state) { - switch (state) { - case MonitoringIF::BELOW_LOW_LIMIT: - EventManagerIF::triggerEvent(reportingId, - ThermalComponentIF::COMPONENT_TEMP_OOL_LOW, state); - break; - case MonitoringIF::ABOVE_HIGH_LIMIT: - EventManagerIF::triggerEvent(reportingId, - ThermalComponentIF::COMPONENT_TEMP_OOL_HIGH, state); - break; - case ThermalComponentIF::BELOW_OPERATIONAL_LIMIT: - EventManagerIF::triggerEvent(reportingId, - ThermalComponentIF::COMPONENT_TEMP_LOW, state); - break; - case ThermalComponentIF::ABOVE_OPERATIONAL_LIMIT: - EventManagerIF::triggerEvent(reportingId, - ThermalComponentIF::COMPONENT_TEMP_HIGH, state); - break; - default: - break; - } -} - -bool ThermalMonitor::isAboveHighLimit() { - if (oldState == ThermalComponentIF::ABOVE_OPERATIONAL_LIMIT) { - return true; - } else { - return false; - } -} - -ReturnValue_t ThermalMonitor::translateState(ThermalComponentIF::State state, float sample, float lowerLimit, - float upperLimit, bool componentIsOperational) { - if (ThermalComponentIF::isIgnoredState(state)) { - setToUnchecked(); - return MonitoringIF::UNCHECKED; - } - switch (state) { - case ThermalComponentIF::OUT_OF_RANGE_LOW: - return monitorStateIs(MonitoringIF::BELOW_LOW_LIMIT, sample, lowerLimit); - case ThermalComponentIF::NON_OPERATIONAL_LOW: - if (componentIsOperational) { - return monitorStateIs(ThermalComponentIF::BELOW_OPERATIONAL_LIMIT, sample, lowerLimit); - } else { - return monitorStateIs(HasReturnvaluesIF::RETURN_OK, sample, 0.0); - } - case ThermalComponentIF::OPERATIONAL: - return monitorStateIs(HasReturnvaluesIF::RETURN_OK, sample, 0.0); - case ThermalComponentIF::NON_OPERATIONAL_HIGH: - if (componentIsOperational) { - return monitorStateIs(ThermalComponentIF::ABOVE_OPERATIONAL_LIMIT, sample, upperLimit); - } else { - return monitorStateIs(HasReturnvaluesIF::RETURN_OK, sample, 0.0); - } - case ThermalComponentIF::OUT_OF_RANGE_HIGH: - return monitorStateIs(MonitoringIF::ABOVE_HIGH_LIMIT, sample, upperLimit); - default: - //Never reached, all states covered. - return HasReturnvaluesIF::RETURN_FAILED; - } -} +#include "../thermal/ThermalMonitor.h" +#include "../thermal/ThermalComponentIF.h" +#include "../monitoring/MonitoringIF.h" +ThermalMonitor::~ThermalMonitor() { +} + +void ThermalMonitor::sendTransitionEvent(float currentValue, + ReturnValue_t state) { + switch (state) { + case MonitoringIF::BELOW_LOW_LIMIT: + EventManagerIF::triggerEvent(reportingId, + ThermalComponentIF::COMPONENT_TEMP_OOL_LOW, state); + break; + case MonitoringIF::ABOVE_HIGH_LIMIT: + EventManagerIF::triggerEvent(reportingId, + ThermalComponentIF::COMPONENT_TEMP_OOL_HIGH, state); + break; + case ThermalComponentIF::BELOW_OPERATIONAL_LIMIT: + EventManagerIF::triggerEvent(reportingId, + ThermalComponentIF::COMPONENT_TEMP_LOW, state); + break; + case ThermalComponentIF::ABOVE_OPERATIONAL_LIMIT: + EventManagerIF::triggerEvent(reportingId, + ThermalComponentIF::COMPONENT_TEMP_HIGH, state); + break; + default: + break; + } +} + +bool ThermalMonitor::isAboveHighLimit() { + if (oldState == ThermalComponentIF::ABOVE_OPERATIONAL_LIMIT) { + return true; + } else { + return false; + } +} + +ReturnValue_t ThermalMonitor::translateState(ThermalComponentIF::State state, float sample, float lowerLimit, + float upperLimit, bool componentIsOperational) { + if (ThermalComponentIF::isIgnoredState(state)) { + setToUnchecked(); + return MonitoringIF::UNCHECKED; + } + switch (state) { + case ThermalComponentIF::OUT_OF_RANGE_LOW: + return monitorStateIs(MonitoringIF::BELOW_LOW_LIMIT, sample, lowerLimit); + case ThermalComponentIF::NON_OPERATIONAL_LOW: + if (componentIsOperational) { + return monitorStateIs(ThermalComponentIF::BELOW_OPERATIONAL_LIMIT, sample, lowerLimit); + } else { + return monitorStateIs(HasReturnvaluesIF::RETURN_OK, sample, 0.0); + } + case ThermalComponentIF::OPERATIONAL: + return monitorStateIs(HasReturnvaluesIF::RETURN_OK, sample, 0.0); + case ThermalComponentIF::NON_OPERATIONAL_HIGH: + if (componentIsOperational) { + return monitorStateIs(ThermalComponentIF::ABOVE_OPERATIONAL_LIMIT, sample, upperLimit); + } else { + return monitorStateIs(HasReturnvaluesIF::RETURN_OK, sample, 0.0); + } + case ThermalComponentIF::OUT_OF_RANGE_HIGH: + return monitorStateIs(MonitoringIF::ABOVE_HIGH_LIMIT, sample, upperLimit); + default: + //Never reached, all states covered. + return HasReturnvaluesIF::RETURN_FAILED; + } +} diff --git a/thermal/ThermalMonitor.h b/thermal/ThermalMonitor.h index a38889d0..69528600 100644 --- a/thermal/ThermalMonitor.h +++ b/thermal/ThermalMonitor.h @@ -1,26 +1,26 @@ -#ifndef FRAMEWORK_THERMAL_THERMALMONITOR_H_ -#define FRAMEWORK_THERMAL_THERMALMONITOR_H_ - -#include -#include - -/** - * What does it do. How to use it. - */ -class ThermalMonitor: public MonitorReporter { -public: - template - ThermalMonitor(Args ... args) : - MonitorReporter(std::forward(args)...) { - } - ~ThermalMonitor(); - ReturnValue_t translateState(ThermalComponentIF::State state, float sample, - float lowerLimit, float upperLimit, bool componentIsOperational = true); - - bool isAboveHighLimit(); -protected: - virtual void sendTransitionEvent(float currentValue, ReturnValue_t state); - -}; - -#endif /* FRAMEWORK_THERMAL_THERMALMONITOR_H_ */ +#ifndef FRAMEWORK_THERMAL_THERMALMONITOR_H_ +#define FRAMEWORK_THERMAL_THERMALMONITOR_H_ + +#include "../monitoring/MonitorReporter.h" +#include "../thermal/ThermalComponentIF.h" + +/** + * What does it do. How to use it. + */ +class ThermalMonitor: public MonitorReporter { +public: + template + ThermalMonitor(Args ... args) : + MonitorReporter(std::forward(args)...) { + } + ~ThermalMonitor(); + ReturnValue_t translateState(ThermalComponentIF::State state, float sample, + float lowerLimit, float upperLimit, bool componentIsOperational = true); + + bool isAboveHighLimit(); +protected: + virtual void sendTransitionEvent(float currentValue, ReturnValue_t state); + +}; + +#endif /* FRAMEWORK_THERMAL_THERMALMONITOR_H_ */ diff --git a/timemanager/CCSDSTime.cpp b/timemanager/CCSDSTime.cpp index 71b2539d..e073ad86 100644 --- a/timemanager/CCSDSTime.cpp +++ b/timemanager/CCSDSTime.cpp @@ -1,602 +1,602 @@ -#include -#include -#include -#include - -CCSDSTime::CCSDSTime() { -} - -CCSDSTime::~CCSDSTime() { -} - -ReturnValue_t CCSDSTime::convertToCcsds(Ccs_seconds* to, - const Clock::TimeOfDay_t* from) { - ReturnValue_t result = checkTimeOfDay(from); - if (result != RETURN_OK) { - return result; - } - - to->pField = (CCS << 4); - - to->yearMSB = (from->year >> 8); - to->yearLSB = from->year & 0xff; - to->month = from->month; - to->day = from->day; - to->hour = from->hour; - to->minute = from->minute; - to->second = from->second; - - return RETURN_OK; -} - -ReturnValue_t CCSDSTime::convertToCcsds(Ccs_mseconds* to, - const Clock::TimeOfDay_t* from) { - ReturnValue_t result = checkTimeOfDay(from); - if (result != RETURN_OK) { - return result; - } - - to->pField = (CCS << 4) + 2; - - to->yearMSB = (from->year >> 8); - to->yearLSB = from->year & 0xff; - to->month = from->month; - to->day = from->day; - to->hour = from->hour; - to->minute = from->minute; - to->second = from->second; - to->secondEminus2 = from->usecond / 10000; - to->secondEminus4 = (from->usecond % 10000) / 100; - - return RETURN_OK; -} - -ReturnValue_t CCSDSTime::convertFromCcsds(Clock::TimeOfDay_t* to, const uint8_t* from, - uint32_t length) { - ReturnValue_t result; - if (length > 0xFF) { - return LENGTH_MISMATCH; - } - result = convertFromASCII(to, from, length); //Try to parse it as ASCII - if (result == RETURN_OK) { - return RETURN_OK; - } - - //Seems to be no ascii, try the other formats - uint8_t codeIdentification = (*from >> 4); - switch (codeIdentification) { - case CUC_LEVEL1: //CUC_LEVEL2 can not be converted to TimeOfDay (ToD is Level 1) <- Well, if we know the epoch, we can... <- see bug 1133 - return convertFromCUC(to, from, length); - case CDS: - return convertFromCDS(to, from, length); - case CCS: { - uint32_t temp = 0; - return convertFromCCS(to, from, &temp, length); - } - - default: - return UNSUPPORTED_TIME_FORMAT; - } -} - -ReturnValue_t CCSDSTime::convertFromCUC(Clock::TimeOfDay_t* to, const uint8_t* from, - uint8_t length) { - return UNSUPPORTED_TIME_FORMAT; -} - -ReturnValue_t CCSDSTime::convertFromCDS(Clock::TimeOfDay_t* to, const uint8_t* from, - uint8_t length) { - timeval time; - ReturnValue_t result = convertFromCDS(&time, from, NULL, length); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - return convertTimevalToTimeOfDay(to, &time); -} - -ReturnValue_t CCSDSTime::convertFromCCS(Clock::TimeOfDay_t* to, const uint8_t* from, - uint32_t* foundLength, uint32_t maxLength) { - uint8_t subsecondsLength = *from & 0b111; - uint32_t totalLength = subsecondsLength + 8; - if (maxLength < totalLength) { - return LENGTH_MISMATCH; - } - - *foundLength = totalLength; - - ReturnValue_t result = checkCcs(from, maxLength); - - if (result != RETURN_OK) { - return result; - } - - Ccs_mseconds *temp = (Ccs_mseconds *) from; - - to->year = (temp->yearMSB << 8) + temp->yearLSB; - to->hour = temp->hour; - to->minute = temp->minute; - to->second = temp->second; - - if (temp->pField & (1 << 3)) { //day of year variation - uint16_t tempDay = (temp->month << 8) + temp->day; - ReturnValue_t result = convertDaysOfYear(tempDay, to->year, - &(temp->month), &(temp->day)); - if (result != RETURN_OK) { - return result; - } - } - - to->month = temp->month; - to->day = temp->day; - - to->usecond = 0; - if (subsecondsLength > 0) { - *foundLength += 1; - if (temp->secondEminus2 >= 100) { - return INVALID_TIME_FORMAT; - } - to->usecond = temp->secondEminus2 * 10000; - } - - if (subsecondsLength > 1) { - *foundLength += 1; - if (temp->secondEminus4 >= 100) { - return INVALID_TIME_FORMAT; - } - to->usecond += temp->secondEminus4 * 100; - } - - return RETURN_OK; - -} - -ReturnValue_t CCSDSTime::convertFromASCII(Clock::TimeOfDay_t* to, const uint8_t* from, - uint8_t length) { - if (length < 19) { - return RETURN_FAILED; - } -// Newlib nano can't parse uint8, see SCNu8 documentation and https://sourceware.org/newlib/README -// Suggestion: use uint16 all the time. This should work on all systems. -#ifdef NEWLIB_NANO_NO_C99_IO - uint16_t year; - uint16_t month; - uint16_t day; - uint16_t hour; - uint16_t minute; - float second; - int count = sscanf((char *) from, "%4" SCNu16 "-%2" SCNu16 "-%2" SCNu16 "T%2" SCNu16 ":%2" SCNu16 ":%fZ", &year, - &month, &day, &hour, &minute, &second); - if (count == 6) { - to->year = year; - to->month = month; - to->day = day; - to->hour = hour; - to->minute = minute; - to->second = second; - to->usecond = (second - floor(second)) * 1000000; - return RETURN_OK; - } - - // try Code B (yyyy-ddd) - count = sscanf((char *) from, "%4" SCNu16 "-%3" SCNu16 "T%2" SCNu16 ":%2" SCNu16 ":%fZ", &year, &day, - &hour, &minute, &second); - if (count == 5) { - uint8_t tempDay; - ReturnValue_t result = CCSDSTime::convertDaysOfYear(day, year, - reinterpret_cast(&month), reinterpret_cast(&tempDay)); - if (result != RETURN_OK) { - return RETURN_FAILED; - } - to->year = year; - to->month = month; - to->day = tempDay; - to->hour = hour; - to->minute = minute; - to->second = second; - to->usecond = (second - floor(second)) * 1000000; - return RETURN_OK; - } -// Warning: Compiler/Linker fails ambiguously if library does not implement -// C99 I/O -#else - uint16_t year; - uint8_t month; - uint16_t day; - uint8_t hour; - uint8_t minute; - float second; - //try Code A (yyyy-mm-dd) - int count = sscanf((char *) from, "%4" SCNu16 "-%2" SCNu8 "-%2" SCNu16 - "T%2" SCNu8 ":%2" SCNu8 ":%fZ", &year, &month, &day, - &hour, &minute, &second); - if (count == 6) { - to->year = year; - to->month = month; - to->day = day; - to->hour = hour; - to->minute = minute; - to->second = second; - to->usecond = (second - floor(second)) * 1000000; - return RETURN_OK; - } - - //try Code B (yyyy-ddd) - count = sscanf((char *) from, "%4" SCNu16 "-%3" SCNu16 "T%2" SCNu8 - ":%2" SCNu8 ":%fZ", &year, &day, &hour, &minute, &second); - if (count == 5) { - uint8_t tempDay; - ReturnValue_t result = CCSDSTime::convertDaysOfYear(day, year, &month, - &tempDay); - if (result != RETURN_OK) { - return RETURN_FAILED; - } - to->year = year; - to->month = month; - to->day = tempDay; - to->hour = hour; - to->minute = minute; - to->second = second; - to->usecond = (second - floor(second)) * 1000000; - return RETURN_OK; - } -#endif - - return UNSUPPORTED_TIME_FORMAT; -} - -ReturnValue_t CCSDSTime::checkCcs(const uint8_t* time, uint8_t length) { - Ccs_mseconds *time_struct = (Ccs_mseconds *) time; - - uint8_t additionalBytes = time_struct->pField & 0b111; - if ((additionalBytes == 0b111) || (length < (additionalBytes + 8))) { - return INVALID_TIME_FORMAT; - } - - if (time_struct->pField & (1 << 3)) { //day of year variation - uint16_t day = (time_struct->month << 8) + time_struct->day; - if (day > 366) { - return INVALID_TIME_FORMAT; - } - } else { - if (time_struct->month > 12) { - return INVALID_TIME_FORMAT; - } - if (time_struct->day > 31) { - return INVALID_TIME_FORMAT; - } - } - if (time_struct->hour > 23) { - return INVALID_TIME_FORMAT; - } - if (time_struct->minute > 59) { - return INVALID_TIME_FORMAT; - } - if (time_struct->second > 59) { - return INVALID_TIME_FORMAT; - } - - uint8_t *additionalByte = &time_struct->secondEminus2; - - for (; additionalBytes != 0; additionalBytes--) { - if (*additionalByte++ > 99) { - return INVALID_TIME_FORMAT; - } - } - return RETURN_OK; -} - -ReturnValue_t CCSDSTime::convertDaysOfYear(uint16_t dayofYear, uint16_t year, - uint8_t* month, uint8_t* day) { - if (isLeapYear(year)) { - if (dayofYear > 366) { - return INVALID_DAY_OF_YEAR; - } - } else { - if (dayofYear > 365) { - return INVALID_DAY_OF_YEAR; - } - } - *month = 1; - if (dayofYear <= 31) { - *day = dayofYear; - return RETURN_OK; - } - *month += 1; - dayofYear -= 31; - if (isLeapYear(year)) { - if (dayofYear <= 29) { - *day = dayofYear; - return RETURN_OK; - } - *month += 1; - dayofYear -= 29; - } else { - if (dayofYear <= 28) { - *day = dayofYear; - return RETURN_OK; - } - *month += 1; - dayofYear -= 28; - } - while (*month <= 12) { - if (dayofYear <= 31) { - *day = dayofYear; - return RETURN_OK; - } - *month += 1; - dayofYear -= 31; - - if (*month == 8) { - continue; - } - - if (dayofYear <= 30) { - *day = dayofYear; - return RETURN_OK; - } - *month += 1; - dayofYear -= 30; - } - return INVALID_DAY_OF_YEAR; -} - -bool CCSDSTime::isLeapYear(uint32_t year) { - if ((year % 400) == 0) { - return true; - } - if ((year % 100) == 0) { - return false; - } - if ((year % 4) == 0) { - return true; - } - return false; -} - -ReturnValue_t CCSDSTime::convertToCcsds(CDS_short* to, const timeval* from) { - to->pField = (CDS << 4) + 0; - uint32_t days = ((from->tv_sec) / SECONDS_PER_DAY) - + DAYS_CCSDS_TO_UNIX_EPOCH; - if (days > (1 << 16)) { - //Date is beyond year 2137 - return TIME_DOES_NOT_FIT_FORMAT; - } - to->dayMSB = (days & 0xFF00) >> 8; - to->dayLSB = (days & 0xFF); - uint32_t msDay = ((from->tv_sec % SECONDS_PER_DAY) * 1000) - + (from->tv_usec / 1000); - to->msDay_hh = (msDay & 0xFF000000) >> 24; - to->msDay_h = (msDay & 0xFF0000) >> 16; - to->msDay_l = (msDay & 0xFF00) >> 8; - to->msDay_ll = (msDay & 0xFF); - return RETURN_OK; -} - -ReturnValue_t CCSDSTime::convertToCcsds(OBT_FLP* to, const timeval* from) { - to->pFiled = (AGENCY_DEFINED << 4) + 5; - to->seconds_hh = (from->tv_sec >> 24) & 0xff; - to->seconds_h = (from->tv_sec >> 16) & 0xff; - to->seconds_l = (from->tv_sec >> 8) & 0xff; - to->seconds_ll = (from->tv_sec >> 0) & 0xff; - - //convert the µs to 2E-16 seconds - uint64_t temp = from->tv_usec; - temp = temp << 16; - temp = temp / 1E6; - - to->subsecondsMSB = (temp >> 8) & 0xff; - to->subsecondsLSB = temp & 0xff; - - return RETURN_OK; -} - -ReturnValue_t CCSDSTime::convertFromCcsds(timeval* to, const uint8_t* from, - uint32_t* foundLength, uint32_t maxLength) { - //We don't expect ascii here. SHOULDDO - uint8_t codeIdentification = (*from >> 4); - switch (codeIdentification) { - //unsupported, as Leap second correction would have to be applied -// case CUC_LEVEL1: -// return convertFromCUC(to, from, foundLength, maxLength); - case CDS: - return convertFromCDS(to, from, foundLength, maxLength); - case CCS: - return convertFromCCS(to, from, foundLength, maxLength); - default: - return UNSUPPORTED_TIME_FORMAT; - } - -} - -ReturnValue_t CCSDSTime::convertFromCUC(timeval* to, const uint8_t* from, - uint32_t* foundLength, uint32_t maxLength) { - if (maxLength < 1) { - return INVALID_TIME_FORMAT; - } - uint8_t pField = *from; - from++; - ReturnValue_t result = convertFromCUC(to, pField, from, foundLength, - maxLength - 1); - if (result == HasReturnvaluesIF::RETURN_OK) { - if (foundLength != NULL) { - *foundLength += 1; - } - } - return result; -} - -ReturnValue_t CCSDSTime::checkTimeOfDay(const Clock::TimeOfDay_t* time) { - if ((time->month > 12) || (time->month == 0)) { - return INVALID_TIME_FORMAT; - } - - if (time->day == 0) { - return INVALID_TIME_FORMAT; - } - switch (time->month) { - case 2: - if (isLeapYear(time->year)) { - if (time->day > 29) { - return INVALID_TIME_FORMAT; - } - } else { - if (time->day > 28) { - return INVALID_TIME_FORMAT; - } - } - break; - case 4: - case 6: - case 9: - case 11: - if (time->day > 30) { - return INVALID_TIME_FORMAT; - } - break; - default: - if (time->day > 31) { - return INVALID_TIME_FORMAT; - } - break; - } - - if (time->hour > 23) { - return INVALID_TIME_FORMAT; - } - - if (time->minute > 59) { - return INVALID_TIME_FORMAT; - } - - if (time->second > 59) { - return INVALID_TIME_FORMAT; - } - - if (time->usecond > 999999) { - return INVALID_TIME_FORMAT; - } - - return RETURN_OK; - -} - -ReturnValue_t CCSDSTime::convertTimevalToTimeOfDay(Clock::TimeOfDay_t* to, - timeval* from) { -//This is rather tricky. Implement only if needed. Also, if so, move to OSAL. - return UNSUPPORTED_TIME_FORMAT; -} - -ReturnValue_t CCSDSTime::convertFromCDS(timeval* to, const uint8_t* from, - uint32_t* foundLength, uint32_t maxLength) { - uint8_t pField = *from; - from++; -//Check epoch - if (pField & 0b1000) { - return NOT_ENOUGH_INFORMATION_FOR_TARGET_FORMAT; - } -//Check length - uint8_t expectedLength = 7; //Including p-Field. - bool extendedDays = pField & 0b100; - if (extendedDays) { - expectedLength += 1; - } - if ((pField & 0b11) == 0b01) { - expectedLength += 2; - } else if ((pField & 0b11) == 0b10) { - expectedLength += 4; - } - if (foundLength != NULL) { - *foundLength = expectedLength; - } - if (expectedLength > maxLength) { - return LENGTH_MISMATCH; - } -//Check and count days - uint32_t days = 0; - if (extendedDays) { - days = (from[0] << 16) + (from[1] << 8) + from[2]; - from += 3; - } else { - days = (from[0] << 8) + from[1]; - from += 2; - } -//Move to POSIX epoch. - if (days <= DAYS_CCSDS_TO_UNIX_EPOCH) { - return INVALID_TIME_FORMAT; - } - days -= DAYS_CCSDS_TO_UNIX_EPOCH; - to->tv_sec = days * SECONDS_PER_DAY; - uint32_t msDay = (from[0] << 24) + (from[1] << 16) + (from[2] << 8) - + from[3]; - from += 4; - to->tv_sec += (msDay / 1000); - to->tv_usec = (msDay % 1000) * 1000; - if ((pField & 0b11) == 0b01) { - uint16_t usecs = (from[0] << 16) + from[1]; - from += 2; - if (usecs > 999) { - return INVALID_TIME_FORMAT; - } - to->tv_usec += usecs; - } else if ((pField & 0b11) == 0b10) { - uint32_t picosecs = (from[0] << 24) + (from[1] << 16) + (from[2] << 8) - + from[3]; - from += 4; - if (picosecs > 999999) { - return INVALID_TIME_FORMAT; - } - //Not very useful. - to->tv_usec += (picosecs / 1000); - } - return RETURN_OK; -} - -ReturnValue_t CCSDSTime::convertFromCUC(timeval* to, uint8_t pField, - const uint8_t* from, uint32_t* foundLength, uint32_t maxLength) { - uint32_t secs = 0; - uint32_t subSeconds = 0; - uint8_t nCoarse = ((pField & 0b1100) >> 2) + 1; - uint8_t nFine = (pField & 0b11); - uint32_t totalLength = nCoarse + nFine; - if (foundLength != NULL) { - *foundLength = totalLength; - } - if (totalLength > maxLength) { - return LENGTH_MISMATCH; - } - for (int count = 0; count < nCoarse; count++) { - secs += *from << ((nCoarse * 8 - 8) * (1 + count)); - from++; - } - for (int count = 0; count < nFine; count++) { - subSeconds += *from << ((nFine * 8 - 8) * (1 + count)); - from++; - } - //Move to POSIX epoch. - to->tv_sec = secs; - if (pField & 0b10000) { - //CCSDS-Epoch - to->tv_sec -= (DAYS_CCSDS_TO_UNIX_EPOCH * SECONDS_PER_DAY); - } - to->tv_usec = subsecondsToMicroseconds(subSeconds); - return RETURN_OK; -} - -uint32_t CCSDSTime::subsecondsToMicroseconds(uint16_t subseconds) { - uint64_t temp = (uint64_t) subseconds * 1000000 - / (1 << (sizeof(subseconds) * 8)); - return temp; -} - -ReturnValue_t CCSDSTime::convertFromCCS(timeval* to, const uint8_t* from, - uint32_t* foundLength, uint32_t maxLength) { - Clock::TimeOfDay_t tempTime; - ReturnValue_t result = convertFromCCS(&tempTime, from, foundLength, - maxLength); - if (result != RETURN_OK) { - return result; - } - - return Clock::convertTimeOfDayToTimeval(&tempTime, to); - -} +#include "../timemanager/CCSDSTime.h" +#include +#include +#include + +CCSDSTime::CCSDSTime() { +} + +CCSDSTime::~CCSDSTime() { +} + +ReturnValue_t CCSDSTime::convertToCcsds(Ccs_seconds* to, + const Clock::TimeOfDay_t* from) { + ReturnValue_t result = checkTimeOfDay(from); + if (result != RETURN_OK) { + return result; + } + + to->pField = (CCS << 4); + + to->yearMSB = (from->year >> 8); + to->yearLSB = from->year & 0xff; + to->month = from->month; + to->day = from->day; + to->hour = from->hour; + to->minute = from->minute; + to->second = from->second; + + return RETURN_OK; +} + +ReturnValue_t CCSDSTime::convertToCcsds(Ccs_mseconds* to, + const Clock::TimeOfDay_t* from) { + ReturnValue_t result = checkTimeOfDay(from); + if (result != RETURN_OK) { + return result; + } + + to->pField = (CCS << 4) + 2; + + to->yearMSB = (from->year >> 8); + to->yearLSB = from->year & 0xff; + to->month = from->month; + to->day = from->day; + to->hour = from->hour; + to->minute = from->minute; + to->second = from->second; + to->secondEminus2 = from->usecond / 10000; + to->secondEminus4 = (from->usecond % 10000) / 100; + + return RETURN_OK; +} + +ReturnValue_t CCSDSTime::convertFromCcsds(Clock::TimeOfDay_t* to, const uint8_t* from, + uint32_t length) { + ReturnValue_t result; + if (length > 0xFF) { + return LENGTH_MISMATCH; + } + result = convertFromASCII(to, from, length); //Try to parse it as ASCII + if (result == RETURN_OK) { + return RETURN_OK; + } + + //Seems to be no ascii, try the other formats + uint8_t codeIdentification = (*from >> 4); + switch (codeIdentification) { + case CUC_LEVEL1: //CUC_LEVEL2 can not be converted to TimeOfDay (ToD is Level 1) <- Well, if we know the epoch, we can... <- see bug 1133 + return convertFromCUC(to, from, length); + case CDS: + return convertFromCDS(to, from, length); + case CCS: { + uint32_t temp = 0; + return convertFromCCS(to, from, &temp, length); + } + + default: + return UNSUPPORTED_TIME_FORMAT; + } +} + +ReturnValue_t CCSDSTime::convertFromCUC(Clock::TimeOfDay_t* to, const uint8_t* from, + uint8_t length) { + return UNSUPPORTED_TIME_FORMAT; +} + +ReturnValue_t CCSDSTime::convertFromCDS(Clock::TimeOfDay_t* to, const uint8_t* from, + uint8_t length) { + timeval time; + ReturnValue_t result = convertFromCDS(&time, from, NULL, length); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return convertTimevalToTimeOfDay(to, &time); +} + +ReturnValue_t CCSDSTime::convertFromCCS(Clock::TimeOfDay_t* to, const uint8_t* from, + uint32_t* foundLength, uint32_t maxLength) { + uint8_t subsecondsLength = *from & 0b111; + uint32_t totalLength = subsecondsLength + 8; + if (maxLength < totalLength) { + return LENGTH_MISMATCH; + } + + *foundLength = totalLength; + + ReturnValue_t result = checkCcs(from, maxLength); + + if (result != RETURN_OK) { + return result; + } + + Ccs_mseconds *temp = (Ccs_mseconds *) from; + + to->year = (temp->yearMSB << 8) + temp->yearLSB; + to->hour = temp->hour; + to->minute = temp->minute; + to->second = temp->second; + + if (temp->pField & (1 << 3)) { //day of year variation + uint16_t tempDay = (temp->month << 8) + temp->day; + ReturnValue_t result = convertDaysOfYear(tempDay, to->year, + &(temp->month), &(temp->day)); + if (result != RETURN_OK) { + return result; + } + } + + to->month = temp->month; + to->day = temp->day; + + to->usecond = 0; + if (subsecondsLength > 0) { + *foundLength += 1; + if (temp->secondEminus2 >= 100) { + return INVALID_TIME_FORMAT; + } + to->usecond = temp->secondEminus2 * 10000; + } + + if (subsecondsLength > 1) { + *foundLength += 1; + if (temp->secondEminus4 >= 100) { + return INVALID_TIME_FORMAT; + } + to->usecond += temp->secondEminus4 * 100; + } + + return RETURN_OK; + +} + +ReturnValue_t CCSDSTime::convertFromASCII(Clock::TimeOfDay_t* to, const uint8_t* from, + uint8_t length) { + if (length < 19) { + return RETURN_FAILED; + } +// Newlib nano can't parse uint8, see SCNu8 documentation and https://sourceware.org/newlib/README +// Suggestion: use uint16 all the time. This should work on all systems. +#ifdef NEWLIB_NANO_NO_C99_IO + uint16_t year; + uint16_t month; + uint16_t day; + uint16_t hour; + uint16_t minute; + float second; + int count = sscanf((char *) from, "%4" SCNu16 "-%2" SCNu16 "-%2" SCNu16 "T%2" SCNu16 ":%2" SCNu16 ":%fZ", &year, + &month, &day, &hour, &minute, &second); + if (count == 6) { + to->year = year; + to->month = month; + to->day = day; + to->hour = hour; + to->minute = minute; + to->second = second; + to->usecond = (second - floor(second)) * 1000000; + return RETURN_OK; + } + + // try Code B (yyyy-ddd) + count = sscanf((char *) from, "%4" SCNu16 "-%3" SCNu16 "T%2" SCNu16 ":%2" SCNu16 ":%fZ", &year, &day, + &hour, &minute, &second); + if (count == 5) { + uint8_t tempDay; + ReturnValue_t result = CCSDSTime::convertDaysOfYear(day, year, + reinterpret_cast(&month), reinterpret_cast(&tempDay)); + if (result != RETURN_OK) { + return RETURN_FAILED; + } + to->year = year; + to->month = month; + to->day = tempDay; + to->hour = hour; + to->minute = minute; + to->second = second; + to->usecond = (second - floor(second)) * 1000000; + return RETURN_OK; + } +// Warning: Compiler/Linker fails ambiguously if library does not implement +// C99 I/O +#else + uint16_t year; + uint8_t month; + uint16_t day; + uint8_t hour; + uint8_t minute; + float second; + //try Code A (yyyy-mm-dd) + int count = sscanf((char *) from, "%4" SCNu16 "-%2" SCNu8 "-%2" SCNu16 + "T%2" SCNu8 ":%2" SCNu8 ":%fZ", &year, &month, &day, + &hour, &minute, &second); + if (count == 6) { + to->year = year; + to->month = month; + to->day = day; + to->hour = hour; + to->minute = minute; + to->second = second; + to->usecond = (second - floor(second)) * 1000000; + return RETURN_OK; + } + + //try Code B (yyyy-ddd) + count = sscanf((char *) from, "%4" SCNu16 "-%3" SCNu16 "T%2" SCNu8 + ":%2" SCNu8 ":%fZ", &year, &day, &hour, &minute, &second); + if (count == 5) { + uint8_t tempDay; + ReturnValue_t result = CCSDSTime::convertDaysOfYear(day, year, &month, + &tempDay); + if (result != RETURN_OK) { + return RETURN_FAILED; + } + to->year = year; + to->month = month; + to->day = tempDay; + to->hour = hour; + to->minute = minute; + to->second = second; + to->usecond = (second - floor(second)) * 1000000; + return RETURN_OK; + } +#endif + + return UNSUPPORTED_TIME_FORMAT; +} + +ReturnValue_t CCSDSTime::checkCcs(const uint8_t* time, uint8_t length) { + Ccs_mseconds *time_struct = (Ccs_mseconds *) time; + + uint8_t additionalBytes = time_struct->pField & 0b111; + if ((additionalBytes == 0b111) || (length < (additionalBytes + 8))) { + return INVALID_TIME_FORMAT; + } + + if (time_struct->pField & (1 << 3)) { //day of year variation + uint16_t day = (time_struct->month << 8) + time_struct->day; + if (day > 366) { + return INVALID_TIME_FORMAT; + } + } else { + if (time_struct->month > 12) { + return INVALID_TIME_FORMAT; + } + if (time_struct->day > 31) { + return INVALID_TIME_FORMAT; + } + } + if (time_struct->hour > 23) { + return INVALID_TIME_FORMAT; + } + if (time_struct->minute > 59) { + return INVALID_TIME_FORMAT; + } + if (time_struct->second > 59) { + return INVALID_TIME_FORMAT; + } + + uint8_t *additionalByte = &time_struct->secondEminus2; + + for (; additionalBytes != 0; additionalBytes--) { + if (*additionalByte++ > 99) { + return INVALID_TIME_FORMAT; + } + } + return RETURN_OK; +} + +ReturnValue_t CCSDSTime::convertDaysOfYear(uint16_t dayofYear, uint16_t year, + uint8_t* month, uint8_t* day) { + if (isLeapYear(year)) { + if (dayofYear > 366) { + return INVALID_DAY_OF_YEAR; + } + } else { + if (dayofYear > 365) { + return INVALID_DAY_OF_YEAR; + } + } + *month = 1; + if (dayofYear <= 31) { + *day = dayofYear; + return RETURN_OK; + } + *month += 1; + dayofYear -= 31; + if (isLeapYear(year)) { + if (dayofYear <= 29) { + *day = dayofYear; + return RETURN_OK; + } + *month += 1; + dayofYear -= 29; + } else { + if (dayofYear <= 28) { + *day = dayofYear; + return RETURN_OK; + } + *month += 1; + dayofYear -= 28; + } + while (*month <= 12) { + if (dayofYear <= 31) { + *day = dayofYear; + return RETURN_OK; + } + *month += 1; + dayofYear -= 31; + + if (*month == 8) { + continue; + } + + if (dayofYear <= 30) { + *day = dayofYear; + return RETURN_OK; + } + *month += 1; + dayofYear -= 30; + } + return INVALID_DAY_OF_YEAR; +} + +bool CCSDSTime::isLeapYear(uint32_t year) { + if ((year % 400) == 0) { + return true; + } + if ((year % 100) == 0) { + return false; + } + if ((year % 4) == 0) { + return true; + } + return false; +} + +ReturnValue_t CCSDSTime::convertToCcsds(CDS_short* to, const timeval* from) { + to->pField = (CDS << 4) + 0; + uint32_t days = ((from->tv_sec) / SECONDS_PER_DAY) + + DAYS_CCSDS_TO_UNIX_EPOCH; + if (days > (1 << 16)) { + //Date is beyond year 2137 + return TIME_DOES_NOT_FIT_FORMAT; + } + to->dayMSB = (days & 0xFF00) >> 8; + to->dayLSB = (days & 0xFF); + uint32_t msDay = ((from->tv_sec % SECONDS_PER_DAY) * 1000) + + (from->tv_usec / 1000); + to->msDay_hh = (msDay & 0xFF000000) >> 24; + to->msDay_h = (msDay & 0xFF0000) >> 16; + to->msDay_l = (msDay & 0xFF00) >> 8; + to->msDay_ll = (msDay & 0xFF); + return RETURN_OK; +} + +ReturnValue_t CCSDSTime::convertToCcsds(OBT_FLP* to, const timeval* from) { + to->pFiled = (AGENCY_DEFINED << 4) + 5; + to->seconds_hh = (from->tv_sec >> 24) & 0xff; + to->seconds_h = (from->tv_sec >> 16) & 0xff; + to->seconds_l = (from->tv_sec >> 8) & 0xff; + to->seconds_ll = (from->tv_sec >> 0) & 0xff; + + //convert the µs to 2E-16 seconds + uint64_t temp = from->tv_usec; + temp = temp << 16; + temp = temp / 1E6; + + to->subsecondsMSB = (temp >> 8) & 0xff; + to->subsecondsLSB = temp & 0xff; + + return RETURN_OK; +} + +ReturnValue_t CCSDSTime::convertFromCcsds(timeval* to, const uint8_t* from, + uint32_t* foundLength, uint32_t maxLength) { + //We don't expect ascii here. SHOULDDO + uint8_t codeIdentification = (*from >> 4); + switch (codeIdentification) { + //unsupported, as Leap second correction would have to be applied +// case CUC_LEVEL1: +// return convertFromCUC(to, from, foundLength, maxLength); + case CDS: + return convertFromCDS(to, from, foundLength, maxLength); + case CCS: + return convertFromCCS(to, from, foundLength, maxLength); + default: + return UNSUPPORTED_TIME_FORMAT; + } + +} + +ReturnValue_t CCSDSTime::convertFromCUC(timeval* to, const uint8_t* from, + uint32_t* foundLength, uint32_t maxLength) { + if (maxLength < 1) { + return INVALID_TIME_FORMAT; + } + uint8_t pField = *from; + from++; + ReturnValue_t result = convertFromCUC(to, pField, from, foundLength, + maxLength - 1); + if (result == HasReturnvaluesIF::RETURN_OK) { + if (foundLength != NULL) { + *foundLength += 1; + } + } + return result; +} + +ReturnValue_t CCSDSTime::checkTimeOfDay(const Clock::TimeOfDay_t* time) { + if ((time->month > 12) || (time->month == 0)) { + return INVALID_TIME_FORMAT; + } + + if (time->day == 0) { + return INVALID_TIME_FORMAT; + } + switch (time->month) { + case 2: + if (isLeapYear(time->year)) { + if (time->day > 29) { + return INVALID_TIME_FORMAT; + } + } else { + if (time->day > 28) { + return INVALID_TIME_FORMAT; + } + } + break; + case 4: + case 6: + case 9: + case 11: + if (time->day > 30) { + return INVALID_TIME_FORMAT; + } + break; + default: + if (time->day > 31) { + return INVALID_TIME_FORMAT; + } + break; + } + + if (time->hour > 23) { + return INVALID_TIME_FORMAT; + } + + if (time->minute > 59) { + return INVALID_TIME_FORMAT; + } + + if (time->second > 59) { + return INVALID_TIME_FORMAT; + } + + if (time->usecond > 999999) { + return INVALID_TIME_FORMAT; + } + + return RETURN_OK; + +} + +ReturnValue_t CCSDSTime::convertTimevalToTimeOfDay(Clock::TimeOfDay_t* to, + timeval* from) { +//This is rather tricky. Implement only if needed. Also, if so, move to OSAL. + return UNSUPPORTED_TIME_FORMAT; +} + +ReturnValue_t CCSDSTime::convertFromCDS(timeval* to, const uint8_t* from, + uint32_t* foundLength, uint32_t maxLength) { + uint8_t pField = *from; + from++; +//Check epoch + if (pField & 0b1000) { + return NOT_ENOUGH_INFORMATION_FOR_TARGET_FORMAT; + } +//Check length + uint8_t expectedLength = 7; //Including p-Field. + bool extendedDays = pField & 0b100; + if (extendedDays) { + expectedLength += 1; + } + if ((pField & 0b11) == 0b01) { + expectedLength += 2; + } else if ((pField & 0b11) == 0b10) { + expectedLength += 4; + } + if (foundLength != NULL) { + *foundLength = expectedLength; + } + if (expectedLength > maxLength) { + return LENGTH_MISMATCH; + } +//Check and count days + uint32_t days = 0; + if (extendedDays) { + days = (from[0] << 16) + (from[1] << 8) + from[2]; + from += 3; + } else { + days = (from[0] << 8) + from[1]; + from += 2; + } +//Move to POSIX epoch. + if (days <= DAYS_CCSDS_TO_UNIX_EPOCH) { + return INVALID_TIME_FORMAT; + } + days -= DAYS_CCSDS_TO_UNIX_EPOCH; + to->tv_sec = days * SECONDS_PER_DAY; + uint32_t msDay = (from[0] << 24) + (from[1] << 16) + (from[2] << 8) + + from[3]; + from += 4; + to->tv_sec += (msDay / 1000); + to->tv_usec = (msDay % 1000) * 1000; + if ((pField & 0b11) == 0b01) { + uint16_t usecs = (from[0] << 16) + from[1]; + from += 2; + if (usecs > 999) { + return INVALID_TIME_FORMAT; + } + to->tv_usec += usecs; + } else if ((pField & 0b11) == 0b10) { + uint32_t picosecs = (from[0] << 24) + (from[1] << 16) + (from[2] << 8) + + from[3]; + from += 4; + if (picosecs > 999999) { + return INVALID_TIME_FORMAT; + } + //Not very useful. + to->tv_usec += (picosecs / 1000); + } + return RETURN_OK; +} + +ReturnValue_t CCSDSTime::convertFromCUC(timeval* to, uint8_t pField, + const uint8_t* from, uint32_t* foundLength, uint32_t maxLength) { + uint32_t secs = 0; + uint32_t subSeconds = 0; + uint8_t nCoarse = ((pField & 0b1100) >> 2) + 1; + uint8_t nFine = (pField & 0b11); + uint32_t totalLength = nCoarse + nFine; + if (foundLength != NULL) { + *foundLength = totalLength; + } + if (totalLength > maxLength) { + return LENGTH_MISMATCH; + } + for (int count = 0; count < nCoarse; count++) { + secs += *from << ((nCoarse * 8 - 8) * (1 + count)); + from++; + } + for (int count = 0; count < nFine; count++) { + subSeconds += *from << ((nFine * 8 - 8) * (1 + count)); + from++; + } + //Move to POSIX epoch. + to->tv_sec = secs; + if (pField & 0b10000) { + //CCSDS-Epoch + to->tv_sec -= (DAYS_CCSDS_TO_UNIX_EPOCH * SECONDS_PER_DAY); + } + to->tv_usec = subsecondsToMicroseconds(subSeconds); + return RETURN_OK; +} + +uint32_t CCSDSTime::subsecondsToMicroseconds(uint16_t subseconds) { + uint64_t temp = (uint64_t) subseconds * 1000000 + / (1 << (sizeof(subseconds) * 8)); + return temp; +} + +ReturnValue_t CCSDSTime::convertFromCCS(timeval* to, const uint8_t* from, + uint32_t* foundLength, uint32_t maxLength) { + Clock::TimeOfDay_t tempTime; + ReturnValue_t result = convertFromCCS(&tempTime, from, foundLength, + maxLength); + if (result != RETURN_OK) { + return result; + } + + return Clock::convertTimeOfDayToTimeval(&tempTime, to); + +} diff --git a/timemanager/CCSDSTime.h b/timemanager/CCSDSTime.h index 92060d5d..6bb3a75c 100644 --- a/timemanager/CCSDSTime.h +++ b/timemanager/CCSDSTime.h @@ -1,233 +1,233 @@ -#ifndef CCSDSTIME_H_ -#define CCSDSTIME_H_ - -// COULDDO: have calls in Clock.h which return time quality and use timespec accordingly - -#include -#include -#include - -bool operator<(const timeval& lhs, const timeval& rhs); -bool operator<=(const timeval& lhs, const timeval& rhs); -bool operator==(const timeval& lhs, const timeval& rhs); -/** - * static helper class for CCSDS Time Code Formats - * - * as described in CCSDS 301.0-B-3 - * - * Still work in progress - */ -class CCSDSTime: public HasReturnvaluesIF { -public: - /** - * The Time code identifications, bits 4-6 in the P-Field - */ - enum TimeCodeIdentification { - CCS = 0b101, - CUC_LEVEL1 = 0b001, - CUC_LEVEL2 = 0b010, - CDS = 0b100, - AGENCY_DEFINED = 0b110 - }; - static const uint8_t P_FIELD_CUC_6B_CCSDS = (CUC_LEVEL1 << 4) + (3 << 2) - + 2; - static const uint8_t P_FIELD_CUC_6B_AGENCY = (CUC_LEVEL2 << 4) + (3 << 2) - + 2; - static const uint8_t P_FIELD_CDS_SHORT = (CDS << 4); - /** - * Struct for CDS day-segmented format. - */ - struct CDS_short { - uint8_t pField; - uint8_t dayMSB; - uint8_t dayLSB; - uint8_t msDay_hh; - uint8_t msDay_h; - uint8_t msDay_l; - uint8_t msDay_ll; - }; - /** - * Struct for the CCS fromat in day of month variation with max resolution - */ - struct Ccs_seconds { - uint8_t pField; - uint8_t yearMSB; - uint8_t yearLSB; - uint8_t month; - uint8_t day; - uint8_t hour; - uint8_t minute; - uint8_t second; - }; - - /** - * Struct for the CCS fromat in day of month variation with 10E-4 seconds resolution - */ - struct Ccs_mseconds { - uint8_t pField; - uint8_t yearMSB; - uint8_t yearLSB; - uint8_t month; - uint8_t day; - uint8_t hour; - uint8_t minute; - uint8_t second; - uint8_t secondEminus2; - uint8_t secondEminus4; - }; - - struct OBT_FLP { - uint8_t pFiled; - uint8_t seconds_hh; - uint8_t seconds_h; - uint8_t seconds_l; - uint8_t seconds_ll; - uint8_t subsecondsMSB; - uint8_t subsecondsLSB; - }; - - struct TimevalLess { - bool operator()(const timeval& lhs, const timeval& rhs) const { - return (lhs < rhs); - } - }; - - static const uint8_t INTERFACE_ID = CLASS_ID::CCSDS_TIME_HELPER_CLASS; - static const ReturnValue_t UNSUPPORTED_TIME_FORMAT = MAKE_RETURN_CODE(0); - static const ReturnValue_t NOT_ENOUGH_INFORMATION_FOR_TARGET_FORMAT = - MAKE_RETURN_CODE(1); - static const ReturnValue_t LENGTH_MISMATCH = MAKE_RETURN_CODE(2); - static const ReturnValue_t INVALID_TIME_FORMAT = MAKE_RETURN_CODE(3); - static const ReturnValue_t INVALID_DAY_OF_YEAR = MAKE_RETURN_CODE(4); - static const ReturnValue_t TIME_DOES_NOT_FIT_FORMAT = MAKE_RETURN_CODE(5); - - /** - * convert a TimeofDay struct to ccs with seconds resolution - * - * @param to pointer to a CCS struct - * @param from pointer to a TimeOfDay Struct - * @return - * - @c RETURN_OK if OK - * - @c INVALID_TIMECODE if not OK - */ - static ReturnValue_t convertToCcsds(Ccs_seconds *to, - Clock::TimeOfDay_t const *from); - - /** - * Converts to CDS format from timeval. - * @param to pointer to the CDS struct to generate - * @param from pointer to a timeval struct which comprises a time of day since UNIX epoch. - * @return - * - @c RETURN_OK as it assumes a valid timeval. - */ - static ReturnValue_t convertToCcsds(CDS_short* to, timeval const *from); - - static ReturnValue_t convertToCcsds(OBT_FLP* to, timeval const *from); - - /** - * convert a TimeofDay struct to ccs with 10E-3 seconds resolution - * - * The 10E-4 seconds in the CCS Struct are 0 as the TimeOfDay only has ms resolution - * - * @param to pointer to a CCS struct - * @param from pointer to a TimeOfDay Struct - * @return - * - @c RETURN_OK if OK - * - @c INVALID_TIMECODE if not OK - */ - static ReturnValue_t convertToCcsds(Ccs_mseconds *to, - Clock::TimeOfDay_t const *from); - - /** - * SHOULDDO: can this be modified to recognize padding? - * Tries to interpret a Level 1 CCSDS time code - * - * It assumes binary formats contain a valid P Field and recognizes the ASCII format - * by the lack of one. - * - * @param to an empty TimeOfDay struct - * @param from pointer to an CCSDS Time code - * @param length length of the Time code - * @return - * - @c RETURN_OK if successful - * - @c UNSUPPORTED_TIME_FORMAT if a (possibly valid) time code is not supported - * - @c LENGTH_MISMATCH if the length does not match the P Field - * - @c INVALID_TIME_FORMAT if the format or a value is invalid - */ - static ReturnValue_t convertFromCcsds(Clock::TimeOfDay_t *to, uint8_t const *from, - uint32_t length); - - /** - * not implemented yet - * - * @param to - * @param from - * @return - */ - static ReturnValue_t convertFromCcsds(timeval *to, uint8_t const *from, - uint32_t* foundLength, uint32_t maxLength); - - static ReturnValue_t convertFromCUC(Clock::TimeOfDay_t *to, uint8_t const *from, - uint8_t length); - - static ReturnValue_t convertFromCUC(timeval *to, uint8_t const *from, - uint32_t* foundLength, uint32_t maxLength); - - static ReturnValue_t convertFromCUC(timeval *to, uint8_t pField, - uint8_t const *from, uint32_t* foundLength, uint32_t maxLength); - - static ReturnValue_t convertFromCCS(timeval *to, uint8_t const *from, - uint32_t* foundLength, uint32_t maxLength); - - static ReturnValue_t convertFromCCS(timeval *to, uint8_t pField, - uint8_t const *from, uint32_t* foundLength, uint32_t maxLength); - - static ReturnValue_t convertFromCDS(Clock::TimeOfDay_t *to, uint8_t const *from, - uint8_t length); - - static ReturnValue_t convertFromCDS(timeval *to, uint8_t const *from, - uint32_t* foundLength, uint32_t maxLength); - - static ReturnValue_t convertFromCCS(Clock::TimeOfDay_t *to, uint8_t const *from, - uint32_t* foundLength, uint32_t maxLength); - - static ReturnValue_t convertFromASCII(Clock::TimeOfDay_t *to, uint8_t const *from, - uint8_t length); - - static uint32_t subsecondsToMicroseconds(uint16_t subseconds); -private: - CCSDSTime(); - virtual ~CCSDSTime(); - /** - * checks a ccs time stream for validity - * - * Stream may be longer than the actual timecode - * - * @param time pointer to an Ccs stream - * @param length length of stream - * @return - */ - static ReturnValue_t checkCcs(const uint8_t* time, uint8_t length); - - static ReturnValue_t checkTimeOfDay(const Clock::TimeOfDay_t *time); - - static const uint32_t SECONDS_PER_DAY = 24 * 60 * 60; - static const uint32_t SECONDS_PER_NON_LEAP_YEAR = SECONDS_PER_DAY * 365; - static const uint32_t DAYS_CCSDS_TO_UNIX_EPOCH = 4383; //!< Time difference between CCSDS and POSIX epoch. This is exact, because leap-seconds where not introduced before 1972. - static const uint32_t SECONDS_CCSDS_TO_UNIX_EPOCH = DAYS_CCSDS_TO_UNIX_EPOCH - * SECONDS_PER_DAY; - /** - * @param dayofYear - * @param year - * @param month - * @param day - */ - static ReturnValue_t convertDaysOfYear(uint16_t dayofYear, uint16_t year, - uint8_t *month, uint8_t *day); - - static bool isLeapYear(uint32_t year); - static ReturnValue_t convertTimevalToTimeOfDay(Clock::TimeOfDay_t* to, - timeval* from); -}; - -#endif /* CCSDSTIME_H_ */ +#ifndef CCSDSTIME_H_ +#define CCSDSTIME_H_ + +// COULDDO: have calls in Clock.h which return time quality and use timespec accordingly + +#include "../timemanager/Clock.h" +#include "../returnvalues/HasReturnvaluesIF.h" +#include + +bool operator<(const timeval& lhs, const timeval& rhs); +bool operator<=(const timeval& lhs, const timeval& rhs); +bool operator==(const timeval& lhs, const timeval& rhs); +/** + * static helper class for CCSDS Time Code Formats + * + * as described in CCSDS 301.0-B-3 + * + * Still work in progress + */ +class CCSDSTime: public HasReturnvaluesIF { +public: + /** + * The Time code identifications, bits 4-6 in the P-Field + */ + enum TimeCodeIdentification { + CCS = 0b101, + CUC_LEVEL1 = 0b001, + CUC_LEVEL2 = 0b010, + CDS = 0b100, + AGENCY_DEFINED = 0b110 + }; + static const uint8_t P_FIELD_CUC_6B_CCSDS = (CUC_LEVEL1 << 4) + (3 << 2) + + 2; + static const uint8_t P_FIELD_CUC_6B_AGENCY = (CUC_LEVEL2 << 4) + (3 << 2) + + 2; + static const uint8_t P_FIELD_CDS_SHORT = (CDS << 4); + /** + * Struct for CDS day-segmented format. + */ + struct CDS_short { + uint8_t pField; + uint8_t dayMSB; + uint8_t dayLSB; + uint8_t msDay_hh; + uint8_t msDay_h; + uint8_t msDay_l; + uint8_t msDay_ll; + }; + /** + * Struct for the CCS fromat in day of month variation with max resolution + */ + struct Ccs_seconds { + uint8_t pField; + uint8_t yearMSB; + uint8_t yearLSB; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t minute; + uint8_t second; + }; + + /** + * Struct for the CCS fromat in day of month variation with 10E-4 seconds resolution + */ + struct Ccs_mseconds { + uint8_t pField; + uint8_t yearMSB; + uint8_t yearLSB; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t minute; + uint8_t second; + uint8_t secondEminus2; + uint8_t secondEminus4; + }; + + struct OBT_FLP { + uint8_t pFiled; + uint8_t seconds_hh; + uint8_t seconds_h; + uint8_t seconds_l; + uint8_t seconds_ll; + uint8_t subsecondsMSB; + uint8_t subsecondsLSB; + }; + + struct TimevalLess { + bool operator()(const timeval& lhs, const timeval& rhs) const { + return (lhs < rhs); + } + }; + + static const uint8_t INTERFACE_ID = CLASS_ID::CCSDS_TIME_HELPER_CLASS; + static const ReturnValue_t UNSUPPORTED_TIME_FORMAT = MAKE_RETURN_CODE(0); + static const ReturnValue_t NOT_ENOUGH_INFORMATION_FOR_TARGET_FORMAT = + MAKE_RETURN_CODE(1); + static const ReturnValue_t LENGTH_MISMATCH = MAKE_RETURN_CODE(2); + static const ReturnValue_t INVALID_TIME_FORMAT = MAKE_RETURN_CODE(3); + static const ReturnValue_t INVALID_DAY_OF_YEAR = MAKE_RETURN_CODE(4); + static const ReturnValue_t TIME_DOES_NOT_FIT_FORMAT = MAKE_RETURN_CODE(5); + + /** + * convert a TimeofDay struct to ccs with seconds resolution + * + * @param to pointer to a CCS struct + * @param from pointer to a TimeOfDay Struct + * @return + * - @c RETURN_OK if OK + * - @c INVALID_TIMECODE if not OK + */ + static ReturnValue_t convertToCcsds(Ccs_seconds *to, + Clock::TimeOfDay_t const *from); + + /** + * Converts to CDS format from timeval. + * @param to pointer to the CDS struct to generate + * @param from pointer to a timeval struct which comprises a time of day since UNIX epoch. + * @return + * - @c RETURN_OK as it assumes a valid timeval. + */ + static ReturnValue_t convertToCcsds(CDS_short* to, timeval const *from); + + static ReturnValue_t convertToCcsds(OBT_FLP* to, timeval const *from); + + /** + * convert a TimeofDay struct to ccs with 10E-3 seconds resolution + * + * The 10E-4 seconds in the CCS Struct are 0 as the TimeOfDay only has ms resolution + * + * @param to pointer to a CCS struct + * @param from pointer to a TimeOfDay Struct + * @return + * - @c RETURN_OK if OK + * - @c INVALID_TIMECODE if not OK + */ + static ReturnValue_t convertToCcsds(Ccs_mseconds *to, + Clock::TimeOfDay_t const *from); + + /** + * SHOULDDO: can this be modified to recognize padding? + * Tries to interpret a Level 1 CCSDS time code + * + * It assumes binary formats contain a valid P Field and recognizes the ASCII format + * by the lack of one. + * + * @param to an empty TimeOfDay struct + * @param from pointer to an CCSDS Time code + * @param length length of the Time code + * @return + * - @c RETURN_OK if successful + * - @c UNSUPPORTED_TIME_FORMAT if a (possibly valid) time code is not supported + * - @c LENGTH_MISMATCH if the length does not match the P Field + * - @c INVALID_TIME_FORMAT if the format or a value is invalid + */ + static ReturnValue_t convertFromCcsds(Clock::TimeOfDay_t *to, uint8_t const *from, + uint32_t length); + + /** + * not implemented yet + * + * @param to + * @param from + * @return + */ + static ReturnValue_t convertFromCcsds(timeval *to, uint8_t const *from, + uint32_t* foundLength, uint32_t maxLength); + + static ReturnValue_t convertFromCUC(Clock::TimeOfDay_t *to, uint8_t const *from, + uint8_t length); + + static ReturnValue_t convertFromCUC(timeval *to, uint8_t const *from, + uint32_t* foundLength, uint32_t maxLength); + + static ReturnValue_t convertFromCUC(timeval *to, uint8_t pField, + uint8_t const *from, uint32_t* foundLength, uint32_t maxLength); + + static ReturnValue_t convertFromCCS(timeval *to, uint8_t const *from, + uint32_t* foundLength, uint32_t maxLength); + + static ReturnValue_t convertFromCCS(timeval *to, uint8_t pField, + uint8_t const *from, uint32_t* foundLength, uint32_t maxLength); + + static ReturnValue_t convertFromCDS(Clock::TimeOfDay_t *to, uint8_t const *from, + uint8_t length); + + static ReturnValue_t convertFromCDS(timeval *to, uint8_t const *from, + uint32_t* foundLength, uint32_t maxLength); + + static ReturnValue_t convertFromCCS(Clock::TimeOfDay_t *to, uint8_t const *from, + uint32_t* foundLength, uint32_t maxLength); + + static ReturnValue_t convertFromASCII(Clock::TimeOfDay_t *to, uint8_t const *from, + uint8_t length); + + static uint32_t subsecondsToMicroseconds(uint16_t subseconds); +private: + CCSDSTime(); + virtual ~CCSDSTime(); + /** + * checks a ccs time stream for validity + * + * Stream may be longer than the actual timecode + * + * @param time pointer to an Ccs stream + * @param length length of stream + * @return + */ + static ReturnValue_t checkCcs(const uint8_t* time, uint8_t length); + + static ReturnValue_t checkTimeOfDay(const Clock::TimeOfDay_t *time); + + static const uint32_t SECONDS_PER_DAY = 24 * 60 * 60; + static const uint32_t SECONDS_PER_NON_LEAP_YEAR = SECONDS_PER_DAY * 365; + static const uint32_t DAYS_CCSDS_TO_UNIX_EPOCH = 4383; //!< Time difference between CCSDS and POSIX epoch. This is exact, because leap-seconds where not introduced before 1972. + static const uint32_t SECONDS_CCSDS_TO_UNIX_EPOCH = DAYS_CCSDS_TO_UNIX_EPOCH + * SECONDS_PER_DAY; + /** + * @param dayofYear + * @param year + * @param month + * @param day + */ + static ReturnValue_t convertDaysOfYear(uint16_t dayofYear, uint16_t year, + uint8_t *month, uint8_t *day); + + static bool isLeapYear(uint32_t year); + static ReturnValue_t convertTimevalToTimeOfDay(Clock::TimeOfDay_t* to, + timeval* from); +}; + +#endif /* CCSDSTIME_H_ */ diff --git a/timemanager/Clock.h b/timemanager/Clock.h index 65e152bf..c7436252 100644 --- a/timemanager/Clock.h +++ b/timemanager/Clock.h @@ -1,155 +1,155 @@ -#ifndef FRAMEWORK_TIMEMANAGER_CLOCK_H_ -#define FRAMEWORK_TIMEMANAGER_CLOCK_H_ - -#include -#include -#include - -#include -#include - -//! Don't use these for time points, type is not large enough for UNIX epoch. -using dur_millis_t = uint32_t; -using dur_seconds_t = double; - -class Clock { -public: - typedef struct { - uint32_t year; //!< Year, A.D. - uint32_t month; //!< Month, 1 .. 12. - uint32_t day; //!< Day, 1 .. 31. - uint32_t hour; //!< Hour, 0 .. 23. - uint32_t minute; //!< Minute, 0 .. 59. - uint32_t second; //!< Second, 0 .. 59. - uint32_t usecond; //!< Microseconds, 0 .. 999999 - } TimeOfDay_t; - - /** - * This method returns the number of clock ticks per second. - * In RTEMS, this is typically 1000. - * @return The number of ticks. - * - * @deprecated, we should not worry about ticks, but only time - */ - static uint32_t getTicksPerSecond(void); - /** - * This system call sets the system time. - * To set the time, it uses a TimeOfDay_t struct. - * @param time The struct with the time settings to set. - * @return -@c RETURN_OK on success. Otherwise, the OS failure code - * is returned. - */ - static ReturnValue_t setClock(const TimeOfDay_t* time); - /** - * This system call sets the system time. - * To set the time, it uses a timeval struct. - * @param time The struct with the time settings to set. - * @return -@c RETURN_OK on success. Otherwise, the OS failure code is returned. - */ - static ReturnValue_t setClock(const timeval* time); - /** - * This system call returns the current system clock in timeval format. - * The timval format has the fields @c tv_sec with seconds and @c tv_usec with - * microseconds since an OS-defined epoch. - * @param time A pointer to a timeval struct where the current time is stored. - * @return @c RETURN_OK on success. Otherwise, the OS failure code is returned. - */ - static ReturnValue_t getClock_timeval(timeval* time); - - /** - * Get the time since boot in a timeval struct - * - * @param[out] time A pointer to a timeval struct where the uptime is stored. - * @return @c RETURN_OK on success. Otherwise, the OS failure code is returned. - * - * @deprecated, I do not think this should be able to fail, use timeval getUptime() - */ - static ReturnValue_t getUptime(timeval* uptime); - - static timeval getUptime(); - - /** - * Get the time since boot in milliseconds - * - * This value can overflow! Still, it can be used to calculate time intervalls - * between two calls up to 49 days by always using uint32_t in the calculation - * - * @param ms uptime in ms - * @return RETURN_OK on success. Otherwise, the OS failure code is returned. - */ - static ReturnValue_t getUptime(uint32_t* uptimeMs); - - /** - * Returns the time in microseconds since an OS-defined epoch. - * The time is returned in a 64 bit unsigned integer. - * @param time A pointer to a 64 bit unisigned integer where the data is stored. - * @return \c RETURN_OK on success. Otherwise, the OS failure code is returned. - */ - static ReturnValue_t getClock_usecs(uint64_t* time); - /** - * Returns the time in a TimeOfDay_t struct. - * @param time A pointer to a TimeOfDay_t struct. - * @return \c RETURN_OK on success. Otherwise, the OS failure code is returned. - */ - static ReturnValue_t getDateAndTime(TimeOfDay_t* time); - - /** - * Converts a time of day struct to POSIX seconds. - * @param time The time of day as input - * @param timeval The corresponding seconds since the epoch. - * @return \c RETURN_OK on success. Otherwise, the OS failure code is returned. - */ - static ReturnValue_t convertTimeOfDayToTimeval(const TimeOfDay_t* from, - timeval* to); - - /** - * Converts a time represented as seconds and subseconds since unix epoch to days since J2000 - * - * @param time seconds since unix epoch - * @param[out] JD2000 days since J2000 - * @return \c RETURN_OK - */ - static ReturnValue_t convertTimevalToJD2000(timeval time, double* JD2000); - - /** - * Calculates and adds the offset between UTC and TT - * - * Depends on the leap seconds to be set correctly. - * - * @param utc timeval, corresponding to UTC time - * @param[out] tt timeval, corresponding to Terrestial Time - * @return \c RETURN_OK on success, \c RETURN_FAILED if leapSeconds are not set - */ - static ReturnValue_t convertUTCToTT(timeval utc, timeval* tt); - - /** - * Set the Leap Seconds since 1972 - * - * @param leapSeconds_ - * @return \c RETURN_OK on success. Otherwise, the OS failure code is returned. - */ - static ReturnValue_t setLeapSeconds(const uint16_t leapSeconds_); - - /** - * Get the Leap Seconds since 1972 - * - * Must be set before! - * - * @param[out] leapSeconds_ - * @return \c RETURN_OK on success. Otherwise, the OS failure code is returned. - */ - static ReturnValue_t getLeapSeconds(uint16_t *leapSeconds_); - - /** - * Function to check and create the Mutex for the clock - * @return \c RETURN_OK on success. Otherwise \c RETURN_FAILED if not able to create one - */ - static ReturnValue_t checkOrCreateClockMutex(); - -private: - static MutexIF* timeMutex; - static uint16_t leapSeconds; -}; - - -#endif /* FRAMEWORK_TIMEMANAGER_CLOCK_H_ */ +#ifndef FRAMEWORK_TIMEMANAGER_CLOCK_H_ +#define FRAMEWORK_TIMEMANAGER_CLOCK_H_ + +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../ipc/MutexFactory.h" +#include "../globalfunctions/timevalOperations.h" + +#include +#include + +//! Don't use these for time points, type is not large enough for UNIX epoch. +using dur_millis_t = uint32_t; +using dur_seconds_t = double; + +class Clock { +public: + typedef struct { + uint32_t year; //!< Year, A.D. + uint32_t month; //!< Month, 1 .. 12. + uint32_t day; //!< Day, 1 .. 31. + uint32_t hour; //!< Hour, 0 .. 23. + uint32_t minute; //!< Minute, 0 .. 59. + uint32_t second; //!< Second, 0 .. 59. + uint32_t usecond; //!< Microseconds, 0 .. 999999 + } TimeOfDay_t; + + /** + * This method returns the number of clock ticks per second. + * In RTEMS, this is typically 1000. + * @return The number of ticks. + * + * @deprecated, we should not worry about ticks, but only time + */ + static uint32_t getTicksPerSecond(void); + /** + * This system call sets the system time. + * To set the time, it uses a TimeOfDay_t struct. + * @param time The struct with the time settings to set. + * @return -@c RETURN_OK on success. Otherwise, the OS failure code + * is returned. + */ + static ReturnValue_t setClock(const TimeOfDay_t* time); + /** + * This system call sets the system time. + * To set the time, it uses a timeval struct. + * @param time The struct with the time settings to set. + * @return -@c RETURN_OK on success. Otherwise, the OS failure code is returned. + */ + static ReturnValue_t setClock(const timeval* time); + /** + * This system call returns the current system clock in timeval format. + * The timval format has the fields @c tv_sec with seconds and @c tv_usec with + * microseconds since an OS-defined epoch. + * @param time A pointer to a timeval struct where the current time is stored. + * @return @c RETURN_OK on success. Otherwise, the OS failure code is returned. + */ + static ReturnValue_t getClock_timeval(timeval* time); + + /** + * Get the time since boot in a timeval struct + * + * @param[out] time A pointer to a timeval struct where the uptime is stored. + * @return @c RETURN_OK on success. Otherwise, the OS failure code is returned. + * + * @deprecated, I do not think this should be able to fail, use timeval getUptime() + */ + static ReturnValue_t getUptime(timeval* uptime); + + static timeval getUptime(); + + /** + * Get the time since boot in milliseconds + * + * This value can overflow! Still, it can be used to calculate time intervalls + * between two calls up to 49 days by always using uint32_t in the calculation + * + * @param ms uptime in ms + * @return RETURN_OK on success. Otherwise, the OS failure code is returned. + */ + static ReturnValue_t getUptime(uint32_t* uptimeMs); + + /** + * Returns the time in microseconds since an OS-defined epoch. + * The time is returned in a 64 bit unsigned integer. + * @param time A pointer to a 64 bit unisigned integer where the data is stored. + * @return \c RETURN_OK on success. Otherwise, the OS failure code is returned. + */ + static ReturnValue_t getClock_usecs(uint64_t* time); + /** + * Returns the time in a TimeOfDay_t struct. + * @param time A pointer to a TimeOfDay_t struct. + * @return \c RETURN_OK on success. Otherwise, the OS failure code is returned. + */ + static ReturnValue_t getDateAndTime(TimeOfDay_t* time); + + /** + * Converts a time of day struct to POSIX seconds. + * @param time The time of day as input + * @param timeval The corresponding seconds since the epoch. + * @return \c RETURN_OK on success. Otherwise, the OS failure code is returned. + */ + static ReturnValue_t convertTimeOfDayToTimeval(const TimeOfDay_t* from, + timeval* to); + + /** + * Converts a time represented as seconds and subseconds since unix epoch to days since J2000 + * + * @param time seconds since unix epoch + * @param[out] JD2000 days since J2000 + * @return \c RETURN_OK + */ + static ReturnValue_t convertTimevalToJD2000(timeval time, double* JD2000); + + /** + * Calculates and adds the offset between UTC and TT + * + * Depends on the leap seconds to be set correctly. + * + * @param utc timeval, corresponding to UTC time + * @param[out] tt timeval, corresponding to Terrestial Time + * @return \c RETURN_OK on success, \c RETURN_FAILED if leapSeconds are not set + */ + static ReturnValue_t convertUTCToTT(timeval utc, timeval* tt); + + /** + * Set the Leap Seconds since 1972 + * + * @param leapSeconds_ + * @return \c RETURN_OK on success. Otherwise, the OS failure code is returned. + */ + static ReturnValue_t setLeapSeconds(const uint16_t leapSeconds_); + + /** + * Get the Leap Seconds since 1972 + * + * Must be set before! + * + * @param[out] leapSeconds_ + * @return \c RETURN_OK on success. Otherwise, the OS failure code is returned. + */ + static ReturnValue_t getLeapSeconds(uint16_t *leapSeconds_); + + /** + * Function to check and create the Mutex for the clock + * @return \c RETURN_OK on success. Otherwise \c RETURN_FAILED if not able to create one + */ + static ReturnValue_t checkOrCreateClockMutex(); + +private: + static MutexIF* timeMutex; + static uint16_t leapSeconds; +}; + + +#endif /* FRAMEWORK_TIMEMANAGER_CLOCK_H_ */ diff --git a/timemanager/Countdown.cpp b/timemanager/Countdown.cpp index e6565914..5b019f2b 100644 --- a/timemanager/Countdown.cpp +++ b/timemanager/Countdown.cpp @@ -1,45 +1,45 @@ -/** - * @file Countdown.cpp - * @brief This file defines the Countdown class. - * @date 21.03.2013 - * @author baetz - */ - - -#include - -Countdown::Countdown(uint32_t initialTimeout) : startTime(0), timeout(initialTimeout) { -} - -Countdown::~Countdown() { -} - -ReturnValue_t Countdown::setTimeout(uint32_t miliseconds) { - ReturnValue_t return_value = Clock::getUptime( &startTime ); - timeout = miliseconds; - return return_value; -} - -bool Countdown::hasTimedOut() const { - uint32_t current_time; - Clock::getUptime( ¤t_time ); - if ( uint32_t(current_time - startTime) >= timeout) { - return true; - } else { - return false; - } -} - -bool Countdown::isBusy() const { - return !hasTimedOut(); -} - -ReturnValue_t Countdown::resetTimer() { - return setTimeout(timeout); -} - -void Countdown::timeOut() { - uint32_t current_time; - Clock::getUptime( ¤t_time ); - startTime= current_time - timeout; -} +/** + * @file Countdown.cpp + * @brief This file defines the Countdown class. + * @date 21.03.2013 + * @author baetz + */ + + +#include "../timemanager/Countdown.h" + +Countdown::Countdown(uint32_t initialTimeout) : startTime(0), timeout(initialTimeout) { +} + +Countdown::~Countdown() { +} + +ReturnValue_t Countdown::setTimeout(uint32_t miliseconds) { + ReturnValue_t return_value = Clock::getUptime( &startTime ); + timeout = miliseconds; + return return_value; +} + +bool Countdown::hasTimedOut() const { + uint32_t current_time; + Clock::getUptime( ¤t_time ); + if ( uint32_t(current_time - startTime) >= timeout) { + return true; + } else { + return false; + } +} + +bool Countdown::isBusy() const { + return !hasTimedOut(); +} + +ReturnValue_t Countdown::resetTimer() { + return setTimeout(timeout); +} + +void Countdown::timeOut() { + uint32_t current_time; + Clock::getUptime( ¤t_time ); + startTime= current_time - timeout; +} diff --git a/timemanager/Countdown.h b/timemanager/Countdown.h index 57a11f91..741ab0f8 100644 --- a/timemanager/Countdown.h +++ b/timemanager/Countdown.h @@ -1,31 +1,31 @@ -/** - * @file Countdown.h - * @brief This file defines the Countdown class. - * @date 21.03.2013 - * @author baetz - */ - -#ifndef COUNTDOWN_H_ -#define COUNTDOWN_H_ - -#include - -class Countdown { -private: - uint32_t startTime; -public: - uint32_t timeout; - Countdown(uint32_t initialTimeout = 0); - ~Countdown(); - ReturnValue_t setTimeout(uint32_t miliseconds); - - bool hasTimedOut() const; - - bool isBusy() const; - - ReturnValue_t resetTimer(); //!< Use last set timeout value and restart timer. - - void timeOut(); //!< Make hasTimedOut() return true -}; - -#endif /* COUNTDOWN_H_ */ +/** + * @file Countdown.h + * @brief This file defines the Countdown class. + * @date 21.03.2013 + * @author baetz + */ + +#ifndef COUNTDOWN_H_ +#define COUNTDOWN_H_ + +#include "../timemanager/Clock.h" + +class Countdown { +private: + uint32_t startTime; +public: + uint32_t timeout; + Countdown(uint32_t initialTimeout = 0); + ~Countdown(); + ReturnValue_t setTimeout(uint32_t miliseconds); + + bool hasTimedOut() const; + + bool isBusy() const; + + ReturnValue_t resetTimer(); //!< Use last set timeout value and restart timer. + + void timeOut(); //!< Make hasTimedOut() return true +}; + +#endif /* COUNTDOWN_H_ */ diff --git a/timemanager/ReceivesTimeInfoIF.h b/timemanager/ReceivesTimeInfoIF.h index f65f9dad..09915e83 100644 --- a/timemanager/ReceivesTimeInfoIF.h +++ b/timemanager/ReceivesTimeInfoIF.h @@ -1,32 +1,32 @@ -/** - * @file ReceivesTimeInfoIF.h - * @brief This file defines the ReceivesTimeInfoIF class. - * @date 26.02.2013 - * @author baetz - */ - -#ifndef RECEIVESTIMEINFOIF_H_ -#define RECEIVESTIMEINFOIF_H_ -#include - -/** - * This is a Interface for classes that receive timing information - * with the help of a dedicated message queue. - */ -class ReceivesTimeInfoIF { -public: - /** - * Returns the id of the queue which receives the timing information. - * @return Queue id of the timing queue. - */ - virtual MessageQueueId_t getTimeReceptionQueue() const = 0; - /** - * Empty virtual destructor. - */ - virtual ~ReceivesTimeInfoIF() { - } - -}; - - -#endif /* RECEIVESTIMEINFOIF_H_ */ +/** + * @file ReceivesTimeInfoIF.h + * @brief This file defines the ReceivesTimeInfoIF class. + * @date 26.02.2013 + * @author baetz + */ + +#ifndef RECEIVESTIMEINFOIF_H_ +#define RECEIVESTIMEINFOIF_H_ +#include "../ipc/MessageQueueSenderIF.h" + +/** + * This is a Interface for classes that receive timing information + * with the help of a dedicated message queue. + */ +class ReceivesTimeInfoIF { +public: + /** + * Returns the id of the queue which receives the timing information. + * @return Queue id of the timing queue. + */ + virtual MessageQueueId_t getTimeReceptionQueue() const = 0; + /** + * Empty virtual destructor. + */ + virtual ~ReceivesTimeInfoIF() { + } + +}; + + +#endif /* RECEIVESTIMEINFOIF_H_ */ diff --git a/timemanager/Stopwatch.cpp b/timemanager/Stopwatch.cpp index 52118d58..bf69d3ce 100644 --- a/timemanager/Stopwatch.cpp +++ b/timemanager/Stopwatch.cpp @@ -1,5 +1,5 @@ -#include -#include +#include "../timemanager/Stopwatch.h" +#include "../serviceinterface/ServiceInterfaceStream.h" #include Stopwatch::Stopwatch(bool displayOnDestruction, diff --git a/timemanager/Stopwatch.h b/timemanager/Stopwatch.h index 630202cc..30735b2c 100644 --- a/timemanager/Stopwatch.h +++ b/timemanager/Stopwatch.h @@ -1,6 +1,6 @@ #ifndef FRAMEWORK_TIMEMANAGER_STOPWATCH_H_ #define FRAMEWORK_TIMEMANAGER_STOPWATCH_H_ -#include +#include "../timemanager/Clock.h" enum class StopwatchDisplayMode { MILLIS, diff --git a/timemanager/TimeMessage.cpp b/timemanager/TimeMessage.cpp index bf514317..a60718a4 100644 --- a/timemanager/TimeMessage.cpp +++ b/timemanager/TimeMessage.cpp @@ -1,37 +1,37 @@ -/** - * @file TimeMessage.cpp - * @brief This file defines the TimeMessage class. - * @date 26.02.2013 - * @author baetz - */ - -#include - -TimeMessage::TimeMessage() { - this->messageSize += sizeof(timeval) + sizeof(uint32_t); -} - -TimeMessage::TimeMessage(timeval setTime, uint32_t CounterValue) { - memcpy (this->getData(), &setTime, sizeof(timeval)); - this->messageSize += sizeof(timeval) + sizeof(uint32_t); - memcpy (this->getData() + sizeof(timeval), &CounterValue, sizeof(uint32_t)); -} - -TimeMessage::~TimeMessage() { -} - -timeval TimeMessage::getTime() { - timeval temp; - memcpy( &temp, this->getData(), sizeof(timeval)); - return temp; -} - -uint32_t TimeMessage::getCounterValue() { - uint32_t temp; - memcpy ( &temp, this->getData() + sizeof(timeval), sizeof(uint32_t)); - return temp; -} - -size_t TimeMessage::getMinimumMessageSize() { - return this->MAX_SIZE; -} +/** + * @file TimeMessage.cpp + * @brief This file defines the TimeMessage class. + * @date 26.02.2013 + * @author baetz + */ + +#include "../timemanager/TimeMessage.h" + +TimeMessage::TimeMessage() { + this->messageSize += sizeof(timeval) + sizeof(uint32_t); +} + +TimeMessage::TimeMessage(timeval setTime, uint32_t CounterValue) { + memcpy (this->getData(), &setTime, sizeof(timeval)); + this->messageSize += sizeof(timeval) + sizeof(uint32_t); + memcpy (this->getData() + sizeof(timeval), &CounterValue, sizeof(uint32_t)); +} + +TimeMessage::~TimeMessage() { +} + +timeval TimeMessage::getTime() { + timeval temp; + memcpy( &temp, this->getData(), sizeof(timeval)); + return temp; +} + +uint32_t TimeMessage::getCounterValue() { + uint32_t temp; + memcpy ( &temp, this->getData() + sizeof(timeval), sizeof(uint32_t)); + return temp; +} + +size_t TimeMessage::getMinimumMessageSize() { + return this->MAX_SIZE; +} diff --git a/timemanager/TimeMessage.h b/timemanager/TimeMessage.h index 95685fec..1e440e5d 100644 --- a/timemanager/TimeMessage.h +++ b/timemanager/TimeMessage.h @@ -1,56 +1,56 @@ -/** - * @file TimeMessage.h - * @brief This file defines the TimeMessage class. - * @date 26.02.2013 - * @author baetz - */ - -#ifndef TIMEMESSAGE_H_ -#define TIMEMESSAGE_H_ - -#include -#include -#include - -class TimeMessage : public MessageQueueMessage { -protected: - /** - * @brief This call always returns the same fixed size of the message. - * @return Returns HEADER_SIZE + \c sizeof(timeval) + sizeof(uint32_t). - */ - size_t getMinimumMessageSize(); -public: - - /** - * @ brief the size of a TimeMessage - */ - static const uint32_t MAX_SIZE = HEADER_SIZE + sizeof(timeval) + sizeof(uint32_t); - - /** - * @brief In the default constructor, only the message_size is set. - */ - TimeMessage(); - /** - * @brief With this constructor, the passed time information is directly put - * into the message. - * @param setTime The time information to put into the message. - * @param counterValue The counterValue to put into the message (GPS PPS). - */ - TimeMessage( timeval setTime, uint32_t counterValue = 0 ); - /** - * @brief The class's destructor is empty. - */ - ~TimeMessage(); - /** - * @brief This getter returns the time information in timeval format. - * @return Returns the time stored in this packet. - */ - timeval getTime(); - /** - * @brief This getter returns the CounterValue in uint32_t format. - * @return Returns the CounterValue stored in this packet. - */ - uint32_t getCounterValue(); -}; - -#endif /* TIMEMESSAGE_H_ */ +/** + * @file TimeMessage.h + * @brief This file defines the TimeMessage class. + * @date 26.02.2013 + * @author baetz + */ + +#ifndef TIMEMESSAGE_H_ +#define TIMEMESSAGE_H_ + +#include "../ipc/MessageQueueMessage.h" +#include "../timemanager/Clock.h" +#include + +class TimeMessage : public MessageQueueMessage { +protected: + /** + * @brief This call always returns the same fixed size of the message. + * @return Returns HEADER_SIZE + \c sizeof(timeval) + sizeof(uint32_t). + */ + size_t getMinimumMessageSize(); +public: + + /** + * @ brief the size of a TimeMessage + */ + static const uint32_t MAX_SIZE = HEADER_SIZE + sizeof(timeval) + sizeof(uint32_t); + + /** + * @brief In the default constructor, only the message_size is set. + */ + TimeMessage(); + /** + * @brief With this constructor, the passed time information is directly put + * into the message. + * @param setTime The time information to put into the message. + * @param counterValue The counterValue to put into the message (GPS PPS). + */ + TimeMessage( timeval setTime, uint32_t counterValue = 0 ); + /** + * @brief The class's destructor is empty. + */ + ~TimeMessage(); + /** + * @brief This getter returns the time information in timeval format. + * @return Returns the time stored in this packet. + */ + timeval getTime(); + /** + * @brief This getter returns the CounterValue in uint32_t format. + * @return Returns the CounterValue stored in this packet. + */ + uint32_t getCounterValue(); +}; + +#endif /* TIMEMESSAGE_H_ */ diff --git a/timemanager/TimeStamperIF.h b/timemanager/TimeStamperIF.h index 7ed45371..49e0ec18 100644 --- a/timemanager/TimeStamperIF.h +++ b/timemanager/TimeStamperIF.h @@ -1,24 +1,24 @@ -#ifndef FRAMEWORK_TIMEMANAGER_TIMESTAMPERIF_H_ -#define FRAMEWORK_TIMEMANAGER_TIMESTAMPERIF_H_ - -#include - -/** - * A class implementing this IF provides facilities to add a time stamp to the - * buffer provided. - * Implementors need to ensure that calling the method is thread-safe, i.e. - * addTimeStamp may be called in parallel from a different context. - */ -class TimeStamperIF { -public: - static const uint8_t INTERFACE_ID = CLASS_ID::TIME_STAMPER_IF; - static const ReturnValue_t BAD_TIMESTAMP = MAKE_RETURN_CODE(1); - - static const uint8_t MISSION_TIMESTAMP_SIZE = 8; //!< This is a mission-specific constant and determines the total size reserved for timestamps. - virtual ReturnValue_t addTimeStamp(uint8_t* buffer, const uint8_t maxSize) = 0; - virtual ~TimeStamperIF() {} -}; - - - -#endif /* FRAMEWORK_TIMEMANAGER_TIMESTAMPERIF_H_ */ +#ifndef FRAMEWORK_TIMEMANAGER_TIMESTAMPERIF_H_ +#define FRAMEWORK_TIMEMANAGER_TIMESTAMPERIF_H_ + +#include "../returnvalues/HasReturnvaluesIF.h" + +/** + * A class implementing this IF provides facilities to add a time stamp to the + * buffer provided. + * Implementors need to ensure that calling the method is thread-safe, i.e. + * addTimeStamp may be called in parallel from a different context. + */ +class TimeStamperIF { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::TIME_STAMPER_IF; + static const ReturnValue_t BAD_TIMESTAMP = MAKE_RETURN_CODE(1); + + static const uint8_t MISSION_TIMESTAMP_SIZE = 8; //!< This is a mission-specific constant and determines the total size reserved for timestamps. + virtual ReturnValue_t addTimeStamp(uint8_t* buffer, const uint8_t maxSize) = 0; + virtual ~TimeStamperIF() {} +}; + + + +#endif /* FRAMEWORK_TIMEMANAGER_TIMESTAMPERIF_H_ */ diff --git a/tmstorage/TmStoreBackendIF.h b/tmstorage/TmStoreBackendIF.h index 9b913b35..0e20a314 100644 --- a/tmstorage/TmStoreBackendIF.h +++ b/tmstorage/TmStoreBackendIF.h @@ -1,95 +1,95 @@ -#ifndef PLATFORM_TMTCSERVICES_TMSTOREBACKENDIF_H_ -#define PLATFORM_TMTCSERVICES_TMSTOREBACKENDIF_H_ - -#include -#include -#include -#include -#include -class TmPacketInformation; -class TmPacketMinimal; -class SpacePacketBase; -class ApidSsc; - -class TmStoreBackendIF : public HasParametersIF { -public: - static const uint8_t INTERFACE_ID = CLASS_ID::TM_STORE_BACKEND_IF; - static const ReturnValue_t BUSY = MAKE_RETURN_CODE(1); - static const ReturnValue_t FULL = MAKE_RETURN_CODE(2); - static const ReturnValue_t EMPTY = MAKE_RETURN_CODE(3); - static const ReturnValue_t NULL_REQUESTED = MAKE_RETURN_CODE(4); - static const ReturnValue_t TOO_LARGE = MAKE_RETURN_CODE(5); - static const ReturnValue_t NOT_READY = MAKE_RETURN_CODE(6); - static const ReturnValue_t DUMP_ERROR = MAKE_RETURN_CODE(7); - static const ReturnValue_t CRC_ERROR = MAKE_RETURN_CODE(8); - static const ReturnValue_t TIMEOUT = MAKE_RETURN_CODE(9); - static const ReturnValue_t IDLE_PACKET_FOUND = MAKE_RETURN_CODE(10); - static const ReturnValue_t TELECOMMAND_FOUND = MAKE_RETURN_CODE(11); - static const ReturnValue_t NO_PUS_A_TM = MAKE_RETURN_CODE(12); - static const ReturnValue_t TOO_SMALL = MAKE_RETURN_CODE(13); - static const ReturnValue_t BLOCK_NOT_FOUND = MAKE_RETURN_CODE(14); - static const ReturnValue_t INVALID_REQUEST = MAKE_RETURN_CODE(15); - - static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::MEMORY; - static const Event STORE_SEND_WRITE_FAILED = MAKE_EVENT(0, SEVERITY::LOW); //!< Initiating sending data to store failed. Low, par1: returnCode, par2: integer (debug info) - static const Event STORE_WRITE_FAILED = MAKE_EVENT(1, SEVERITY::LOW); //!< Data was sent, but writing failed. Low, par1: returnCode, par2: 0 - static const Event STORE_SEND_READ_FAILED = MAKE_EVENT(2, SEVERITY::LOW); //!< Initiating reading data from store failed. Low, par1: returnCode, par2: 0 - static const Event STORE_READ_FAILED = MAKE_EVENT(3, SEVERITY::LOW); //!< Data was requested, but access failed. Low, par1: returnCode, par2: 0 - static const Event UNEXPECTED_MSG = MAKE_EVENT(4, SEVERITY::LOW); //!< An unexpected TM packet or data message occurred. Low, par1: 0, par2: integer (debug info) - static const Event STORING_FAILED = MAKE_EVENT(5, SEVERITY::LOW); //!< Storing data failed. May simply be a full store. Low, par1: returnCode, par2: integer (sequence count of failed packet). - static const Event TM_DUMP_FAILED = MAKE_EVENT(6, SEVERITY::LOW); //!< Dumping retrieved data failed. Low, par1: returnCode, par2: integer (sequence count of failed packet). - static const Event STORE_INIT_FAILED = MAKE_EVENT(7, SEVERITY::LOW); //!< Corrupted init data or read error. Low, par1: returnCode, par2: integer (debug info) - static const Event STORE_INIT_EMPTY = MAKE_EVENT(8, SEVERITY::INFO); //!< Store was not initialized. Starts empty. Info, parameters both zero. - static const Event STORE_CONTENT_CORRUPTED = MAKE_EVENT(9, SEVERITY::LOW); //!< Data was read out, but it is inconsistent. Low par1: Memory address of corruption, par2: integer (debug info) - static const Event STORE_INITIALIZE = MAKE_EVENT(10, SEVERITY::INFO); //!< Info event indicating the store will be initialized, either at boot or after IOB switch. Info. pars: 0 - static const Event INIT_DONE = MAKE_EVENT(11, SEVERITY::INFO); //!< Info event indicating the store was successfully initialized, either at boot or after IOB switch. Info. pars: 0 - static const Event DUMP_FINISHED = MAKE_EVENT(12, SEVERITY::INFO); //!< Info event indicating that dumping finished successfully. par1: Number of dumped packets. par2: APID/SSC (16bits each) - static const Event DELETION_FINISHED = MAKE_EVENT(13, SEVERITY::INFO); //!< Info event indicating that deletion finished successfully. par1: Number of deleted packets. par2: APID/SSC (16bits each) - static const Event DELETION_FAILED = MAKE_EVENT(14, SEVERITY::LOW); //!< Info event indicating that something went wrong during deletion. pars: 0 - static const Event AUTO_CATALOGS_SENDING_FAILED = MAKE_EVENT(15, SEVERITY::INFO);//!< Info that the a auto catalog report failed - - virtual ~TmStoreBackendIF() {} - - /** - * What do I need to implement here ? - * @param opCode - * @return - */ - virtual ReturnValue_t performOperation(uint8_t opCode) = 0; - virtual ReturnValue_t initialize() = 0; - - /** - * Implement the storage of TM packets to mass memory - * @param tmPacket - * @return - */ - virtual ReturnValue_t storePacket(TmPacketMinimal* tmPacket) = 0; - virtual ReturnValue_t setFetchLimitTime(const timeval* loverLimit, const timeval* upperLimit) = 0; - virtual ReturnValue_t setFetchLimitBlocks(uint32_t startAddress, uint32_t endAddress) = 0; - virtual ReturnValue_t fetchPackets(bool fromBegin = false) = 0; - virtual ReturnValue_t initializeStore(object_id_t dumpTarget) = 0; - virtual ReturnValue_t dumpIndex(store_address_t* storeId) = 0; - - /** - * TODO: Adapt for file management system? - * @param startAddress - * @param endAddress - * @return - */ - virtual ReturnValue_t deleteBlocks(uint32_t startAddress, uint32_t endAddress) = 0; - virtual ReturnValue_t deleteTime(const timeval* timeUntil, - uint32_t* deletedPackets) = 0; - virtual void resetStore(bool clearStore, bool resetWrite, bool resetRead) = 0; - virtual bool isReady() = 0; - virtual uint32_t availableData() = 0; - virtual float getPercentageFilled() const = 0; - virtual uint32_t getStoredPacketsCount() const = 0; - virtual TmPacketInformation* getOldestPacket() = 0; - virtual TmPacketInformation* getYoungestPacket() = 0; - virtual float getDataRate() = 0; - -}; - - - -#endif /* PLATFORM_TMTCSERVICES_TMSTOREBACKENDIF_H_ */ +#ifndef PLATFORM_TMTCSERVICES_TMSTOREBACKENDIF_H_ +#define PLATFORM_TMTCSERVICES_TMSTOREBACKENDIF_H_ + +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../objectmanager/SystemObjectIF.h" +#include "../parameters/HasParametersIF.h" +#include "../storagemanager/StorageManagerIF.h" +#include "../timemanager/Clock.h" +class TmPacketInformation; +class TmPacketMinimal; +class SpacePacketBase; +class ApidSsc; + +class TmStoreBackendIF : public HasParametersIF { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::TM_STORE_BACKEND_IF; + static const ReturnValue_t BUSY = MAKE_RETURN_CODE(1); + static const ReturnValue_t FULL = MAKE_RETURN_CODE(2); + static const ReturnValue_t EMPTY = MAKE_RETURN_CODE(3); + static const ReturnValue_t NULL_REQUESTED = MAKE_RETURN_CODE(4); + static const ReturnValue_t TOO_LARGE = MAKE_RETURN_CODE(5); + static const ReturnValue_t NOT_READY = MAKE_RETURN_CODE(6); + static const ReturnValue_t DUMP_ERROR = MAKE_RETURN_CODE(7); + static const ReturnValue_t CRC_ERROR = MAKE_RETURN_CODE(8); + static const ReturnValue_t TIMEOUT = MAKE_RETURN_CODE(9); + static const ReturnValue_t IDLE_PACKET_FOUND = MAKE_RETURN_CODE(10); + static const ReturnValue_t TELECOMMAND_FOUND = MAKE_RETURN_CODE(11); + static const ReturnValue_t NO_PUS_A_TM = MAKE_RETURN_CODE(12); + static const ReturnValue_t TOO_SMALL = MAKE_RETURN_CODE(13); + static const ReturnValue_t BLOCK_NOT_FOUND = MAKE_RETURN_CODE(14); + static const ReturnValue_t INVALID_REQUEST = MAKE_RETURN_CODE(15); + + static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::MEMORY; + static const Event STORE_SEND_WRITE_FAILED = MAKE_EVENT(0, SEVERITY::LOW); //!< Initiating sending data to store failed. Low, par1: returnCode, par2: integer (debug info) + static const Event STORE_WRITE_FAILED = MAKE_EVENT(1, SEVERITY::LOW); //!< Data was sent, but writing failed. Low, par1: returnCode, par2: 0 + static const Event STORE_SEND_READ_FAILED = MAKE_EVENT(2, SEVERITY::LOW); //!< Initiating reading data from store failed. Low, par1: returnCode, par2: 0 + static const Event STORE_READ_FAILED = MAKE_EVENT(3, SEVERITY::LOW); //!< Data was requested, but access failed. Low, par1: returnCode, par2: 0 + static const Event UNEXPECTED_MSG = MAKE_EVENT(4, SEVERITY::LOW); //!< An unexpected TM packet or data message occurred. Low, par1: 0, par2: integer (debug info) + static const Event STORING_FAILED = MAKE_EVENT(5, SEVERITY::LOW); //!< Storing data failed. May simply be a full store. Low, par1: returnCode, par2: integer (sequence count of failed packet). + static const Event TM_DUMP_FAILED = MAKE_EVENT(6, SEVERITY::LOW); //!< Dumping retrieved data failed. Low, par1: returnCode, par2: integer (sequence count of failed packet). + static const Event STORE_INIT_FAILED = MAKE_EVENT(7, SEVERITY::LOW); //!< Corrupted init data or read error. Low, par1: returnCode, par2: integer (debug info) + static const Event STORE_INIT_EMPTY = MAKE_EVENT(8, SEVERITY::INFO); //!< Store was not initialized. Starts empty. Info, parameters both zero. + static const Event STORE_CONTENT_CORRUPTED = MAKE_EVENT(9, SEVERITY::LOW); //!< Data was read out, but it is inconsistent. Low par1: Memory address of corruption, par2: integer (debug info) + static const Event STORE_INITIALIZE = MAKE_EVENT(10, SEVERITY::INFO); //!< Info event indicating the store will be initialized, either at boot or after IOB switch. Info. pars: 0 + static const Event INIT_DONE = MAKE_EVENT(11, SEVERITY::INFO); //!< Info event indicating the store was successfully initialized, either at boot or after IOB switch. Info. pars: 0 + static const Event DUMP_FINISHED = MAKE_EVENT(12, SEVERITY::INFO); //!< Info event indicating that dumping finished successfully. par1: Number of dumped packets. par2: APID/SSC (16bits each) + static const Event DELETION_FINISHED = MAKE_EVENT(13, SEVERITY::INFO); //!< Info event indicating that deletion finished successfully. par1: Number of deleted packets. par2: APID/SSC (16bits each) + static const Event DELETION_FAILED = MAKE_EVENT(14, SEVERITY::LOW); //!< Info event indicating that something went wrong during deletion. pars: 0 + static const Event AUTO_CATALOGS_SENDING_FAILED = MAKE_EVENT(15, SEVERITY::INFO);//!< Info that the a auto catalog report failed + + virtual ~TmStoreBackendIF() {} + + /** + * What do I need to implement here ? + * @param opCode + * @return + */ + virtual ReturnValue_t performOperation(uint8_t opCode) = 0; + virtual ReturnValue_t initialize() = 0; + + /** + * Implement the storage of TM packets to mass memory + * @param tmPacket + * @return + */ + virtual ReturnValue_t storePacket(TmPacketMinimal* tmPacket) = 0; + virtual ReturnValue_t setFetchLimitTime(const timeval* loverLimit, const timeval* upperLimit) = 0; + virtual ReturnValue_t setFetchLimitBlocks(uint32_t startAddress, uint32_t endAddress) = 0; + virtual ReturnValue_t fetchPackets(bool fromBegin = false) = 0; + virtual ReturnValue_t initializeStore(object_id_t dumpTarget) = 0; + virtual ReturnValue_t dumpIndex(store_address_t* storeId) = 0; + + /** + * TODO: Adapt for file management system? + * @param startAddress + * @param endAddress + * @return + */ + virtual ReturnValue_t deleteBlocks(uint32_t startAddress, uint32_t endAddress) = 0; + virtual ReturnValue_t deleteTime(const timeval* timeUntil, + uint32_t* deletedPackets) = 0; + virtual void resetStore(bool clearStore, bool resetWrite, bool resetRead) = 0; + virtual bool isReady() = 0; + virtual uint32_t availableData() = 0; + virtual float getPercentageFilled() const = 0; + virtual uint32_t getStoredPacketsCount() const = 0; + virtual TmPacketInformation* getOldestPacket() = 0; + virtual TmPacketInformation* getYoungestPacket() = 0; + virtual float getDataRate() = 0; + +}; + + + +#endif /* PLATFORM_TMTCSERVICES_TMSTOREBACKENDIF_H_ */ diff --git a/tmstorage/TmStoreFrontendIF.h b/tmstorage/TmStoreFrontendIF.h index 7d38cfc6..7a2b3c9e 100644 --- a/tmstorage/TmStoreFrontendIF.h +++ b/tmstorage/TmStoreFrontendIF.h @@ -1,63 +1,63 @@ -#ifndef PLATFORM_TMTCSERVICES_TMSTOREFRONTENDIF_H_ -#define PLATFORM_TMTCSERVICES_TMSTOREFRONTENDIF_H_ - -#include -#include -#include -class TmPacketMinimal; -class SpacePacketBase; -class TmStoreBackendIF; - -class TmStoreFrontendIF { -public: - virtual TmStoreBackendIF* getBackend() const = 0; - - /** - * What do I need to implement here? - * This is propably used by PUS Service 15 so we should propably check for messages.. - * Provide base implementation? - * @param opCode - * @return - */ - virtual ReturnValue_t performOperation(uint8_t opCode) = 0; - /** - * Callback from the back-end to indicate a certain packet was received. - * front-end takes care of discarding/downloading the packet. - * @param packet Pointer to the newly received Space Packet. - * @param address Start address of the packet found - * @param isLastPacket Indicates if no more packets can be fetched. - * @return If more packets shall be fetched, RETURN_OK must be returned. - * Any other code stops fetching packets. - */ - virtual ReturnValue_t packetRetrieved(TmPacketMinimal* packet, uint32_t address) = 0; - virtual void noMorePacketsInStore() = 0; - virtual void handleRetrievalFailed(ReturnValue_t errorCode, uint32_t parameter1 = 0, uint32_t parameter2 = 0) = 0; - /** - * To get the queue where commands shall be sent. - * @return Id of command queue. - */ - virtual MessageQueueId_t getCommandQueue() const = 0; - virtual ReturnValue_t fetchPackets(ApidSsc start, ApidSsc end) = 0; - virtual ReturnValue_t deletePackets(ApidSsc upTo) = 0; - virtual ReturnValue_t checkPacket(SpacePacketBase* tmPacket) = 0; - virtual bool isEnabled() const = 0; - virtual void setEnabled(bool enabled) = 0; - virtual void resetDownlinkedPacketCount() = 0; - virtual ReturnValue_t setDumpTarget(object_id_t dumpTarget) = 0; - static const uint8_t INTERFACE_ID = CLASS_ID::TM_STORE_FRONTEND_IF; - static const ReturnValue_t BUSY = MAKE_RETURN_CODE(1); - static const ReturnValue_t LAST_PACKET_FOUND = MAKE_RETURN_CODE(2); - static const ReturnValue_t STOP_FETCH = MAKE_RETURN_CODE(3); - static const ReturnValue_t TIMEOUT = MAKE_RETURN_CODE(4); - static const ReturnValue_t TM_CHANNEL_FULL = MAKE_RETURN_CODE(5); - static const ReturnValue_t NOT_STORED = MAKE_RETURN_CODE(6); - static const ReturnValue_t ALL_DELETED = MAKE_RETURN_CODE(7); - static const ReturnValue_t INVALID_DATA = MAKE_RETURN_CODE(8); - static const ReturnValue_t NOT_READY = MAKE_RETURN_CODE(9); - virtual ~TmStoreFrontendIF() { - } -}; - - - -#endif /* PLATFORM_TMTCSERVICES_TMSTOREFRONTENDIF_H_ */ +#ifndef PLATFORM_TMTCSERVICES_TMSTOREFRONTENDIF_H_ +#define PLATFORM_TMTCSERVICES_TMSTOREFRONTENDIF_H_ + +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../tmstorage/TmStorePackets.h" +#include "../ipc/MessageQueueSenderIF.h" +class TmPacketMinimal; +class SpacePacketBase; +class TmStoreBackendIF; + +class TmStoreFrontendIF { +public: + virtual TmStoreBackendIF* getBackend() const = 0; + + /** + * What do I need to implement here? + * This is propably used by PUS Service 15 so we should propably check for messages.. + * Provide base implementation? + * @param opCode + * @return + */ + virtual ReturnValue_t performOperation(uint8_t opCode) = 0; + /** + * Callback from the back-end to indicate a certain packet was received. + * front-end takes care of discarding/downloading the packet. + * @param packet Pointer to the newly received Space Packet. + * @param address Start address of the packet found + * @param isLastPacket Indicates if no more packets can be fetched. + * @return If more packets shall be fetched, RETURN_OK must be returned. + * Any other code stops fetching packets. + */ + virtual ReturnValue_t packetRetrieved(TmPacketMinimal* packet, uint32_t address) = 0; + virtual void noMorePacketsInStore() = 0; + virtual void handleRetrievalFailed(ReturnValue_t errorCode, uint32_t parameter1 = 0, uint32_t parameter2 = 0) = 0; + /** + * To get the queue where commands shall be sent. + * @return Id of command queue. + */ + virtual MessageQueueId_t getCommandQueue() const = 0; + virtual ReturnValue_t fetchPackets(ApidSsc start, ApidSsc end) = 0; + virtual ReturnValue_t deletePackets(ApidSsc upTo) = 0; + virtual ReturnValue_t checkPacket(SpacePacketBase* tmPacket) = 0; + virtual bool isEnabled() const = 0; + virtual void setEnabled(bool enabled) = 0; + virtual void resetDownlinkedPacketCount() = 0; + virtual ReturnValue_t setDumpTarget(object_id_t dumpTarget) = 0; + static const uint8_t INTERFACE_ID = CLASS_ID::TM_STORE_FRONTEND_IF; + static const ReturnValue_t BUSY = MAKE_RETURN_CODE(1); + static const ReturnValue_t LAST_PACKET_FOUND = MAKE_RETURN_CODE(2); + static const ReturnValue_t STOP_FETCH = MAKE_RETURN_CODE(3); + static const ReturnValue_t TIMEOUT = MAKE_RETURN_CODE(4); + static const ReturnValue_t TM_CHANNEL_FULL = MAKE_RETURN_CODE(5); + static const ReturnValue_t NOT_STORED = MAKE_RETURN_CODE(6); + static const ReturnValue_t ALL_DELETED = MAKE_RETURN_CODE(7); + static const ReturnValue_t INVALID_DATA = MAKE_RETURN_CODE(8); + static const ReturnValue_t NOT_READY = MAKE_RETURN_CODE(9); + virtual ~TmStoreFrontendIF() { + } +}; + + + +#endif /* PLATFORM_TMTCSERVICES_TMSTOREFRONTENDIF_H_ */ diff --git a/tmstorage/TmStoreMessage.cpp b/tmstorage/TmStoreMessage.cpp index 669ecc0e..0436442b 100644 --- a/tmstorage/TmStoreMessage.cpp +++ b/tmstorage/TmStoreMessage.cpp @@ -1,165 +1,165 @@ -#include -#include - -TmStoreMessage::~TmStoreMessage() { - -} - -TmStoreMessage::TmStoreMessage() { -} - -ReturnValue_t TmStoreMessage::setEnableStoringMessage(CommandMessage* cmd, - bool setEnabled) { - cmd->setCommand(ENABLE_STORING); - cmd->setParameter(setEnabled); - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t TmStoreMessage::setDeleteContentMessage(CommandMessage* cmd, - ApidSsc upTo) { - cmd->setCommand(DELETE_STORE_CONTENT); - cmd->setParameter((upTo.apid<<16) + upTo.ssc); - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t TmStoreMessage::setDownlinkContentMessage(CommandMessage* cmd, - ApidSsc fromPacket, - ApidSsc toPacket) { - cmd->setCommand(DOWNLINK_STORE_CONTENT); - cmd->setParameter((fromPacket.apid<<16) + fromPacket.ssc); - cmd->setParameter2((toPacket.apid<<16) + toPacket.ssc); - return HasReturnvaluesIF::RETURN_OK; -} - -ApidSsc TmStoreMessage::getPacketId1(CommandMessage* cmd) { - ApidSsc temp; - temp.apid = (cmd->getParameter() >> 16) & 0xFFFF; - temp.ssc = cmd->getParameter() & 0xFFFF; - return temp; -} - -ApidSsc TmStoreMessage::getPacketId2(CommandMessage* cmd) { - ApidSsc temp; - temp.apid = (cmd->getParameter2() >> 16) & 0xFFFF; - temp.ssc = cmd->getParameter2() & 0xFFFF; - return temp; -} - -bool TmStoreMessage::getEnableStoring(CommandMessage* cmd) { - return (bool)cmd->getParameter(); -} - -void TmStoreMessage::setChangeSelectionDefinitionMessage( - CommandMessage* cmd, bool addDefinition, store_address_t store_id) { - cmd->setCommand(CHANGE_SELECTION_DEFINITION); - cmd->setParameter(addDefinition); - cmd->setParameter2(store_id.raw); -} - -void TmStoreMessage::clear(CommandMessage* cmd) { - switch(cmd->getCommand()) { - case SELECTION_DEFINITION_REPORT: - case STORE_CATALOGUE_REPORT: - case CHANGE_SELECTION_DEFINITION: - case INDEX_REPORT: - case DELETE_STORE_CONTENT_TIME: - case DOWNLINK_STORE_CONTENT_TIME: { - StorageManagerIF *ipcStore = objectManager->get( - objects::IPC_STORE); - if (ipcStore != NULL) { - ipcStore->deleteData(getStoreId(cmd)); - } - } - /* NO BREAK falls through*/ - case DELETE_STORE_CONTENT_BLOCKS: - case DOWNLINK_STORE_CONTENT_BLOCKS: - case REPORT_INDEX_REQUEST: - cmd->setCommand(CommandMessage::UNKNOWN_COMMAND); - cmd->setParameter(0); - cmd->setParameter2(0); - break; - default: - break; - } -} - -store_address_t TmStoreMessage::getStoreId(const CommandMessage* cmd) { - store_address_t temp; - temp.raw = cmd->getParameter2(); - return temp; -} - -bool TmStoreMessage::getAddToSelection(CommandMessage* cmd) { - return (bool)cmd->getParameter(); -} - -ReturnValue_t TmStoreMessage::setReportSelectionDefinitionMessage( - CommandMessage* cmd) { - cmd->setCommand(REPORT_SELECTION_DEFINITION); - return HasReturnvaluesIF::RETURN_OK; -} - -void TmStoreMessage::setSelectionDefinitionReportMessage( - CommandMessage* cmd, store_address_t storeId) { - cmd->setCommand(SELECTION_DEFINITION_REPORT); - cmd->setParameter2(storeId.raw); -} - -ReturnValue_t TmStoreMessage::setReportStoreCatalogueMessage( - CommandMessage* cmd) { - cmd->setCommand(REPORT_STORE_CATALOGUE); - return HasReturnvaluesIF::RETURN_OK; -} - -void TmStoreMessage::setStoreCatalogueReportMessage(CommandMessage* cmd, object_id_t objectId, - store_address_t storeId) { - cmd->setCommand(STORE_CATALOGUE_REPORT); - cmd->setParameter(objectId); - cmd->setParameter2(storeId.raw); -} - -object_id_t TmStoreMessage::getObjectId(CommandMessage* cmd) { - return cmd->getParameter(); -} - -void TmStoreMessage::setDownlinkContentTimeMessage(CommandMessage* cmd, - store_address_t storeId) { - cmd->setCommand(DOWNLINK_STORE_CONTENT_TIME); - cmd->setParameter2(storeId.raw); -} - -uint32_t TmStoreMessage::getAddressLow(CommandMessage* cmd){ - return cmd->getParameter(); -} -uint32_t TmStoreMessage::getAddressHigh(CommandMessage* cmd){ - return cmd->getParameter2(); -} - -void TmStoreMessage::setDeleteContentTimeMessage(CommandMessage* cmd, - store_address_t storeId) { - cmd->setCommand(DELETE_STORE_CONTENT_TIME); - cmd->setParameter2(storeId.raw); -} - -ReturnValue_t TmStoreMessage::setDeleteBlocksMessage(CommandMessage* cmd, uint32_t addressLow, uint32_t addressHigh){ - cmd->setCommand(DELETE_STORE_CONTENT_BLOCKS); - cmd->setParameter(addressLow); - cmd->setParameter2(addressHigh); - return HasReturnvaluesIF::RETURN_OK; -} -ReturnValue_t TmStoreMessage::setDownlinkBlocksMessage(CommandMessage* cmd, uint32_t addressLow, uint32_t addressHigh){ - cmd->setCommand(DOWNLINK_STORE_CONTENT_BLOCKS); - cmd->setParameter(addressLow); - cmd->setParameter2(addressHigh); - return HasReturnvaluesIF::RETURN_OK; -} -ReturnValue_t TmStoreMessage::setIndexRequestMessage(CommandMessage* cmd){ - cmd->setCommand(REPORT_INDEX_REQUEST); - return HasReturnvaluesIF::RETURN_OK; -} - - -void TmStoreMessage::setIndexReportMessage(CommandMessage* cmd, store_address_t storeId){ - cmd->setCommand(INDEX_REPORT); - cmd->setParameter2(storeId.raw); -} +#include "../objectmanager/ObjectManagerIF.h" +#include "../tmstorage/TmStoreMessage.h" + +TmStoreMessage::~TmStoreMessage() { + +} + +TmStoreMessage::TmStoreMessage() { +} + +ReturnValue_t TmStoreMessage::setEnableStoringMessage(CommandMessage* cmd, + bool setEnabled) { + cmd->setCommand(ENABLE_STORING); + cmd->setParameter(setEnabled); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t TmStoreMessage::setDeleteContentMessage(CommandMessage* cmd, + ApidSsc upTo) { + cmd->setCommand(DELETE_STORE_CONTENT); + cmd->setParameter((upTo.apid<<16) + upTo.ssc); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t TmStoreMessage::setDownlinkContentMessage(CommandMessage* cmd, + ApidSsc fromPacket, + ApidSsc toPacket) { + cmd->setCommand(DOWNLINK_STORE_CONTENT); + cmd->setParameter((fromPacket.apid<<16) + fromPacket.ssc); + cmd->setParameter2((toPacket.apid<<16) + toPacket.ssc); + return HasReturnvaluesIF::RETURN_OK; +} + +ApidSsc TmStoreMessage::getPacketId1(CommandMessage* cmd) { + ApidSsc temp; + temp.apid = (cmd->getParameter() >> 16) & 0xFFFF; + temp.ssc = cmd->getParameter() & 0xFFFF; + return temp; +} + +ApidSsc TmStoreMessage::getPacketId2(CommandMessage* cmd) { + ApidSsc temp; + temp.apid = (cmd->getParameter2() >> 16) & 0xFFFF; + temp.ssc = cmd->getParameter2() & 0xFFFF; + return temp; +} + +bool TmStoreMessage::getEnableStoring(CommandMessage* cmd) { + return (bool)cmd->getParameter(); +} + +void TmStoreMessage::setChangeSelectionDefinitionMessage( + CommandMessage* cmd, bool addDefinition, store_address_t store_id) { + cmd->setCommand(CHANGE_SELECTION_DEFINITION); + cmd->setParameter(addDefinition); + cmd->setParameter2(store_id.raw); +} + +void TmStoreMessage::clear(CommandMessage* cmd) { + switch(cmd->getCommand()) { + case SELECTION_DEFINITION_REPORT: + case STORE_CATALOGUE_REPORT: + case CHANGE_SELECTION_DEFINITION: + case INDEX_REPORT: + case DELETE_STORE_CONTENT_TIME: + case DOWNLINK_STORE_CONTENT_TIME: { + StorageManagerIF *ipcStore = objectManager->get( + objects::IPC_STORE); + if (ipcStore != NULL) { + ipcStore->deleteData(getStoreId(cmd)); + } + } + /* NO BREAK falls through*/ + case DELETE_STORE_CONTENT_BLOCKS: + case DOWNLINK_STORE_CONTENT_BLOCKS: + case REPORT_INDEX_REQUEST: + cmd->setCommand(CommandMessage::UNKNOWN_COMMAND); + cmd->setParameter(0); + cmd->setParameter2(0); + break; + default: + break; + } +} + +store_address_t TmStoreMessage::getStoreId(const CommandMessage* cmd) { + store_address_t temp; + temp.raw = cmd->getParameter2(); + return temp; +} + +bool TmStoreMessage::getAddToSelection(CommandMessage* cmd) { + return (bool)cmd->getParameter(); +} + +ReturnValue_t TmStoreMessage::setReportSelectionDefinitionMessage( + CommandMessage* cmd) { + cmd->setCommand(REPORT_SELECTION_DEFINITION); + return HasReturnvaluesIF::RETURN_OK; +} + +void TmStoreMessage::setSelectionDefinitionReportMessage( + CommandMessage* cmd, store_address_t storeId) { + cmd->setCommand(SELECTION_DEFINITION_REPORT); + cmd->setParameter2(storeId.raw); +} + +ReturnValue_t TmStoreMessage::setReportStoreCatalogueMessage( + CommandMessage* cmd) { + cmd->setCommand(REPORT_STORE_CATALOGUE); + return HasReturnvaluesIF::RETURN_OK; +} + +void TmStoreMessage::setStoreCatalogueReportMessage(CommandMessage* cmd, object_id_t objectId, + store_address_t storeId) { + cmd->setCommand(STORE_CATALOGUE_REPORT); + cmd->setParameter(objectId); + cmd->setParameter2(storeId.raw); +} + +object_id_t TmStoreMessage::getObjectId(CommandMessage* cmd) { + return cmd->getParameter(); +} + +void TmStoreMessage::setDownlinkContentTimeMessage(CommandMessage* cmd, + store_address_t storeId) { + cmd->setCommand(DOWNLINK_STORE_CONTENT_TIME); + cmd->setParameter2(storeId.raw); +} + +uint32_t TmStoreMessage::getAddressLow(CommandMessage* cmd){ + return cmd->getParameter(); +} +uint32_t TmStoreMessage::getAddressHigh(CommandMessage* cmd){ + return cmd->getParameter2(); +} + +void TmStoreMessage::setDeleteContentTimeMessage(CommandMessage* cmd, + store_address_t storeId) { + cmd->setCommand(DELETE_STORE_CONTENT_TIME); + cmd->setParameter2(storeId.raw); +} + +ReturnValue_t TmStoreMessage::setDeleteBlocksMessage(CommandMessage* cmd, uint32_t addressLow, uint32_t addressHigh){ + cmd->setCommand(DELETE_STORE_CONTENT_BLOCKS); + cmd->setParameter(addressLow); + cmd->setParameter2(addressHigh); + return HasReturnvaluesIF::RETURN_OK; +} +ReturnValue_t TmStoreMessage::setDownlinkBlocksMessage(CommandMessage* cmd, uint32_t addressLow, uint32_t addressHigh){ + cmd->setCommand(DOWNLINK_STORE_CONTENT_BLOCKS); + cmd->setParameter(addressLow); + cmd->setParameter2(addressHigh); + return HasReturnvaluesIF::RETURN_OK; +} +ReturnValue_t TmStoreMessage::setIndexRequestMessage(CommandMessage* cmd){ + cmd->setCommand(REPORT_INDEX_REQUEST); + return HasReturnvaluesIF::RETURN_OK; +} + + +void TmStoreMessage::setIndexReportMessage(CommandMessage* cmd, store_address_t storeId){ + cmd->setCommand(INDEX_REPORT); + cmd->setParameter2(storeId.raw); +} diff --git a/tmstorage/TmStoreMessage.h b/tmstorage/TmStoreMessage.h index 93c23e40..ce10519b 100644 --- a/tmstorage/TmStoreMessage.h +++ b/tmstorage/TmStoreMessage.h @@ -1,63 +1,63 @@ -#ifndef FRAMEWORK_TMSTORAGE_TMSTOREMESSAGE_H_ -#define FRAMEWORK_TMSTORAGE_TMSTOREMESSAGE_H_ - -#include -#include -#include -#include -class TmStoreMessage { -public: - static ReturnValue_t setEnableStoringMessage(CommandMessage* cmd, - bool setEnabled); - static ReturnValue_t setDeleteContentMessage(CommandMessage* cmd, - ApidSsc upTo); - static ReturnValue_t setDownlinkContentMessage(CommandMessage* cmd, - ApidSsc fromPacket, ApidSsc toPacket); - static void setChangeSelectionDefinitionMessage(CommandMessage* cmd, - bool addDefinition, store_address_t store_id); - static ReturnValue_t setReportSelectionDefinitionMessage( - CommandMessage* cmd); - static void setSelectionDefinitionReportMessage(CommandMessage* cmd, - store_address_t storeId); - static ReturnValue_t setReportStoreCatalogueMessage(CommandMessage* cmd); - static void setStoreCatalogueReportMessage(CommandMessage* cmd, object_id_t objectId, - store_address_t storeId); - static void setDownlinkContentTimeMessage(CommandMessage* cmd, - store_address_t storeId); - static void setIndexReportMessage(CommandMessage* cmd, store_address_t storeId); - static ReturnValue_t setDeleteBlocksMessage(CommandMessage* cmd, uint32_t addressLow, uint32_t addressHigh); - static ReturnValue_t setDownlinkBlocksMessage(CommandMessage* cmd, uint32_t addressLow, uint32_t addressHigh); - static ReturnValue_t setIndexRequestMessage(CommandMessage* cmd); - static void setDeleteContentTimeMessage(CommandMessage* cmd, - store_address_t storeId); - static void clear(CommandMessage* cmd); - static object_id_t getObjectId(CommandMessage* cmd); - static ApidSsc getPacketId1(CommandMessage* cmd); - static ApidSsc getPacketId2(CommandMessage* cmd); - static bool getEnableStoring(CommandMessage* cmd); - static bool getAddToSelection(CommandMessage* cmd); - static uint32_t getAddressLow(CommandMessage* cmd); - static uint32_t getAddressHigh(CommandMessage* cmd); - - static store_address_t getStoreId(const CommandMessage* cmd); - virtual ~TmStoreMessage(); - static const uint8_t MESSAGE_ID = messagetypes::TM_STORE; - static const Command_t ENABLE_STORING = MAKE_COMMAND_ID(1); - static const Command_t DELETE_STORE_CONTENT = MAKE_COMMAND_ID(2); - static const Command_t DOWNLINK_STORE_CONTENT = MAKE_COMMAND_ID(3); - static const Command_t CHANGE_SELECTION_DEFINITION = MAKE_COMMAND_ID(4); - static const Command_t REPORT_SELECTION_DEFINITION = MAKE_COMMAND_ID(5); - static const Command_t SELECTION_DEFINITION_REPORT = MAKE_COMMAND_ID(6); - static const Command_t REPORT_STORE_CATALOGUE = MAKE_COMMAND_ID(7); - static const Command_t STORE_CATALOGUE_REPORT = MAKE_COMMAND_ID(8); - static const Command_t DOWNLINK_STORE_CONTENT_TIME = MAKE_COMMAND_ID(9); - static const Command_t DELETE_STORE_CONTENT_TIME = MAKE_COMMAND_ID(10); - static const Command_t DELETE_STORE_CONTENT_BLOCKS = MAKE_COMMAND_ID(11); - static const Command_t DOWNLINK_STORE_CONTENT_BLOCKS = MAKE_COMMAND_ID(12); - static const Command_t REPORT_INDEX_REQUEST = MAKE_COMMAND_ID(13); - static const Command_t INDEX_REPORT = MAKE_COMMAND_ID(14); -private: - TmStoreMessage(); -}; - -#endif /* FRAMEWORK_TMSTORAGE_TMSTOREMESSAGE_H_ */ +#ifndef FRAMEWORK_TMSTORAGE_TMSTOREMESSAGE_H_ +#define FRAMEWORK_TMSTORAGE_TMSTOREMESSAGE_H_ + +#include "../ipc/CommandMessage.h" +#include "../storagemanager/StorageManagerIF.h" +#include "../tmstorage/TmStorePackets.h" +#include "../objectmanager/SystemObjectIF.h" +class TmStoreMessage { +public: + static ReturnValue_t setEnableStoringMessage(CommandMessage* cmd, + bool setEnabled); + static ReturnValue_t setDeleteContentMessage(CommandMessage* cmd, + ApidSsc upTo); + static ReturnValue_t setDownlinkContentMessage(CommandMessage* cmd, + ApidSsc fromPacket, ApidSsc toPacket); + static void setChangeSelectionDefinitionMessage(CommandMessage* cmd, + bool addDefinition, store_address_t store_id); + static ReturnValue_t setReportSelectionDefinitionMessage( + CommandMessage* cmd); + static void setSelectionDefinitionReportMessage(CommandMessage* cmd, + store_address_t storeId); + static ReturnValue_t setReportStoreCatalogueMessage(CommandMessage* cmd); + static void setStoreCatalogueReportMessage(CommandMessage* cmd, object_id_t objectId, + store_address_t storeId); + static void setDownlinkContentTimeMessage(CommandMessage* cmd, + store_address_t storeId); + static void setIndexReportMessage(CommandMessage* cmd, store_address_t storeId); + static ReturnValue_t setDeleteBlocksMessage(CommandMessage* cmd, uint32_t addressLow, uint32_t addressHigh); + static ReturnValue_t setDownlinkBlocksMessage(CommandMessage* cmd, uint32_t addressLow, uint32_t addressHigh); + static ReturnValue_t setIndexRequestMessage(CommandMessage* cmd); + static void setDeleteContentTimeMessage(CommandMessage* cmd, + store_address_t storeId); + static void clear(CommandMessage* cmd); + static object_id_t getObjectId(CommandMessage* cmd); + static ApidSsc getPacketId1(CommandMessage* cmd); + static ApidSsc getPacketId2(CommandMessage* cmd); + static bool getEnableStoring(CommandMessage* cmd); + static bool getAddToSelection(CommandMessage* cmd); + static uint32_t getAddressLow(CommandMessage* cmd); + static uint32_t getAddressHigh(CommandMessage* cmd); + + static store_address_t getStoreId(const CommandMessage* cmd); + virtual ~TmStoreMessage(); + static const uint8_t MESSAGE_ID = messagetypes::TM_STORE; + static const Command_t ENABLE_STORING = MAKE_COMMAND_ID(1); + static const Command_t DELETE_STORE_CONTENT = MAKE_COMMAND_ID(2); + static const Command_t DOWNLINK_STORE_CONTENT = MAKE_COMMAND_ID(3); + static const Command_t CHANGE_SELECTION_DEFINITION = MAKE_COMMAND_ID(4); + static const Command_t REPORT_SELECTION_DEFINITION = MAKE_COMMAND_ID(5); + static const Command_t SELECTION_DEFINITION_REPORT = MAKE_COMMAND_ID(6); + static const Command_t REPORT_STORE_CATALOGUE = MAKE_COMMAND_ID(7); + static const Command_t STORE_CATALOGUE_REPORT = MAKE_COMMAND_ID(8); + static const Command_t DOWNLINK_STORE_CONTENT_TIME = MAKE_COMMAND_ID(9); + static const Command_t DELETE_STORE_CONTENT_TIME = MAKE_COMMAND_ID(10); + static const Command_t DELETE_STORE_CONTENT_BLOCKS = MAKE_COMMAND_ID(11); + static const Command_t DOWNLINK_STORE_CONTENT_BLOCKS = MAKE_COMMAND_ID(12); + static const Command_t REPORT_INDEX_REQUEST = MAKE_COMMAND_ID(13); + static const Command_t INDEX_REPORT = MAKE_COMMAND_ID(14); +private: + TmStoreMessage(); +}; + +#endif /* FRAMEWORK_TMSTORAGE_TMSTOREMESSAGE_H_ */ diff --git a/tmstorage/TmStorePackets.h b/tmstorage/TmStorePackets.h index 9a669a7d..3c8e1a24 100644 --- a/tmstorage/TmStorePackets.h +++ b/tmstorage/TmStorePackets.h @@ -1,300 +1,300 @@ -#ifndef FRAMEWORK_TMSTORAGE_TMSTOREPACKETS_H_ -#define FRAMEWORK_TMSTORAGE_TMSTOREPACKETS_H_ - -#include -#include -#include -#include -#include -#include -#include -#include - -class ServiceSubservice: public SerialLinkedListAdapter { -public: - SerializeElement service; - SerialFixedArrayListAdapter subservices; - LinkedElement linkedSubservices; - ServiceSubservice() : - SerialLinkedListAdapter(&service), linkedSubservices( - &subservices) { - service.setNext(&linkedSubservices); - } -}; - -class ApidSsc: public SerializeIF { -public: - ApidSsc() : - apid(SpacePacketBase::LIMIT_APID), ssc(0) { - } - ApidSsc(uint16_t apid, uint16_t ssc) : - apid(apid), ssc(ssc) { - } - uint16_t apid; - uint16_t ssc; - ReturnValue_t serialize(uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) const { - ReturnValue_t result = SerializeAdapter::serialize(&apid, - buffer, size, maxSize, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - return SerializeAdapter::serialize(&ssc, buffer, size, - maxSize, streamEndianness); - - } - - size_t getSerializedSize() const { - return sizeof(apid) + sizeof(ssc); - } - - ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - Endianness streamEndianness) { - ReturnValue_t result = SerializeAdapter::deSerialize(&apid, - buffer, size, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - return SerializeAdapter::deSerialize(&ssc, buffer, size, - streamEndianness); - } -}; - -class ChangeSelectionDefinition: public SerialLinkedListAdapter { -public: - SerializeElement apid; - SerialFixedArrayListAdapter serviceList; - LinkedElement linkedServiceList; - ChangeSelectionDefinition() : - SerialLinkedListAdapter(&apid), linkedServiceList( - &serviceList) { - apid.setNext(&linkedServiceList); - } -}; - -class TmPacketInformation: public SerializeIF { -public: - TmPacketInformation(TmPacketMinimal* packet){ - setContent(packet); - } - TmPacketInformation() :apid( - SpacePacketBase::LIMIT_APID), sourceSequenceCount(0), serviceType( - 0), serviceSubtype(0), subCounter(0) { - } - void reset() { - apid = SpacePacketBase::LIMIT_APID; - sourceSequenceCount = 0; - serviceType = 0; - serviceSubtype = 0; - subCounter = 0; - memset(rawTimestamp, 0, sizeof(rawTimestamp)); - } - void setContent(TmPacketMinimal* packet) { - apid = packet->getAPID(); - sourceSequenceCount = packet->getPacketSequenceCount(); - serviceType = packet->getService(); - serviceSubtype = packet->getSubService(); - subCounter = packet->getPacketSubcounter(); - memset(rawTimestamp, 0, sizeof(rawTimestamp)); - const uint8_t* pField = NULL; - uint32_t size = 0; - ReturnValue_t result = packet->getPacketTimeRaw(&pField, &size); - if (result != HasReturnvaluesIF::RETURN_OK) { - return; - } - if (*pField == CCSDSTime::P_FIELD_CDS_SHORT - && size <= TimeStamperIF::MISSION_TIMESTAMP_SIZE) { - //Shortcut to avoid converting CDS back and forth. - memcpy(rawTimestamp, pField, size); - return; - } - timeval time = { 0, 0 }; - result = packet->getPacketTime(&time); - if (result != HasReturnvaluesIF::RETURN_OK) { - return; - } - - CCSDSTime::CDS_short cdsFormat; - result = CCSDSTime::convertToCcsds(&cdsFormat, &time); - if (result != HasReturnvaluesIF::RETURN_OK) { - return; - } - memcpy(rawTimestamp, &cdsFormat, sizeof(cdsFormat)); - } - void setContent(TmPacketInformation* content) { - apid = content->apid; - sourceSequenceCount = content->sourceSequenceCount; - serviceType = content->serviceType; - serviceSubtype = content->serviceSubtype; - subCounter = content->subCounter; - memcpy(rawTimestamp, content->rawTimestamp, sizeof(rawTimestamp)); - } - bool isValid() const { - return (apid < SpacePacketBase::LIMIT_APID) ? true : false; - } - static void reset(TmPacketInformation* packet){ - packet->reset(); - } - - static bool isOlderThan(const TmPacketInformation* packet, const timeval* cmpTime){ - if(packet->isValid()){ - timeval packetTime = {0,0}; - uint32_t foundlen = 0; - CCSDSTime::convertFromCcsds(&packetTime,&packet->rawTimestamp[0],&foundlen,sizeof(rawTimestamp)); - if(packetTime <= *cmpTime){ - return true; - } - } - return false; - } - - static bool isNewerThan(const TmPacketInformation* packet, const timeval* cmpTime){ - if(packet->isValid()){ - timeval packetTime = {0,0}; - uint32_t foundlen = 0; - CCSDSTime::convertFromCcsds(&packetTime,&packet->rawTimestamp[0],&foundlen,sizeof(rawTimestamp)); - if(packetTime >= *cmpTime){ - return true; - } - } - return false; - } - - static bool isSmallerSSC(const TmPacketInformation* packet,const ApidSsc* compareSSC){ - if(packet->isValid()){ - if(packet->apid == compareSSC->apid){ - if(packet->sourceSequenceCount <= compareSSC->ssc){ - return true; - } - } - } - return false; - } - - static bool isLargerSSC(const TmPacketInformation* packet,const ApidSsc* compareSSC){ - if(packet->isValid()){ - if(packet->apid == compareSSC->apid){ - if(packet->sourceSequenceCount >= compareSSC->ssc){ - return true; - } - } - } - return false; - } - - uint16_t getApid() const{ - return apid; - } - - uint16_t getSsc() const{ - return sourceSequenceCount; - } - - uint8_t getServiceType() const{ - return serviceType; - } - - uint8_t getServiceSubtype() const{ - return serviceSubtype; - } - - uint8_t getSubCounter() const{ - return subCounter; - } - - timeval getTime() const { - timeval packetTime = {0,0}; - uint32_t foundlen = 0; - CCSDSTime::convertFromCcsds(&packetTime,&this->rawTimestamp[0],&foundlen,sizeof(rawTimestamp)); - return packetTime; - } - - bool operator==(const TmPacketInformation& other) { - //TODO Does not compare Raw Timestamp - return ((apid == other.getApid()) - && (sourceSequenceCount == other.getSsc()) - && (serviceType == other.getServiceType()) && (serviceSubtype = - other.getServiceSubtype())); - } - - - ReturnValue_t serialize(uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) const { - ReturnValue_t result = SerializeAdapter::serialize(&apid,buffer,size,maxSize,streamEndianness); - if(result!=HasReturnvaluesIF::RETURN_OK){ - return result; - } - result = SerializeAdapter::serialize(&sourceSequenceCount,buffer,size,maxSize,streamEndianness); - if(result!=HasReturnvaluesIF::RETURN_OK){ - return result; - } - result = SerializeAdapter::serialize(&serviceType,buffer,size,maxSize,streamEndianness); - if(result!=HasReturnvaluesIF::RETURN_OK){ - return result; - } - result = SerializeAdapter::serialize(&serviceSubtype,buffer,size,maxSize,streamEndianness); - if(result!=HasReturnvaluesIF::RETURN_OK){ - return result; - } - result = SerializeAdapter::serialize(&subCounter,buffer,size,maxSize,streamEndianness); - if(result!=HasReturnvaluesIF::RETURN_OK){ - return result; - } - SerialBufferAdapter adapter(rawTimestamp,sizeof(rawTimestamp)); - return adapter.serialize(buffer,size,maxSize,streamEndianness); - } - - size_t getSerializedSize() const { - uint32_t size = 0; - size += SerializeAdapter::getSerializedSize(&apid); - size += SerializeAdapter::getSerializedSize(&sourceSequenceCount); - size += SerializeAdapter::getSerializedSize(&serviceType); - size += SerializeAdapter::getSerializedSize(&serviceSubtype); - size += SerializeAdapter::getSerializedSize(&subCounter); - SerialBufferAdapter adapter(rawTimestamp,sizeof(rawTimestamp)); - size += adapter.getSerializedSize(); - return size; - - }; - - ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - Endianness streamEndianness) { - ReturnValue_t result = SerializeAdapter::deSerialize(&apid, buffer, - size, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - result = SerializeAdapter::deSerialize(&sourceSequenceCount, buffer, - size, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - result = SerializeAdapter::deSerialize(&serviceType, buffer, size, - streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - result = SerializeAdapter::deSerialize(&serviceSubtype, buffer, - size, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - result = SerializeAdapter::deSerialize(&subCounter, buffer, size, - streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - SerialBufferAdapter adapter(rawTimestamp,sizeof(rawTimestamp)); - return adapter.deSerialize(buffer,size,streamEndianness); - } - -private: - uint16_t apid; - uint16_t sourceSequenceCount; - uint8_t serviceType; - uint8_t serviceSubtype; - uint8_t subCounter; - uint8_t rawTimestamp[TimeStamperIF::MISSION_TIMESTAMP_SIZE]; - -}; -#endif /* FRAMEWORK_TMSTORAGE_TMSTOREPACKETS_H_ */ +#ifndef FRAMEWORK_TMSTORAGE_TMSTOREPACKETS_H_ +#define FRAMEWORK_TMSTORAGE_TMSTOREPACKETS_H_ + +#include "../serialize/SerialFixedArrayListAdapter.h" +#include "../serialize/SerializeElement.h" +#include "../serialize/SerialLinkedListAdapter.h" +#include "../serialize/SerialBufferAdapter.h" +#include "../tmtcpacket/pus/TmPacketMinimal.h" +#include "../timemanager/TimeStamperIF.h" +#include "../timemanager/CCSDSTime.h" +#include "../globalfunctions/timevalOperations.h" + +class ServiceSubservice: public SerialLinkedListAdapter { +public: + SerializeElement service; + SerialFixedArrayListAdapter subservices; + LinkedElement linkedSubservices; + ServiceSubservice() : + SerialLinkedListAdapter(&service), linkedSubservices( + &subservices) { + service.setNext(&linkedSubservices); + } +}; + +class ApidSsc: public SerializeIF { +public: + ApidSsc() : + apid(SpacePacketBase::LIMIT_APID), ssc(0) { + } + ApidSsc(uint16_t apid, uint16_t ssc) : + apid(apid), ssc(ssc) { + } + uint16_t apid; + uint16_t ssc; + ReturnValue_t serialize(uint8_t** buffer, size_t* size, + size_t maxSize, Endianness streamEndianness) const { + ReturnValue_t result = SerializeAdapter::serialize(&apid, + buffer, size, maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return SerializeAdapter::serialize(&ssc, buffer, size, + maxSize, streamEndianness); + + } + + size_t getSerializedSize() const { + return sizeof(apid) + sizeof(ssc); + } + + ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + Endianness streamEndianness) { + ReturnValue_t result = SerializeAdapter::deSerialize(&apid, + buffer, size, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return SerializeAdapter::deSerialize(&ssc, buffer, size, + streamEndianness); + } +}; + +class ChangeSelectionDefinition: public SerialLinkedListAdapter { +public: + SerializeElement apid; + SerialFixedArrayListAdapter serviceList; + LinkedElement linkedServiceList; + ChangeSelectionDefinition() : + SerialLinkedListAdapter(&apid), linkedServiceList( + &serviceList) { + apid.setNext(&linkedServiceList); + } +}; + +class TmPacketInformation: public SerializeIF { +public: + TmPacketInformation(TmPacketMinimal* packet){ + setContent(packet); + } + TmPacketInformation() :apid( + SpacePacketBase::LIMIT_APID), sourceSequenceCount(0), serviceType( + 0), serviceSubtype(0), subCounter(0) { + } + void reset() { + apid = SpacePacketBase::LIMIT_APID; + sourceSequenceCount = 0; + serviceType = 0; + serviceSubtype = 0; + subCounter = 0; + memset(rawTimestamp, 0, sizeof(rawTimestamp)); + } + void setContent(TmPacketMinimal* packet) { + apid = packet->getAPID(); + sourceSequenceCount = packet->getPacketSequenceCount(); + serviceType = packet->getService(); + serviceSubtype = packet->getSubService(); + subCounter = packet->getPacketSubcounter(); + memset(rawTimestamp, 0, sizeof(rawTimestamp)); + const uint8_t* pField = NULL; + uint32_t size = 0; + ReturnValue_t result = packet->getPacketTimeRaw(&pField, &size); + if (result != HasReturnvaluesIF::RETURN_OK) { + return; + } + if (*pField == CCSDSTime::P_FIELD_CDS_SHORT + && size <= TimeStamperIF::MISSION_TIMESTAMP_SIZE) { + //Shortcut to avoid converting CDS back and forth. + memcpy(rawTimestamp, pField, size); + return; + } + timeval time = { 0, 0 }; + result = packet->getPacketTime(&time); + if (result != HasReturnvaluesIF::RETURN_OK) { + return; + } + + CCSDSTime::CDS_short cdsFormat; + result = CCSDSTime::convertToCcsds(&cdsFormat, &time); + if (result != HasReturnvaluesIF::RETURN_OK) { + return; + } + memcpy(rawTimestamp, &cdsFormat, sizeof(cdsFormat)); + } + void setContent(TmPacketInformation* content) { + apid = content->apid; + sourceSequenceCount = content->sourceSequenceCount; + serviceType = content->serviceType; + serviceSubtype = content->serviceSubtype; + subCounter = content->subCounter; + memcpy(rawTimestamp, content->rawTimestamp, sizeof(rawTimestamp)); + } + bool isValid() const { + return (apid < SpacePacketBase::LIMIT_APID) ? true : false; + } + static void reset(TmPacketInformation* packet){ + packet->reset(); + } + + static bool isOlderThan(const TmPacketInformation* packet, const timeval* cmpTime){ + if(packet->isValid()){ + timeval packetTime = {0,0}; + uint32_t foundlen = 0; + CCSDSTime::convertFromCcsds(&packetTime,&packet->rawTimestamp[0],&foundlen,sizeof(rawTimestamp)); + if(packetTime <= *cmpTime){ + return true; + } + } + return false; + } + + static bool isNewerThan(const TmPacketInformation* packet, const timeval* cmpTime){ + if(packet->isValid()){ + timeval packetTime = {0,0}; + uint32_t foundlen = 0; + CCSDSTime::convertFromCcsds(&packetTime,&packet->rawTimestamp[0],&foundlen,sizeof(rawTimestamp)); + if(packetTime >= *cmpTime){ + return true; + } + } + return false; + } + + static bool isSmallerSSC(const TmPacketInformation* packet,const ApidSsc* compareSSC){ + if(packet->isValid()){ + if(packet->apid == compareSSC->apid){ + if(packet->sourceSequenceCount <= compareSSC->ssc){ + return true; + } + } + } + return false; + } + + static bool isLargerSSC(const TmPacketInformation* packet,const ApidSsc* compareSSC){ + if(packet->isValid()){ + if(packet->apid == compareSSC->apid){ + if(packet->sourceSequenceCount >= compareSSC->ssc){ + return true; + } + } + } + return false; + } + + uint16_t getApid() const{ + return apid; + } + + uint16_t getSsc() const{ + return sourceSequenceCount; + } + + uint8_t getServiceType() const{ + return serviceType; + } + + uint8_t getServiceSubtype() const{ + return serviceSubtype; + } + + uint8_t getSubCounter() const{ + return subCounter; + } + + timeval getTime() const { + timeval packetTime = {0,0}; + uint32_t foundlen = 0; + CCSDSTime::convertFromCcsds(&packetTime,&this->rawTimestamp[0],&foundlen,sizeof(rawTimestamp)); + return packetTime; + } + + bool operator==(const TmPacketInformation& other) { + //TODO Does not compare Raw Timestamp + return ((apid == other.getApid()) + && (sourceSequenceCount == other.getSsc()) + && (serviceType == other.getServiceType()) && (serviceSubtype = + other.getServiceSubtype())); + } + + + ReturnValue_t serialize(uint8_t** buffer, size_t* size, + size_t maxSize, Endianness streamEndianness) const { + ReturnValue_t result = SerializeAdapter::serialize(&apid,buffer,size,maxSize,streamEndianness); + if(result!=HasReturnvaluesIF::RETURN_OK){ + return result; + } + result = SerializeAdapter::serialize(&sourceSequenceCount,buffer,size,maxSize,streamEndianness); + if(result!=HasReturnvaluesIF::RETURN_OK){ + return result; + } + result = SerializeAdapter::serialize(&serviceType,buffer,size,maxSize,streamEndianness); + if(result!=HasReturnvaluesIF::RETURN_OK){ + return result; + } + result = SerializeAdapter::serialize(&serviceSubtype,buffer,size,maxSize,streamEndianness); + if(result!=HasReturnvaluesIF::RETURN_OK){ + return result; + } + result = SerializeAdapter::serialize(&subCounter,buffer,size,maxSize,streamEndianness); + if(result!=HasReturnvaluesIF::RETURN_OK){ + return result; + } + SerialBufferAdapter adapter(rawTimestamp,sizeof(rawTimestamp)); + return adapter.serialize(buffer,size,maxSize,streamEndianness); + } + + size_t getSerializedSize() const { + uint32_t size = 0; + size += SerializeAdapter::getSerializedSize(&apid); + size += SerializeAdapter::getSerializedSize(&sourceSequenceCount); + size += SerializeAdapter::getSerializedSize(&serviceType); + size += SerializeAdapter::getSerializedSize(&serviceSubtype); + size += SerializeAdapter::getSerializedSize(&subCounter); + SerialBufferAdapter adapter(rawTimestamp,sizeof(rawTimestamp)); + size += adapter.getSerializedSize(); + return size; + + }; + + ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + Endianness streamEndianness) { + ReturnValue_t result = SerializeAdapter::deSerialize(&apid, buffer, + size, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = SerializeAdapter::deSerialize(&sourceSequenceCount, buffer, + size, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = SerializeAdapter::deSerialize(&serviceType, buffer, size, + streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = SerializeAdapter::deSerialize(&serviceSubtype, buffer, + size, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = SerializeAdapter::deSerialize(&subCounter, buffer, size, + streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + SerialBufferAdapter adapter(rawTimestamp,sizeof(rawTimestamp)); + return adapter.deSerialize(buffer,size,streamEndianness); + } + +private: + uint16_t apid; + uint16_t sourceSequenceCount; + uint8_t serviceType; + uint8_t serviceSubtype; + uint8_t subCounter; + uint8_t rawTimestamp[TimeStamperIF::MISSION_TIMESTAMP_SIZE]; + +}; +#endif /* FRAMEWORK_TMSTORAGE_TMSTOREPACKETS_H_ */ diff --git a/tmtcpacket/SpacePacket.cpp b/tmtcpacket/SpacePacket.cpp index d9bc08fa..c04e143f 100644 --- a/tmtcpacket/SpacePacket.cpp +++ b/tmtcpacket/SpacePacket.cpp @@ -1,27 +1,27 @@ -#include -#include -#include -#include - -SpacePacket::SpacePacket( uint16_t packetDataLength, bool isTelecommand, uint16_t apid, uint16_t sequenceCount ): -SpacePacketBase( (uint8_t*)&this->localData ) { - initSpacePacketHeader(isTelecommand, false, apid, sequenceCount); - this->setPacketSequenceCount(sequenceCount); - if ( packetDataLength <= sizeof(this->localData.fields.buffer) ) { - this->setPacketDataLength(packetDataLength); - } else { - this->setPacketDataLength( sizeof(this->localData.fields.buffer) ); - } -} - -SpacePacket::~SpacePacket( void ) { -} - -bool SpacePacket::addWholeData( const uint8_t* p_Data, uint32_t packet_size ) { - if ( packet_size <= sizeof(this->data) ) { - memcpy( &this->localData.byteStream, p_Data, packet_size ); - return true; - } else { - return false; - } -} +#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../tmtcpacket/ccsds_header.h" +#include "../tmtcpacket/SpacePacket.h" +#include + +SpacePacket::SpacePacket( uint16_t packetDataLength, bool isTelecommand, uint16_t apid, uint16_t sequenceCount ): +SpacePacketBase( (uint8_t*)&this->localData ) { + initSpacePacketHeader(isTelecommand, false, apid, sequenceCount); + this->setPacketSequenceCount(sequenceCount); + if ( packetDataLength <= sizeof(this->localData.fields.buffer) ) { + this->setPacketDataLength(packetDataLength); + } else { + this->setPacketDataLength( sizeof(this->localData.fields.buffer) ); + } +} + +SpacePacket::~SpacePacket( void ) { +} + +bool SpacePacket::addWholeData( const uint8_t* p_Data, uint32_t packet_size ) { + if ( packet_size <= sizeof(this->data) ) { + memcpy( &this->localData.byteStream, p_Data, packet_size ); + return true; + } else { + return false; + } +} diff --git a/tmtcpacket/SpacePacket.h b/tmtcpacket/SpacePacket.h index f2d45752..a75b9ae3 100644 --- a/tmtcpacket/SpacePacket.h +++ b/tmtcpacket/SpacePacket.h @@ -1,70 +1,70 @@ -#ifndef SPACEPACKET_H_ -#define SPACEPACKET_H_ - -#include - -/** - * The SpacePacket class is a representation of a simple CCSDS Space Packet - * without (control over) a secondary header. - * It can be instantiated with a size smaller than \c PACKET_MAX_SIZE. Its - * main use is to serve as an idle packet in case no other packets are sent. - * For the ECSS PUS part the TcPacket and TmPacket classes are used. - * A pointer to \c local_data is passed to the \c SpacePacketBase parent class, - * so the parent's methods are reachable. - * @ingroup tmtcpackets - */ -class SpacePacket: public SpacePacketBase { -public: - static const uint16_t PACKET_MAX_SIZE = 1024; - /** - * The constructor initializes the packet and sets all header information - * according to the passed parameters. - * @param packetDataLength Sets the packet data length field and therefore specifies the size of the packet. - * @param isTelecommand Sets the packet type field to either TC (true) or TM (false). - * @param apid Sets the packet's APID field. The default value describes an idle packet. - * @param sequenceCount ets the packet's Source Sequence Count field. - */ - SpacePacket(uint16_t packetDataLength, bool isTelecommand = false, - uint16_t apid = APID_IDLE_PACKET, uint16_t sequenceCount = 0); - /** - * The class's default destructor. - */ - virtual ~SpacePacket(); - /** - * With this call, the complete data content (including the CCSDS Primary - * Header) is overwritten with the byte stream given. - * @param p_data Pointer to data to overwrite the content with - * @param packet_size Size of the data - * @return @li \c true if packet_size is smaller than \c MAX_PACKET_SIZE. - * @li \c false else. - */ - bool addWholeData(const uint8_t* p_data, uint32_t packet_size); -protected: - /** - * This structure defines the data structure of a Space Packet as local data. - * There's a buffer which corresponds to the Space Packet Data Field with a - * maximum size of \c PACKET_MAX_SIZE. - */ - struct PacketStructured { - CCSDSPrimaryHeader header; - uint8_t buffer[PACKET_MAX_SIZE]; - }; - /** - * This union simplifies accessing the full data content of the Space Packet. - * This is achieved by putting the \c PacketStructured struct in a union with - * a plain buffer. - */ - union SpacePacketData { - PacketStructured fields; - uint8_t byteStream[PACKET_MAX_SIZE + sizeof(CCSDSPrimaryHeader)]; - }; - /** - * This is the data representation of the class. - * It is a struct of CCSDS Primary Header and a data field, which again is - * packed in an union, so the data can be accessed as a byte stream without - * a cast. - */ - SpacePacketData localData; -}; - -#endif /* SPACEPACKET_H_ */ +#ifndef SPACEPACKET_H_ +#define SPACEPACKET_H_ + +#include "../tmtcpacket/SpacePacketBase.h" + +/** + * The SpacePacket class is a representation of a simple CCSDS Space Packet + * without (control over) a secondary header. + * It can be instantiated with a size smaller than \c PACKET_MAX_SIZE. Its + * main use is to serve as an idle packet in case no other packets are sent. + * For the ECSS PUS part the TcPacket and TmPacket classes are used. + * A pointer to \c local_data is passed to the \c SpacePacketBase parent class, + * so the parent's methods are reachable. + * @ingroup tmtcpackets + */ +class SpacePacket: public SpacePacketBase { +public: + static const uint16_t PACKET_MAX_SIZE = 1024; + /** + * The constructor initializes the packet and sets all header information + * according to the passed parameters. + * @param packetDataLength Sets the packet data length field and therefore specifies the size of the packet. + * @param isTelecommand Sets the packet type field to either TC (true) or TM (false). + * @param apid Sets the packet's APID field. The default value describes an idle packet. + * @param sequenceCount ets the packet's Source Sequence Count field. + */ + SpacePacket(uint16_t packetDataLength, bool isTelecommand = false, + uint16_t apid = APID_IDLE_PACKET, uint16_t sequenceCount = 0); + /** + * The class's default destructor. + */ + virtual ~SpacePacket(); + /** + * With this call, the complete data content (including the CCSDS Primary + * Header) is overwritten with the byte stream given. + * @param p_data Pointer to data to overwrite the content with + * @param packet_size Size of the data + * @return @li \c true if packet_size is smaller than \c MAX_PACKET_SIZE. + * @li \c false else. + */ + bool addWholeData(const uint8_t* p_data, uint32_t packet_size); +protected: + /** + * This structure defines the data structure of a Space Packet as local data. + * There's a buffer which corresponds to the Space Packet Data Field with a + * maximum size of \c PACKET_MAX_SIZE. + */ + struct PacketStructured { + CCSDSPrimaryHeader header; + uint8_t buffer[PACKET_MAX_SIZE]; + }; + /** + * This union simplifies accessing the full data content of the Space Packet. + * This is achieved by putting the \c PacketStructured struct in a union with + * a plain buffer. + */ + union SpacePacketData { + PacketStructured fields; + uint8_t byteStream[PACKET_MAX_SIZE + sizeof(CCSDSPrimaryHeader)]; + }; + /** + * This is the data representation of the class. + * It is a struct of CCSDS Primary Header and a data field, which again is + * packed in an union, so the data can be accessed as a byte stream without + * a cast. + */ + SpacePacketData localData; +}; + +#endif /* SPACEPACKET_H_ */ diff --git a/tmtcpacket/SpacePacketBase.cpp b/tmtcpacket/SpacePacketBase.cpp index b9ae0684..3d3a51e3 100644 --- a/tmtcpacket/SpacePacketBase.cpp +++ b/tmtcpacket/SpacePacketBase.cpp @@ -1,104 +1,104 @@ -#include -#include -#include - -SpacePacketBase::SpacePacketBase( const uint8_t* set_address ) { - this->data = (SpacePacketPointer*) set_address; -} - -SpacePacketBase::~SpacePacketBase() { -}; - -//CCSDS Methods: -uint8_t SpacePacketBase::getPacketVersionNumber( void ) { - return (this->data->header.packet_id_h & 0b11100000) >> 5; -} - -void SpacePacketBase::initSpacePacketHeader(bool isTelecommand, - bool hasSecondaryHeader, uint16_t apid, uint16_t sequenceCount) { - //reset header to zero: - memset(data,0, sizeof(this->data->header) ); - //Set TC/TM bit. - data->header.packet_id_h = ((isTelecommand? 1 : 0)) << 4; - //Set secondaryHeader bit - data->header.packet_id_h |= ((hasSecondaryHeader? 1 : 0)) << 3; - this->setAPID( apid ); - //Always initialize as standalone packets. - data->header.sequence_control_h = 0b11000000; - setPacketSequenceCount(sequenceCount); - -} - -bool SpacePacketBase::isTelecommand( void ) { - return (this->data->header.packet_id_h & 0b00010000) >> 4; -} - -bool SpacePacketBase::hasSecondaryHeader( void ) { - return (this->data->header.packet_id_h & 0b00001000) >> 3; -} - -uint16_t SpacePacketBase::getPacketId() { - return ( (this->data->header.packet_id_h) << 8 ) + - this->data->header.packet_id_l; -} - -uint16_t SpacePacketBase::getAPID( void ) const { - return ( (this->data->header.packet_id_h & 0b00000111) << 8 ) + - this->data->header.packet_id_l; -} - -void SpacePacketBase::setAPID( uint16_t new_apid ) { - //Use first three bits of new APID, but keep rest of packet id as it was (see specification). - this->data->header.packet_id_h = (this->data->header.packet_id_h & 0b11111000) | ( ( new_apid & 0x0700 ) >> 8 ); - this->data->header.packet_id_l = ( new_apid & 0x00FF ); -} - -uint16_t SpacePacketBase::getPacketSequenceControl( void ) { - return ( (this->data->header.sequence_control_h) << 8 ) - + this->data->header.sequence_control_l; -} - -uint8_t SpacePacketBase::getSequenceFlags( void ) { - return (this->data->header.sequence_control_h & 0b11000000) >> 6 ; -} - -uint16_t SpacePacketBase::getPacketSequenceCount( void ) const { - return ( (this->data->header.sequence_control_h & 0b00111111) << 8 ) - + this->data->header.sequence_control_l; -} - -void SpacePacketBase::setPacketSequenceCount( uint16_t new_count) { - this->data->header.sequence_control_h = ( this->data->header.sequence_control_h & 0b11000000 ) | ( ( (new_count%LIMIT_SEQUENCE_COUNT) & 0x3F00 ) >> 8 ); - this->data->header.sequence_control_l = ( (new_count%LIMIT_SEQUENCE_COUNT) & 0x00FF ); -} - -uint16_t SpacePacketBase::getPacketDataLength( void ) { - return ( (this->data->header.packet_length_h) << 8 ) - + this->data->header.packet_length_l; -} - -void SpacePacketBase::setPacketDataLength( uint16_t new_length) { - this->data->header.packet_length_h = ( ( new_length & 0xFF00 ) >> 8 ); - this->data->header.packet_length_l = ( new_length & 0x00FF ); -} - -size_t SpacePacketBase::getFullSize() { - //+1 is done because size in packet data length field is: size of data field -1 - return this->getPacketDataLength() + sizeof(this->data->header) + 1; -} - -uint8_t* SpacePacketBase::getWholeData() { - return (uint8_t*)this->data; -} - -void SpacePacketBase::setData( const uint8_t* p_Data ) { - this->data = (SpacePacketPointer*)p_Data; -} - -uint32_t SpacePacketBase::getApidAndSequenceCount() const { - return (getAPID() << 16) + getPacketSequenceCount(); -} - -uint8_t* SpacePacketBase::getPacketData() { - return &(data->packet_data); -} +#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../tmtcpacket/SpacePacketBase.h" +#include + +SpacePacketBase::SpacePacketBase( const uint8_t* set_address ) { + this->data = (SpacePacketPointer*) set_address; +} + +SpacePacketBase::~SpacePacketBase() { +}; + +//CCSDS Methods: +uint8_t SpacePacketBase::getPacketVersionNumber( void ) { + return (this->data->header.packet_id_h & 0b11100000) >> 5; +} + +void SpacePacketBase::initSpacePacketHeader(bool isTelecommand, + bool hasSecondaryHeader, uint16_t apid, uint16_t sequenceCount) { + //reset header to zero: + memset(data,0, sizeof(this->data->header) ); + //Set TC/TM bit. + data->header.packet_id_h = ((isTelecommand? 1 : 0)) << 4; + //Set secondaryHeader bit + data->header.packet_id_h |= ((hasSecondaryHeader? 1 : 0)) << 3; + this->setAPID( apid ); + //Always initialize as standalone packets. + data->header.sequence_control_h = 0b11000000; + setPacketSequenceCount(sequenceCount); + +} + +bool SpacePacketBase::isTelecommand( void ) { + return (this->data->header.packet_id_h & 0b00010000) >> 4; +} + +bool SpacePacketBase::hasSecondaryHeader( void ) { + return (this->data->header.packet_id_h & 0b00001000) >> 3; +} + +uint16_t SpacePacketBase::getPacketId() { + return ( (this->data->header.packet_id_h) << 8 ) + + this->data->header.packet_id_l; +} + +uint16_t SpacePacketBase::getAPID( void ) const { + return ( (this->data->header.packet_id_h & 0b00000111) << 8 ) + + this->data->header.packet_id_l; +} + +void SpacePacketBase::setAPID( uint16_t new_apid ) { + //Use first three bits of new APID, but keep rest of packet id as it was (see specification). + this->data->header.packet_id_h = (this->data->header.packet_id_h & 0b11111000) | ( ( new_apid & 0x0700 ) >> 8 ); + this->data->header.packet_id_l = ( new_apid & 0x00FF ); +} + +uint16_t SpacePacketBase::getPacketSequenceControl( void ) { + return ( (this->data->header.sequence_control_h) << 8 ) + + this->data->header.sequence_control_l; +} + +uint8_t SpacePacketBase::getSequenceFlags( void ) { + return (this->data->header.sequence_control_h & 0b11000000) >> 6 ; +} + +uint16_t SpacePacketBase::getPacketSequenceCount( void ) const { + return ( (this->data->header.sequence_control_h & 0b00111111) << 8 ) + + this->data->header.sequence_control_l; +} + +void SpacePacketBase::setPacketSequenceCount( uint16_t new_count) { + this->data->header.sequence_control_h = ( this->data->header.sequence_control_h & 0b11000000 ) | ( ( (new_count%LIMIT_SEQUENCE_COUNT) & 0x3F00 ) >> 8 ); + this->data->header.sequence_control_l = ( (new_count%LIMIT_SEQUENCE_COUNT) & 0x00FF ); +} + +uint16_t SpacePacketBase::getPacketDataLength( void ) { + return ( (this->data->header.packet_length_h) << 8 ) + + this->data->header.packet_length_l; +} + +void SpacePacketBase::setPacketDataLength( uint16_t new_length) { + this->data->header.packet_length_h = ( ( new_length & 0xFF00 ) >> 8 ); + this->data->header.packet_length_l = ( new_length & 0x00FF ); +} + +size_t SpacePacketBase::getFullSize() { + //+1 is done because size in packet data length field is: size of data field -1 + return this->getPacketDataLength() + sizeof(this->data->header) + 1; +} + +uint8_t* SpacePacketBase::getWholeData() { + return (uint8_t*)this->data; +} + +void SpacePacketBase::setData( const uint8_t* p_Data ) { + this->data = (SpacePacketPointer*)p_Data; +} + +uint32_t SpacePacketBase::getApidAndSequenceCount() const { + return (getAPID() << 16) + getPacketSequenceCount(); +} + +uint8_t* SpacePacketBase::getPacketData() { + return &(data->packet_data); +} diff --git a/tmtcpacket/SpacePacketBase.h b/tmtcpacket/SpacePacketBase.h index 57a5df9c..a132bfd1 100644 --- a/tmtcpacket/SpacePacketBase.h +++ b/tmtcpacket/SpacePacketBase.h @@ -1,177 +1,177 @@ -#ifndef SPACEPACKETBASE_H_ -#define SPACEPACKETBASE_H_ - -#include -#include - -/** - * @defgroup tmtcpackets Space Packets - * This is the group, where all classes associated with Telecommand and - * Telemetry packets belong to. - * The class hierarchy resembles the dependency between the different standards - * applied, namely the CCSDS Space Packet standard and the ECCSS Packet - * Utilization Standard. Most field and structure names are taken from these - * standards. - */ - -/** - * This struct defines the data structure of a Space Packet when accessed - * via a pointer. - * @ingroup tmtcpackets - */ -struct SpacePacketPointer { - CCSDSPrimaryHeader header; - uint8_t packet_data; -}; - -/** - * This class is the basic data handler for any CCSDS Space Packet - * compatible Telecommand and Telemetry packet. - * It does not contain the packet data itself but a pointer to the - * data must be set on instantiation. An invalid pointer may cause - * damage, as no getter method checks data validity. Anyway, a NULL - * check can be performed by making use of the getWholeData method. - * Remark: All bit numbers in this documentation are counted from - * the most significant bit (from left). - * @ingroup tmtcpackets - */ -class SpacePacketBase { -protected: - /** - * A pointer to a structure which defines the data structure of - * the packet header. - * To be hardware-safe, all elements are of byte size. - */ - SpacePacketPointer* data; -public: - static const uint16_t LIMIT_APID = 2048; //2^1 - static const uint16_t LIMIT_SEQUENCE_COUNT = 16384; // 2^14 - static const uint16_t APID_IDLE_PACKET = 0x7FF; - static const uint8_t TELECOMMAND_PACKET = 1; - static const uint8_t TELEMETRY_PACKET = 0; - /** - * This definition defines the CRC size in byte. - */ - static const uint8_t CRC_SIZE = 2; - /** - * This is the minimum size of a SpacePacket. - */ - static const uint16_t MINIMUM_SIZE = sizeof(CCSDSPrimaryHeader) + CRC_SIZE; - /** - * This is the default constructor. - * It sets its internal data pointer to the address passed. - * @param set_address The position where the packet data lies. - */ - SpacePacketBase( const uint8_t* set_address ); - /** - * No data is allocated, so the destructor is empty. - */ - virtual ~SpacePacketBase(); - - //CCSDS Methods: - /** - * Getter for the packet version number field. - * @return Returns the highest three bit of the packet in one byte. - */ - uint8_t getPacketVersionNumber( void ); - /** - * This method checks the type field in the header. - * This bit specifies, if the command is interpreted as Telecommand of - * as Telemetry. For a Telecommand, the bit is set. - * @return Returns true if the bit is set and false if not. - */ - bool isTelecommand( void ); - - void initSpacePacketHeader(bool isTelecommand, bool hasSecondaryHeader, uint16_t apid, uint16_t sequenceCount = 0); - /** - * The CCSDS header provides a secondary header flag (the fifth-highest bit), - * which is checked with this method. - * @return Returns true if the bit is set and false if not. - */ - bool hasSecondaryHeader( void ); - /** - * Returns the complete first two bytes of the packet, which together form - * the CCSDS packet id. - * @return The CCSDS packet id. - */ - uint16_t getPacketId( void ); - /** - * Returns the APID of a packet, which are the lowest 11 bit of the packet - * id. - * @return The CCSDS APID. - */ - uint16_t getAPID( void ) const; - /** - * Sets the APID of a packet, which are the lowest 11 bit of the packet - * id. - * @param The APID to set. The highest five bits of the parameter are - * ignored. - */ - void setAPID( uint16_t setAPID ); - /** - * Returns the CCSDS packet sequence control field, which are the third and - * the fourth byte of the CCSDS primary header. - * @return The CCSDS packet sequence control field. - */ - uint16_t getPacketSequenceControl( void ); - /** - * Returns the SequenceFlags, which are the highest two bit of the packet - * sequence control field. - * @return The CCSDS sequence flags. - */ - uint8_t getSequenceFlags( void ); - /** - * Returns the packet sequence count, which are the lowest 14 bit of the - * packet sequence control field. - * @return The CCSDS sequence count. - */ - uint16_t getPacketSequenceCount( void ) const; - /** - * Sets the packet sequence count, which are the lowest 14 bit of the - * packet sequence control field. - * setCount is modulo-divided by \c LIMIT_SEQUENCE_COUNT to avoid overflows. - * @param setCount The value to set the count to. - */ - void setPacketSequenceCount( uint16_t setCount ); - /** - * Returns the packet data length, which is the fifth and sixth byte of the - * CCSDS Primary Header. The packet data length is the size of every kind - * of data \b after the CCSDS Primary Header \b -1. - * @return The CCSDS packet data length. - */ - uint16_t getPacketDataLength( void ); //uint16_t is sufficient, because this is limit in CCSDS standard - /** - * Sets the packet data length, which is the fifth and sixth byte of the - * CCSDS Primary Header. - * @param setLength The value of the length to set. It must fit the true - * CCSDS packet data length . The packet data length is - * the size of every kind of data \b after the CCSDS - * Primary Header \b -1. - */ - void setPacketDataLength( uint16_t setLength ); - - //Helper methods: - /** - * This method returns a raw uint8_t pointer to the packet. - * @return A \c uint8_t pointer to the first byte of the CCSDS primary header. - */ - virtual uint8_t* getWholeData( void ); - - uint8_t* getPacketData(); - /** - * With this method, the packet data pointer can be redirected to another - * location. - * @param p_Data A pointer to another raw Space Packet. - */ - virtual void setData( const uint8_t* p_Data ); - /** - * This method returns the full raw packet size. - * @return The full size of the packet in bytes. - */ - size_t getFullSize(); - - uint32_t getApidAndSequenceCount() const; - -}; - -#endif /* SPACEPACKETBASE_H_ */ +#ifndef SPACEPACKETBASE_H_ +#define SPACEPACKETBASE_H_ + +#include "../tmtcpacket/ccsds_header.h" +#include + +/** + * @defgroup tmtcpackets Space Packets + * This is the group, where all classes associated with Telecommand and + * Telemetry packets belong to. + * The class hierarchy resembles the dependency between the different standards + * applied, namely the CCSDS Space Packet standard and the ECCSS Packet + * Utilization Standard. Most field and structure names are taken from these + * standards. + */ + +/** + * This struct defines the data structure of a Space Packet when accessed + * via a pointer. + * @ingroup tmtcpackets + */ +struct SpacePacketPointer { + CCSDSPrimaryHeader header; + uint8_t packet_data; +}; + +/** + * This class is the basic data handler for any CCSDS Space Packet + * compatible Telecommand and Telemetry packet. + * It does not contain the packet data itself but a pointer to the + * data must be set on instantiation. An invalid pointer may cause + * damage, as no getter method checks data validity. Anyway, a NULL + * check can be performed by making use of the getWholeData method. + * Remark: All bit numbers in this documentation are counted from + * the most significant bit (from left). + * @ingroup tmtcpackets + */ +class SpacePacketBase { +protected: + /** + * A pointer to a structure which defines the data structure of + * the packet header. + * To be hardware-safe, all elements are of byte size. + */ + SpacePacketPointer* data; +public: + static const uint16_t LIMIT_APID = 2048; //2^1 + static const uint16_t LIMIT_SEQUENCE_COUNT = 16384; // 2^14 + static const uint16_t APID_IDLE_PACKET = 0x7FF; + static const uint8_t TELECOMMAND_PACKET = 1; + static const uint8_t TELEMETRY_PACKET = 0; + /** + * This definition defines the CRC size in byte. + */ + static const uint8_t CRC_SIZE = 2; + /** + * This is the minimum size of a SpacePacket. + */ + static const uint16_t MINIMUM_SIZE = sizeof(CCSDSPrimaryHeader) + CRC_SIZE; + /** + * This is the default constructor. + * It sets its internal data pointer to the address passed. + * @param set_address The position where the packet data lies. + */ + SpacePacketBase( const uint8_t* set_address ); + /** + * No data is allocated, so the destructor is empty. + */ + virtual ~SpacePacketBase(); + + //CCSDS Methods: + /** + * Getter for the packet version number field. + * @return Returns the highest three bit of the packet in one byte. + */ + uint8_t getPacketVersionNumber( void ); + /** + * This method checks the type field in the header. + * This bit specifies, if the command is interpreted as Telecommand of + * as Telemetry. For a Telecommand, the bit is set. + * @return Returns true if the bit is set and false if not. + */ + bool isTelecommand( void ); + + void initSpacePacketHeader(bool isTelecommand, bool hasSecondaryHeader, uint16_t apid, uint16_t sequenceCount = 0); + /** + * The CCSDS header provides a secondary header flag (the fifth-highest bit), + * which is checked with this method. + * @return Returns true if the bit is set and false if not. + */ + bool hasSecondaryHeader( void ); + /** + * Returns the complete first two bytes of the packet, which together form + * the CCSDS packet id. + * @return The CCSDS packet id. + */ + uint16_t getPacketId( void ); + /** + * Returns the APID of a packet, which are the lowest 11 bit of the packet + * id. + * @return The CCSDS APID. + */ + uint16_t getAPID( void ) const; + /** + * Sets the APID of a packet, which are the lowest 11 bit of the packet + * id. + * @param The APID to set. The highest five bits of the parameter are + * ignored. + */ + void setAPID( uint16_t setAPID ); + /** + * Returns the CCSDS packet sequence control field, which are the third and + * the fourth byte of the CCSDS primary header. + * @return The CCSDS packet sequence control field. + */ + uint16_t getPacketSequenceControl( void ); + /** + * Returns the SequenceFlags, which are the highest two bit of the packet + * sequence control field. + * @return The CCSDS sequence flags. + */ + uint8_t getSequenceFlags( void ); + /** + * Returns the packet sequence count, which are the lowest 14 bit of the + * packet sequence control field. + * @return The CCSDS sequence count. + */ + uint16_t getPacketSequenceCount( void ) const; + /** + * Sets the packet sequence count, which are the lowest 14 bit of the + * packet sequence control field. + * setCount is modulo-divided by \c LIMIT_SEQUENCE_COUNT to avoid overflows. + * @param setCount The value to set the count to. + */ + void setPacketSequenceCount( uint16_t setCount ); + /** + * Returns the packet data length, which is the fifth and sixth byte of the + * CCSDS Primary Header. The packet data length is the size of every kind + * of data \b after the CCSDS Primary Header \b -1. + * @return The CCSDS packet data length. + */ + uint16_t getPacketDataLength( void ); //uint16_t is sufficient, because this is limit in CCSDS standard + /** + * Sets the packet data length, which is the fifth and sixth byte of the + * CCSDS Primary Header. + * @param setLength The value of the length to set. It must fit the true + * CCSDS packet data length . The packet data length is + * the size of every kind of data \b after the CCSDS + * Primary Header \b -1. + */ + void setPacketDataLength( uint16_t setLength ); + + //Helper methods: + /** + * This method returns a raw uint8_t pointer to the packet. + * @return A \c uint8_t pointer to the first byte of the CCSDS primary header. + */ + virtual uint8_t* getWholeData( void ); + + uint8_t* getPacketData(); + /** + * With this method, the packet data pointer can be redirected to another + * location. + * @param p_Data A pointer to another raw Space Packet. + */ + virtual void setData( const uint8_t* p_Data ); + /** + * This method returns the full raw packet size. + * @return The full size of the packet in bytes. + */ + size_t getFullSize(); + + uint32_t getApidAndSequenceCount() const; + +}; + +#endif /* SPACEPACKETBASE_H_ */ diff --git a/tmtcpacket/packetmatcher/ApidMatcher.h b/tmtcpacket/packetmatcher/ApidMatcher.h index 3080ffef..7b1b89ff 100644 --- a/tmtcpacket/packetmatcher/ApidMatcher.h +++ b/tmtcpacket/packetmatcher/ApidMatcher.h @@ -1,40 +1,40 @@ -#ifndef FRAMEWORK_TMTCPACKET_PACKETMATCHER_APIDMATCHER_H_ -#define FRAMEWORK_TMTCPACKET_PACKETMATCHER_APIDMATCHER_H_ - -#include -#include -#include - -class ApidMatcher: public SerializeableMatcherIF { -private: - uint16_t apid; -public: - ApidMatcher(uint16_t setApid) : - apid(setApid) { - } - ApidMatcher(TmPacketMinimal* test) : - apid(test->getAPID()) { - } - bool match(TmPacketMinimal* packet) { - if (packet->getAPID() == apid) { - return true; - } else { - return false; - } - } - ReturnValue_t serialize(uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) const { - return SerializeAdapter::serialize(&apid, buffer, size, maxSize, streamEndianness); - } - size_t getSerializedSize() const { - return SerializeAdapter::getSerializedSize(&apid); - } - ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - Endianness streamEndianness) { - return SerializeAdapter::deSerialize(&apid, buffer, size, streamEndianness); - } -}; - - - -#endif /* FRAMEWORK_TMTCPACKET_PACKETMATCHER_APIDMATCHER_H_ */ +#ifndef FRAMEWORK_TMTCPACKET_PACKETMATCHER_APIDMATCHER_H_ +#define FRAMEWORK_TMTCPACKET_PACKETMATCHER_APIDMATCHER_H_ + +#include "../../globalfunctions/matching/SerializeableMatcherIF.h" +#include "../../serialize/SerializeAdapter.h" +#include "../../tmtcpacket/pus/TmPacketMinimal.h" + +class ApidMatcher: public SerializeableMatcherIF { +private: + uint16_t apid; +public: + ApidMatcher(uint16_t setApid) : + apid(setApid) { + } + ApidMatcher(TmPacketMinimal* test) : + apid(test->getAPID()) { + } + bool match(TmPacketMinimal* packet) { + if (packet->getAPID() == apid) { + return true; + } else { + return false; + } + } + ReturnValue_t serialize(uint8_t** buffer, size_t* size, + size_t maxSize, Endianness streamEndianness) const { + return SerializeAdapter::serialize(&apid, buffer, size, maxSize, streamEndianness); + } + size_t getSerializedSize() const { + return SerializeAdapter::getSerializedSize(&apid); + } + ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + Endianness streamEndianness) { + return SerializeAdapter::deSerialize(&apid, buffer, size, streamEndianness); + } +}; + + + +#endif /* FRAMEWORK_TMTCPACKET_PACKETMATCHER_APIDMATCHER_H_ */ diff --git a/tmtcpacket/packetmatcher/PacketMatchTree.cpp b/tmtcpacket/packetmatcher/PacketMatchTree.cpp index d8f61ffb..356467dc 100644 --- a/tmtcpacket/packetmatcher/PacketMatchTree.cpp +++ b/tmtcpacket/packetmatcher/PacketMatchTree.cpp @@ -1,195 +1,195 @@ -#include -#include -#include -#include - -PacketMatchTree::PacketMatchTree(Node* root) : - MatchTree(root, 2), factoryBackend(0, POOL_SIZES, - N_ELEMENTS, false, true), factory(&factoryBackend) { -} - -PacketMatchTree::PacketMatchTree(iterator root) : - MatchTree(root.element, 2), factoryBackend(0, - POOL_SIZES, N_ELEMENTS, false, true), factory(&factoryBackend) { -} - -PacketMatchTree::PacketMatchTree() : - MatchTree((Node*) NULL, 2), factoryBackend(0, - POOL_SIZES, N_ELEMENTS, false, true), factory(&factoryBackend) { -} - -PacketMatchTree::~PacketMatchTree() { -} - -ReturnValue_t PacketMatchTree::addMatch(uint16_t apid, uint8_t type, - uint8_t subtype) { - //We assume adding APID is always requested. - TmPacketMinimal::TmPacketMinimalPointer data; - data.data_field.service_type = type; - data.data_field.service_subtype = subtype; - TmPacketMinimal testPacket((uint8_t*) &data); - testPacket.setAPID(apid); - iterator lastTest; - iterator rollback; - ReturnValue_t result = findOrInsertMatch( - this->begin(), &testPacket, &lastTest); - if (result == NEW_NODE_CREATED) { - rollback = lastTest; - } else if (result != RETURN_OK) { - return result; - } - if (type == 0) { - //Check if lastTest has no children, otherwise, delete them, - //as a more general check is requested. - if (lastTest.left() != this->end()) { - removeElementAndAllChildren(lastTest.left()); - } - return RETURN_OK; - } - //Type insertion required. - result = findOrInsertMatch( - lastTest.left(), &testPacket, &lastTest); - if (result == NEW_NODE_CREATED) { - if (rollback == this->end()) { - rollback = lastTest; - } - } else if (result != RETURN_OK) { - if (rollback != this->end()) { - removeElementAndAllChildren(rollback); - } - return result; - } - if (subtype == 0) { - if (lastTest.left() != this->end()) { - //See above - removeElementAndAllChildren(lastTest.left()); - } - return RETURN_OK; - } - //Subtype insertion required. - result = findOrInsertMatch( - lastTest.left(), &testPacket, &lastTest); - if (result == NEW_NODE_CREATED) { - return RETURN_OK; - } else if (result != RETURN_OK) { - if (rollback != this->end()) { - removeElementAndAllChildren(rollback); - } - return result; - } - return RETURN_OK; -} - -template -ReturnValue_t PacketMatchTree::findOrInsertMatch(iterator startAt, VALUE_T test, - iterator* lastTest) { - bool attachToBranch = AND; - iterator iter = startAt; - while (iter != this->end()) { - bool isMatch = iter->match(test); - attachToBranch = OR; - *lastTest = iter; - if (isMatch) { - return RETURN_OK; - } else { - //Go down OR branch. - iter = iter.right(); - } - } - //Only reached if nothing was found. - SerializeableMatcherIF* newContent = factory.generate( - test); - if (newContent == NULL) { - return FULL; - } - Node* newNode = factory.generate(newContent); - if (newNode == NULL) { - //Need to make sure partially generated content is deleted, otherwise, that's a leak. - factory.destroy(static_cast(newContent)); - return FULL; - } - *lastTest = insert(attachToBranch, *lastTest, newNode); - if (*lastTest == end()) { - //This actaully never fails, so creating a dedicated returncode seems an overshoot. - return RETURN_FAILED; - } - return NEW_NODE_CREATED; -} - -ReturnValue_t PacketMatchTree::removeMatch(uint16_t apid, uint8_t type, - uint8_t subtype) { - TmPacketMinimal::TmPacketMinimalPointer data; - data.data_field.service_type = type; - data.data_field.service_subtype = subtype; - TmPacketMinimal testPacket((uint8_t*) &data); - testPacket.setAPID(apid); - iterator foundElement = findMatch(begin(), &testPacket); - if (foundElement == this->end()) { - return NO_MATCH; - } - if (type == 0) { - if (foundElement.left() == end()) { - return removeElementAndReconnectChildren(foundElement); - } else { - return TOO_GENERAL_REQUEST; - } - } - //Go down AND branch. Will abort if empty. - foundElement = findMatch(foundElement.left(), &testPacket); - if (foundElement == this->end()) { - return NO_MATCH; - } - if (subtype == 0) { - if (foundElement.left() == end()) { - return removeElementAndReconnectChildren(foundElement); - } else { - return TOO_GENERAL_REQUEST; - } - } - //Again, go down AND branch. - foundElement = findMatch(foundElement.left(), &testPacket); - if (foundElement == end()) { - return NO_MATCH; - } - return removeElementAndReconnectChildren(foundElement); -} - -PacketMatchTree::iterator PacketMatchTree::findMatch(iterator startAt, - TmPacketMinimal* test) { - iterator iter = startAt; - while (iter != end()) { - bool isMatch = iter->match(test); - if (isMatch) { - break; - } else { - iter = iter.right(); //next OR element - } - } - return iter; -} - -ReturnValue_t PacketMatchTree::initialize() { - return factoryBackend.initialize(); -} - -const uint16_t PacketMatchTree::POOL_SIZES[N_POOLS] = { sizeof(ServiceMatcher), - sizeof(SubServiceMatcher), sizeof(ApidMatcher), - sizeof(PacketMatchTree::Node) }; -//Maximum number of types and subtypes to filter should be more than sufficient. -const uint16_t PacketMatchTree::N_ELEMENTS[N_POOLS] = { 10, 20, 2, 40 }; - -ReturnValue_t PacketMatchTree::changeMatch(bool addToMatch, uint16_t apid, - uint8_t type, uint8_t subtype) { - if (addToMatch) { - return addMatch(apid, type, subtype); - } else { - return removeMatch(apid, type, subtype); - } -} - -ReturnValue_t PacketMatchTree::cleanUpElement(iterator position) { - factory.destroy(position.element->value); - //Go on anyway, there's nothing we can do. - //SHOULDDO: Throw event, or write debug message? - return factory.destroy(position.element); -} +#include "../../tmtcpacket/packetmatcher/ApidMatcher.h" +#include "../../tmtcpacket/packetmatcher/PacketMatchTree.h" +#include "../../tmtcpacket/packetmatcher/ServiceMatcher.h" +#include "../../tmtcpacket/packetmatcher/SubserviceMatcher.h" + +PacketMatchTree::PacketMatchTree(Node* root) : + MatchTree(root, 2), factoryBackend(0, POOL_SIZES, + N_ELEMENTS, false, true), factory(&factoryBackend) { +} + +PacketMatchTree::PacketMatchTree(iterator root) : + MatchTree(root.element, 2), factoryBackend(0, + POOL_SIZES, N_ELEMENTS, false, true), factory(&factoryBackend) { +} + +PacketMatchTree::PacketMatchTree() : + MatchTree((Node*) NULL, 2), factoryBackend(0, + POOL_SIZES, N_ELEMENTS, false, true), factory(&factoryBackend) { +} + +PacketMatchTree::~PacketMatchTree() { +} + +ReturnValue_t PacketMatchTree::addMatch(uint16_t apid, uint8_t type, + uint8_t subtype) { + //We assume adding APID is always requested. + TmPacketMinimal::TmPacketMinimalPointer data; + data.data_field.service_type = type; + data.data_field.service_subtype = subtype; + TmPacketMinimal testPacket((uint8_t*) &data); + testPacket.setAPID(apid); + iterator lastTest; + iterator rollback; + ReturnValue_t result = findOrInsertMatch( + this->begin(), &testPacket, &lastTest); + if (result == NEW_NODE_CREATED) { + rollback = lastTest; + } else if (result != RETURN_OK) { + return result; + } + if (type == 0) { + //Check if lastTest has no children, otherwise, delete them, + //as a more general check is requested. + if (lastTest.left() != this->end()) { + removeElementAndAllChildren(lastTest.left()); + } + return RETURN_OK; + } + //Type insertion required. + result = findOrInsertMatch( + lastTest.left(), &testPacket, &lastTest); + if (result == NEW_NODE_CREATED) { + if (rollback == this->end()) { + rollback = lastTest; + } + } else if (result != RETURN_OK) { + if (rollback != this->end()) { + removeElementAndAllChildren(rollback); + } + return result; + } + if (subtype == 0) { + if (lastTest.left() != this->end()) { + //See above + removeElementAndAllChildren(lastTest.left()); + } + return RETURN_OK; + } + //Subtype insertion required. + result = findOrInsertMatch( + lastTest.left(), &testPacket, &lastTest); + if (result == NEW_NODE_CREATED) { + return RETURN_OK; + } else if (result != RETURN_OK) { + if (rollback != this->end()) { + removeElementAndAllChildren(rollback); + } + return result; + } + return RETURN_OK; +} + +template +ReturnValue_t PacketMatchTree::findOrInsertMatch(iterator startAt, VALUE_T test, + iterator* lastTest) { + bool attachToBranch = AND; + iterator iter = startAt; + while (iter != this->end()) { + bool isMatch = iter->match(test); + attachToBranch = OR; + *lastTest = iter; + if (isMatch) { + return RETURN_OK; + } else { + //Go down OR branch. + iter = iter.right(); + } + } + //Only reached if nothing was found. + SerializeableMatcherIF* newContent = factory.generate( + test); + if (newContent == NULL) { + return FULL; + } + Node* newNode = factory.generate(newContent); + if (newNode == NULL) { + //Need to make sure partially generated content is deleted, otherwise, that's a leak. + factory.destroy(static_cast(newContent)); + return FULL; + } + *lastTest = insert(attachToBranch, *lastTest, newNode); + if (*lastTest == end()) { + //This actaully never fails, so creating a dedicated returncode seems an overshoot. + return RETURN_FAILED; + } + return NEW_NODE_CREATED; +} + +ReturnValue_t PacketMatchTree::removeMatch(uint16_t apid, uint8_t type, + uint8_t subtype) { + TmPacketMinimal::TmPacketMinimalPointer data; + data.data_field.service_type = type; + data.data_field.service_subtype = subtype; + TmPacketMinimal testPacket((uint8_t*) &data); + testPacket.setAPID(apid); + iterator foundElement = findMatch(begin(), &testPacket); + if (foundElement == this->end()) { + return NO_MATCH; + } + if (type == 0) { + if (foundElement.left() == end()) { + return removeElementAndReconnectChildren(foundElement); + } else { + return TOO_GENERAL_REQUEST; + } + } + //Go down AND branch. Will abort if empty. + foundElement = findMatch(foundElement.left(), &testPacket); + if (foundElement == this->end()) { + return NO_MATCH; + } + if (subtype == 0) { + if (foundElement.left() == end()) { + return removeElementAndReconnectChildren(foundElement); + } else { + return TOO_GENERAL_REQUEST; + } + } + //Again, go down AND branch. + foundElement = findMatch(foundElement.left(), &testPacket); + if (foundElement == end()) { + return NO_MATCH; + } + return removeElementAndReconnectChildren(foundElement); +} + +PacketMatchTree::iterator PacketMatchTree::findMatch(iterator startAt, + TmPacketMinimal* test) { + iterator iter = startAt; + while (iter != end()) { + bool isMatch = iter->match(test); + if (isMatch) { + break; + } else { + iter = iter.right(); //next OR element + } + } + return iter; +} + +ReturnValue_t PacketMatchTree::initialize() { + return factoryBackend.initialize(); +} + +const uint16_t PacketMatchTree::POOL_SIZES[N_POOLS] = { sizeof(ServiceMatcher), + sizeof(SubServiceMatcher), sizeof(ApidMatcher), + sizeof(PacketMatchTree::Node) }; +//Maximum number of types and subtypes to filter should be more than sufficient. +const uint16_t PacketMatchTree::N_ELEMENTS[N_POOLS] = { 10, 20, 2, 40 }; + +ReturnValue_t PacketMatchTree::changeMatch(bool addToMatch, uint16_t apid, + uint8_t type, uint8_t subtype) { + if (addToMatch) { + return addMatch(apid, type, subtype); + } else { + return removeMatch(apid, type, subtype); + } +} + +ReturnValue_t PacketMatchTree::cleanUpElement(iterator position) { + factory.destroy(position.element->value); + //Go on anyway, there's nothing we can do. + //SHOULDDO: Throw event, or write debug message? + return factory.destroy(position.element); +} diff --git a/tmtcpacket/packetmatcher/PacketMatchTree.h b/tmtcpacket/packetmatcher/PacketMatchTree.h index a6c0c61e..0d246d21 100644 --- a/tmtcpacket/packetmatcher/PacketMatchTree.h +++ b/tmtcpacket/packetmatcher/PacketMatchTree.h @@ -1,36 +1,36 @@ -#ifndef FRAMEWORK_TMTCPACKET_PACKETMATCHER_PACKETMATCHTREE_H_ -#define FRAMEWORK_TMTCPACKET_PACKETMATCHER_PACKETMATCHTREE_H_ - -#include -#include -#include -#include - -class PacketMatchTree: public MatchTree, public HasReturnvaluesIF { -public: - PacketMatchTree(Node* root); - PacketMatchTree(iterator root); - PacketMatchTree(); - virtual ~PacketMatchTree(); - ReturnValue_t changeMatch(bool addToMatch, uint16_t apid, uint8_t type = 0, - uint8_t subtype = 0); - ReturnValue_t addMatch(uint16_t apid, uint8_t type = 0, - uint8_t subtype = 0); - ReturnValue_t removeMatch(uint16_t apid, uint8_t type = 0, - uint8_t subtype = 0); - ReturnValue_t initialize(); -protected: - ReturnValue_t cleanUpElement(iterator position); -private: - static const uint8_t N_POOLS = 4; - LocalPool factoryBackend; - PlacementFactory factory; - static const uint16_t POOL_SIZES[N_POOLS]; - static const uint16_t N_ELEMENTS[N_POOLS]; - template - ReturnValue_t findOrInsertMatch(iterator startAt, VALUE_T test, iterator* lastTest); - iterator findMatch(iterator startAt, TmPacketMinimal* test); -}; - -#endif /* FRAMEWORK_TMTCPACKET_PACKETMATCHER_PACKETMATCHTREE_H_ */ - +#ifndef FRAMEWORK_TMTCPACKET_PACKETMATCHER_PACKETMATCHTREE_H_ +#define FRAMEWORK_TMTCPACKET_PACKETMATCHER_PACKETMATCHTREE_H_ + +#include "../../container/PlacementFactory.h" +#include "../../globalfunctions/matching/MatchTree.h" +#include "../../storagemanager/LocalPool.h" +#include "../../tmtcpacket/pus/TmPacketMinimal.h" + +class PacketMatchTree: public MatchTree, public HasReturnvaluesIF { +public: + PacketMatchTree(Node* root); + PacketMatchTree(iterator root); + PacketMatchTree(); + virtual ~PacketMatchTree(); + ReturnValue_t changeMatch(bool addToMatch, uint16_t apid, uint8_t type = 0, + uint8_t subtype = 0); + ReturnValue_t addMatch(uint16_t apid, uint8_t type = 0, + uint8_t subtype = 0); + ReturnValue_t removeMatch(uint16_t apid, uint8_t type = 0, + uint8_t subtype = 0); + ReturnValue_t initialize(); +protected: + ReturnValue_t cleanUpElement(iterator position); +private: + static const uint8_t N_POOLS = 4; + LocalPool factoryBackend; + PlacementFactory factory; + static const uint16_t POOL_SIZES[N_POOLS]; + static const uint16_t N_ELEMENTS[N_POOLS]; + template + ReturnValue_t findOrInsertMatch(iterator startAt, VALUE_T test, iterator* lastTest); + iterator findMatch(iterator startAt, TmPacketMinimal* test); +}; + +#endif /* FRAMEWORK_TMTCPACKET_PACKETMATCHER_PACKETMATCHTREE_H_ */ + diff --git a/tmtcpacket/packetmatcher/ServiceMatcher.h b/tmtcpacket/packetmatcher/ServiceMatcher.h index f6e9e360..e22288f4 100644 --- a/tmtcpacket/packetmatcher/ServiceMatcher.h +++ b/tmtcpacket/packetmatcher/ServiceMatcher.h @@ -1,39 +1,39 @@ -#ifndef FRAMEWORK_TMTCPACKET_PACKETMATCHER_SERVICEMATCHER_H_ -#define FRAMEWORK_TMTCPACKET_PACKETMATCHER_SERVICEMATCHER_H_ - -#include -#include -#include - -class ServiceMatcher: public SerializeableMatcherIF { -private: - uint8_t service; -public: - ServiceMatcher(uint8_t setService) : - service(setService) { - } - ServiceMatcher(TmPacketMinimal* test) : - service(test->getService()) { - } - bool match(TmPacketMinimal* packet) { - if (packet->getService() == service) { - return true; - } else { - return false; - } - } - ReturnValue_t serialize(uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) const { - return SerializeAdapter::serialize(&service, buffer, size, maxSize, streamEndianness); - } - size_t getSerializedSize() const { - return SerializeAdapter::getSerializedSize(&service); - } - ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - Endianness streamEndianness) { - return SerializeAdapter::deSerialize(&service, buffer, size, streamEndianness); - } -}; - - -#endif /* FRAMEWORK_TMTCPACKET_PACKETMATCHER_SERVICEMATCHER_H_ */ +#ifndef FRAMEWORK_TMTCPACKET_PACKETMATCHER_SERVICEMATCHER_H_ +#define FRAMEWORK_TMTCPACKET_PACKETMATCHER_SERVICEMATCHER_H_ + +#include "../../globalfunctions/matching/SerializeableMatcherIF.h" +#include "../../serialize/SerializeAdapter.h" +#include "../../tmtcpacket/pus/TmPacketMinimal.h" + +class ServiceMatcher: public SerializeableMatcherIF { +private: + uint8_t service; +public: + ServiceMatcher(uint8_t setService) : + service(setService) { + } + ServiceMatcher(TmPacketMinimal* test) : + service(test->getService()) { + } + bool match(TmPacketMinimal* packet) { + if (packet->getService() == service) { + return true; + } else { + return false; + } + } + ReturnValue_t serialize(uint8_t** buffer, size_t* size, + size_t maxSize, Endianness streamEndianness) const { + return SerializeAdapter::serialize(&service, buffer, size, maxSize, streamEndianness); + } + size_t getSerializedSize() const { + return SerializeAdapter::getSerializedSize(&service); + } + ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + Endianness streamEndianness) { + return SerializeAdapter::deSerialize(&service, buffer, size, streamEndianness); + } +}; + + +#endif /* FRAMEWORK_TMTCPACKET_PACKETMATCHER_SERVICEMATCHER_H_ */ diff --git a/tmtcpacket/packetmatcher/SubserviceMatcher.h b/tmtcpacket/packetmatcher/SubserviceMatcher.h index 2e8b82b2..1b173b1a 100644 --- a/tmtcpacket/packetmatcher/SubserviceMatcher.h +++ b/tmtcpacket/packetmatcher/SubserviceMatcher.h @@ -1,40 +1,40 @@ -#ifndef FRAMEWORK_TMTCPACKET_PACKETMATCHER_SUBSERVICEMATCHER_H_ -#define FRAMEWORK_TMTCPACKET_PACKETMATCHER_SUBSERVICEMATCHER_H_ - -#include -#include -#include - -class SubServiceMatcher: public SerializeableMatcherIF { -public: - SubServiceMatcher(uint8_t subService) : - subService(subService) { - } - SubServiceMatcher(TmPacketMinimal* test) : - subService(test->getSubService()) { - } - bool match(TmPacketMinimal* packet) { - if (packet->getSubService() == subService) { - return true; - } else { - return false; - } - } - ReturnValue_t serialize(uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) const { - return SerializeAdapter::serialize(&subService, buffer, size, maxSize, streamEndianness); - } - size_t getSerializedSize() const { - return SerializeAdapter::getSerializedSize(&subService); - } - ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - Endianness streamEndianness) { - return SerializeAdapter::deSerialize(&subService, buffer, size, streamEndianness); - } -private: - uint8_t subService; -}; - - - -#endif /* FRAMEWORK_TMTCPACKET_PACKETMATCHER_SUBSERVICEMATCHER_H_ */ +#ifndef FRAMEWORK_TMTCPACKET_PACKETMATCHER_SUBSERVICEMATCHER_H_ +#define FRAMEWORK_TMTCPACKET_PACKETMATCHER_SUBSERVICEMATCHER_H_ + +#include "../../globalfunctions/matching/SerializeableMatcherIF.h" +#include "../../serialize/SerializeAdapter.h" +#include "../../tmtcpacket/pus/TmPacketMinimal.h" + +class SubServiceMatcher: public SerializeableMatcherIF { +public: + SubServiceMatcher(uint8_t subService) : + subService(subService) { + } + SubServiceMatcher(TmPacketMinimal* test) : + subService(test->getSubService()) { + } + bool match(TmPacketMinimal* packet) { + if (packet->getSubService() == subService) { + return true; + } else { + return false; + } + } + ReturnValue_t serialize(uint8_t** buffer, size_t* size, + size_t maxSize, Endianness streamEndianness) const { + return SerializeAdapter::serialize(&subService, buffer, size, maxSize, streamEndianness); + } + size_t getSerializedSize() const { + return SerializeAdapter::getSerializedSize(&subService); + } + ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + Endianness streamEndianness) { + return SerializeAdapter::deSerialize(&subService, buffer, size, streamEndianness); + } +private: + uint8_t subService; +}; + + + +#endif /* FRAMEWORK_TMTCPACKET_PACKETMATCHER_SUBSERVICEMATCHER_H_ */ diff --git a/tmtcpacket/pus/PacketTimestampInterpreterIF.h b/tmtcpacket/pus/PacketTimestampInterpreterIF.h index 6e19381a..9e442ed6 100644 --- a/tmtcpacket/pus/PacketTimestampInterpreterIF.h +++ b/tmtcpacket/pus/PacketTimestampInterpreterIF.h @@ -1,16 +1,16 @@ -#ifndef FRAMEWORK_TMTCPACKET_PUS_PACKETTIMESTAMPINTERPRETERIF_H_ -#define FRAMEWORK_TMTCPACKET_PUS_PACKETTIMESTAMPINTERPRETERIF_H_ - -#include -class TmPacketMinimal; - -class PacketTimestampInterpreterIF { -public: - virtual ~PacketTimestampInterpreterIF() {} - virtual ReturnValue_t getPacketTime(TmPacketMinimal* packet, timeval* timestamp) const = 0; - virtual ReturnValue_t getPacketTimeRaw(TmPacketMinimal* packet, const uint8_t** timePtr, uint32_t* size) const = 0; -}; - - - -#endif /* FRAMEWORK_TMTCPACKET_PUS_PACKETTIMESTAMPINTERPRETERIF_H_ */ +#ifndef FRAMEWORK_TMTCPACKET_PUS_PACKETTIMESTAMPINTERPRETERIF_H_ +#define FRAMEWORK_TMTCPACKET_PUS_PACKETTIMESTAMPINTERPRETERIF_H_ + +#include "../../returnvalues/HasReturnvaluesIF.h" +class TmPacketMinimal; + +class PacketTimestampInterpreterIF { +public: + virtual ~PacketTimestampInterpreterIF() {} + virtual ReturnValue_t getPacketTime(TmPacketMinimal* packet, timeval* timestamp) const = 0; + virtual ReturnValue_t getPacketTimeRaw(TmPacketMinimal* packet, const uint8_t** timePtr, uint32_t* size) const = 0; +}; + + + +#endif /* FRAMEWORK_TMTCPACKET_PUS_PACKETTIMESTAMPINTERPRETERIF_H_ */ diff --git a/tmtcpacket/pus/TcPacketBase.cpp b/tmtcpacket/pus/TcPacketBase.cpp index 733c36df..3dc15872 100644 --- a/tmtcpacket/pus/TcPacketBase.cpp +++ b/tmtcpacket/pus/TcPacketBase.cpp @@ -1,93 +1,93 @@ -#include -#include -#include -#include - -TcPacketBase::TcPacketBase(const uint8_t* set_data) : - SpacePacketBase(set_data) { - tcData = (TcPacketPointer*) set_data; -} - -TcPacketBase::~TcPacketBase() { - //Nothing to do. -} - -uint8_t TcPacketBase::getService() { - return tcData->dataField.service_type; -} - -uint8_t TcPacketBase::getSubService() { - return tcData->dataField.service_subtype; -} - -uint8_t TcPacketBase::getAcknowledgeFlags() { - return tcData->dataField.version_type_ack & 0b00001111; -} - -const uint8_t* TcPacketBase::getApplicationData() const { - return &tcData->appData; -} - -uint16_t TcPacketBase::getApplicationDataSize() { - return getPacketDataLength() - sizeof(tcData->dataField) - CRC_SIZE + 1; -} - -uint16_t TcPacketBase::getErrorControl() { - uint16_t size = getApplicationDataSize() + CRC_SIZE; - uint8_t* p_to_buffer = &tcData->appData; - return (p_to_buffer[size - 2] << 8) + p_to_buffer[size - 1]; -} - -void TcPacketBase::setErrorControl() { - uint32_t full_size = getFullSize(); - uint16_t crc = CRC::crc16ccitt(getWholeData(), full_size - CRC_SIZE); - uint32_t size = getApplicationDataSize(); - (&tcData->appData)[size] = (crc & 0XFF00) >> 8; // CRCH - (&tcData->appData)[size + 1] = (crc) & 0X00FF; // CRCL -} - -void TcPacketBase::setData(const uint8_t* pData) { - SpacePacketBase::setData(pData); - tcData = (TcPacketPointer*) pData; -} - -void TcPacketBase::setAppData(uint8_t * appData, uint16_t dataLen) { - memcpy(&tcData->appData, appData, dataLen); - SpacePacketBase::setPacketDataLength(dataLen + - sizeof(PUSTcDataFieldHeader) + TcPacketBase::CRC_SIZE - 1); -} - -uint8_t TcPacketBase::getSecondaryHeaderFlag() { - return (tcData->dataField.version_type_ack & 0b10000000) >> 7; -} - -uint8_t TcPacketBase::getPusVersionNumber() { - return (tcData->dataField.version_type_ack & 0b01110000) >> 4; -} - -void TcPacketBase::print() { - uint8_t * wholeData = getWholeData(); - sif::debug << "TcPacket contains: " << std::endl; - for (uint8_t count = 0; count < getFullSize(); ++count) { - sif::debug << std::hex << (uint16_t) wholeData[count] << " "; - } - sif::debug << std::dec << std::endl; -} - -void TcPacketBase::initializeTcPacket(uint16_t apid, uint16_t sequenceCount, - uint8_t ack, uint8_t service, uint8_t subservice) { - initSpacePacketHeader(true, true, apid, sequenceCount); - memset(&tcData->dataField, 0, sizeof(tcData->dataField)); - setPacketDataLength(sizeof(PUSTcDataFieldHeader) + CRC_SIZE - 1); - //Data Field Header: - //Set CCSDS_secondary_header_flag to 0, version number to 001 and ack to 0000 - tcData->dataField.version_type_ack = 0b00010000; - tcData->dataField.version_type_ack |= (ack & 0x0F); - tcData->dataField.service_type = service; - tcData->dataField.service_subtype = subservice; -} - -size_t TcPacketBase::calculateFullPacketLength(size_t appDataLen) { - return sizeof(CCSDSPrimaryHeader) + sizeof(PUSTcDataFieldHeader) + - appDataLen + TcPacketBase::CRC_SIZE; -} +#include "../../globalfunctions/CRC.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "../../tmtcpacket/pus/TcPacketBase.h" +#include + +TcPacketBase::TcPacketBase(const uint8_t* set_data) : + SpacePacketBase(set_data) { + tcData = (TcPacketPointer*) set_data; +} + +TcPacketBase::~TcPacketBase() { + //Nothing to do. +} + +uint8_t TcPacketBase::getService() { + return tcData->dataField.service_type; +} + +uint8_t TcPacketBase::getSubService() { + return tcData->dataField.service_subtype; +} + +uint8_t TcPacketBase::getAcknowledgeFlags() { + return tcData->dataField.version_type_ack & 0b00001111; +} + +const uint8_t* TcPacketBase::getApplicationData() const { + return &tcData->appData; +} + +uint16_t TcPacketBase::getApplicationDataSize() { + return getPacketDataLength() - sizeof(tcData->dataField) - CRC_SIZE + 1; +} + +uint16_t TcPacketBase::getErrorControl() { + uint16_t size = getApplicationDataSize() + CRC_SIZE; + uint8_t* p_to_buffer = &tcData->appData; + return (p_to_buffer[size - 2] << 8) + p_to_buffer[size - 1]; +} + +void TcPacketBase::setErrorControl() { + uint32_t full_size = getFullSize(); + uint16_t crc = CRC::crc16ccitt(getWholeData(), full_size - CRC_SIZE); + uint32_t size = getApplicationDataSize(); + (&tcData->appData)[size] = (crc & 0XFF00) >> 8; // CRCH + (&tcData->appData)[size + 1] = (crc) & 0X00FF; // CRCL +} + +void TcPacketBase::setData(const uint8_t* pData) { + SpacePacketBase::setData(pData); + tcData = (TcPacketPointer*) pData; +} + +void TcPacketBase::setAppData(uint8_t * appData, uint16_t dataLen) { + memcpy(&tcData->appData, appData, dataLen); + SpacePacketBase::setPacketDataLength(dataLen + + sizeof(PUSTcDataFieldHeader) + TcPacketBase::CRC_SIZE - 1); +} + +uint8_t TcPacketBase::getSecondaryHeaderFlag() { + return (tcData->dataField.version_type_ack & 0b10000000) >> 7; +} + +uint8_t TcPacketBase::getPusVersionNumber() { + return (tcData->dataField.version_type_ack & 0b01110000) >> 4; +} + +void TcPacketBase::print() { + uint8_t * wholeData = getWholeData(); + sif::debug << "TcPacket contains: " << std::endl; + for (uint8_t count = 0; count < getFullSize(); ++count) { + sif::debug << std::hex << (uint16_t) wholeData[count] << " "; + } + sif::debug << std::dec << std::endl; +} + +void TcPacketBase::initializeTcPacket(uint16_t apid, uint16_t sequenceCount, + uint8_t ack, uint8_t service, uint8_t subservice) { + initSpacePacketHeader(true, true, apid, sequenceCount); + memset(&tcData->dataField, 0, sizeof(tcData->dataField)); + setPacketDataLength(sizeof(PUSTcDataFieldHeader) + CRC_SIZE - 1); + //Data Field Header: + //Set CCSDS_secondary_header_flag to 0, version number to 001 and ack to 0000 + tcData->dataField.version_type_ack = 0b00010000; + tcData->dataField.version_type_ack |= (ack & 0x0F); + tcData->dataField.service_type = service; + tcData->dataField.service_subtype = subservice; +} + +size_t TcPacketBase::calculateFullPacketLength(size_t appDataLen) { + return sizeof(CCSDSPrimaryHeader) + sizeof(PUSTcDataFieldHeader) + + appDataLen + TcPacketBase::CRC_SIZE; +} diff --git a/tmtcpacket/pus/TcPacketBase.h b/tmtcpacket/pus/TcPacketBase.h index 73076176..1cfe233b 100644 --- a/tmtcpacket/pus/TcPacketBase.h +++ b/tmtcpacket/pus/TcPacketBase.h @@ -1,204 +1,204 @@ -#ifndef TCPACKETBASE_H_ -#define TCPACKETBASE_H_ - -#include -#include - -/** - * This struct defines a byte-wise structured PUS TC Data Field Header. - * Any optional fields in the header must be added or removed here. - * Currently, the Source Id field is present with one byte. - * @ingroup tmtcpackets - */ -struct PUSTcDataFieldHeader { - uint8_t version_type_ack; - uint8_t service_type; - uint8_t service_subtype; - uint8_t source_id; -}; - -/** - * This struct defines the data structure of a PUS Telecommand Packet when - * accessed via a pointer. - * @ingroup tmtcpackets - */ -struct TcPacketPointer { - CCSDSPrimaryHeader primary; - PUSTcDataFieldHeader dataField; - uint8_t appData; -}; - -/** - * This class is the basic data handler for any ECSS PUS Telecommand packet. - * - * In addition to \SpacePacketBase, the class provides methods to handle - * the standardized entries of the PUS TC Packet Data Field Header. - * It does not contain the packet data itself but a pointer to the - * data must be set on instantiation. An invalid pointer may cause - * damage, as no getter method checks data validity. Anyway, a NULL - * check can be performed by making use of the getWholeData method. - * @ingroup tmtcpackets - */ -class TcPacketBase : public SpacePacketBase { -protected: - /** - * A pointer to a structure which defines the data structure of - * the packet's data. - * - * To be hardware-safe, all elements are of byte size. - */ - TcPacketPointer* tcData; -public: - static const uint16_t TC_PACKET_MIN_SIZE = (sizeof(CCSDSPrimaryHeader) + sizeof(PUSTcDataFieldHeader) + 2); - /** - * With this constant for the acknowledge field responses on all levels are expected. - */ - static const uint8_t ACK_ALL = 0b1111; - /** - * With this constant for the acknowledge field a response on acceptance is expected. - */ - static const uint8_t ACK_ACCEPTANCE = 0b0001; - /** - * With this constant for the acknowledge field a response on start of execution is expected. - */ - static const uint8_t ACK_START = 0b0010; - /** - * With this constant for the acknowledge field responses on execution steps are expected. - */ - static const uint8_t ACK_STEP = 0b0100; - /** - * With this constant for the acknowledge field a response on completion is expected. - */ - static const uint8_t ACK_COMPLETION = 0b1000; - /** - * With this constant for the acknowledge field no responses are expected. - */ - static const uint8_t ACK_NONE = 0b000; - /** - * This is the default constructor. - * It sets its internal data pointer to the address passed and also - * forwards the data pointer to the parent SpacePacketBase class. - * @param set_address The position where the packet data lies. - */ - TcPacketBase( const uint8_t* set_data ); - /** - * This is the empty default destructor. - */ - virtual ~TcPacketBase(); - /** - * Initializes the Tc Packet header. - * @param apid APID used. - * @param service PUS Service - * @param subservice PUS Subservice - * @param packetSubcounter Additional subcounter used. - */ - /** - * Initializes the Tc Packet header. - * @param apid APID used. - * @param sequenceCount Sequence Count in the primary header. - * @param ack Which acknowledeges are expected from the receiver. - * @param service PUS Service - * @param subservice PUS Subservice - */ - void initializeTcPacket(uint16_t apid, uint16_t sequenceCount, uint8_t ack, - uint8_t service, uint8_t subservice); - /** - * This command returns the CCSDS Secondary Header Flag. - * It shall always be zero for PUS Packets. This is the - * highest bit of the first byte of the Data Field Header. - * @return the CCSDS Secondary Header Flag - */ - uint8_t getSecondaryHeaderFlag(); - /** - * This command returns the TC Packet PUS Version Number. - * The version number of ECSS PUS 2003 is 1. - * It consists of the second to fourth highest bits of the - * first byte. - * @return - */ - uint8_t getPusVersionNumber(); - /** - * This is a getter for the packet's Ack field, which are the lowest four - * bits of the first byte of the Data Field Header. - * - * It is packed in a uint8_t variable. - * @return The packet's PUS Ack field. - */ - uint8_t getAcknowledgeFlags(); - /** - * This is a getter for the packet's PUS Service ID, which is the second - * byte of the Data Field Header. - * @return The packet's PUS Service ID. - */ - uint8_t getService(); - /** - * This is a getter for the packet's PUS Service Subtype, which is the - * third byte of the Data Field Header. - * @return The packet's PUS Service Subtype. - */ - uint8_t getSubService(); - /** - * This is a getter for a pointer to the packet's Application data. - * - * These are the bytes that follow after the Data Field Header. They form - * the packet's application data. - * @return A pointer to the PUS Application Data. - */ - const uint8_t* getApplicationData() const; - /** - * This method calculates the size of the PUS Application data field. - * - * It takes the information stored in the CCSDS Packet Data Length field - * and subtracts the Data Field Header size and the CRC size. - * @return The size of the PUS Application Data (without Error Control - * field) - */ - uint16_t getApplicationDataSize(); - /** - * This getter returns the Error Control Field of the packet. - * - * The field is placed after any possible Application Data. If no - * Application Data is present there's still an Error Control field. It is - * supposed to be a 16bit-CRC. - * @return The PUS Error Control - */ - uint16_t getErrorControl(); - /** - * With this method, the Error Control Field is updated to match the - * current content of the packet. - */ - void setErrorControl(); - - /** - * Copies the supplied data to the internal TC application data field. - * @param pData - * @param dataLen - */ - void setAppData(uint8_t * appData, uint16_t dataLen); - - /** - * With this method, the packet data pointer can be redirected to another - * location. - * - * This call overwrites the parent's setData method to set both its - * \c tc_data pointer and the parent's \c data pointer. - * - * @param p_data A pointer to another PUS Telecommand Packet. - */ - void setData( const uint8_t* pData ); - - /** - * This is a debugging helper method that prints the whole packet content - * to the screen. - */ - void print(); - /** - * Calculate full packet length from application data length. - * @param appDataLen - * @return - */ - static size_t calculateFullPacketLength(size_t appDataLen); -}; - - -#endif /* TCPACKETBASE_H_ */ +#ifndef TCPACKETBASE_H_ +#define TCPACKETBASE_H_ + +#include "../../tmtcpacket/SpacePacketBase.h" +#include + +/** + * This struct defines a byte-wise structured PUS TC Data Field Header. + * Any optional fields in the header must be added or removed here. + * Currently, the Source Id field is present with one byte. + * @ingroup tmtcpackets + */ +struct PUSTcDataFieldHeader { + uint8_t version_type_ack; + uint8_t service_type; + uint8_t service_subtype; + uint8_t source_id; +}; + +/** + * This struct defines the data structure of a PUS Telecommand Packet when + * accessed via a pointer. + * @ingroup tmtcpackets + */ +struct TcPacketPointer { + CCSDSPrimaryHeader primary; + PUSTcDataFieldHeader dataField; + uint8_t appData; +}; + +/** + * This class is the basic data handler for any ECSS PUS Telecommand packet. + * + * In addition to \SpacePacketBase, the class provides methods to handle + * the standardized entries of the PUS TC Packet Data Field Header. + * It does not contain the packet data itself but a pointer to the + * data must be set on instantiation. An invalid pointer may cause + * damage, as no getter method checks data validity. Anyway, a NULL + * check can be performed by making use of the getWholeData method. + * @ingroup tmtcpackets + */ +class TcPacketBase : public SpacePacketBase { +protected: + /** + * A pointer to a structure which defines the data structure of + * the packet's data. + * + * To be hardware-safe, all elements are of byte size. + */ + TcPacketPointer* tcData; +public: + static const uint16_t TC_PACKET_MIN_SIZE = (sizeof(CCSDSPrimaryHeader) + sizeof(PUSTcDataFieldHeader) + 2); + /** + * With this constant for the acknowledge field responses on all levels are expected. + */ + static const uint8_t ACK_ALL = 0b1111; + /** + * With this constant for the acknowledge field a response on acceptance is expected. + */ + static const uint8_t ACK_ACCEPTANCE = 0b0001; + /** + * With this constant for the acknowledge field a response on start of execution is expected. + */ + static const uint8_t ACK_START = 0b0010; + /** + * With this constant for the acknowledge field responses on execution steps are expected. + */ + static const uint8_t ACK_STEP = 0b0100; + /** + * With this constant for the acknowledge field a response on completion is expected. + */ + static const uint8_t ACK_COMPLETION = 0b1000; + /** + * With this constant for the acknowledge field no responses are expected. + */ + static const uint8_t ACK_NONE = 0b000; + /** + * This is the default constructor. + * It sets its internal data pointer to the address passed and also + * forwards the data pointer to the parent SpacePacketBase class. + * @param set_address The position where the packet data lies. + */ + TcPacketBase( const uint8_t* set_data ); + /** + * This is the empty default destructor. + */ + virtual ~TcPacketBase(); + /** + * Initializes the Tc Packet header. + * @param apid APID used. + * @param service PUS Service + * @param subservice PUS Subservice + * @param packetSubcounter Additional subcounter used. + */ + /** + * Initializes the Tc Packet header. + * @param apid APID used. + * @param sequenceCount Sequence Count in the primary header. + * @param ack Which acknowledeges are expected from the receiver. + * @param service PUS Service + * @param subservice PUS Subservice + */ + void initializeTcPacket(uint16_t apid, uint16_t sequenceCount, uint8_t ack, + uint8_t service, uint8_t subservice); + /** + * This command returns the CCSDS Secondary Header Flag. + * It shall always be zero for PUS Packets. This is the + * highest bit of the first byte of the Data Field Header. + * @return the CCSDS Secondary Header Flag + */ + uint8_t getSecondaryHeaderFlag(); + /** + * This command returns the TC Packet PUS Version Number. + * The version number of ECSS PUS 2003 is 1. + * It consists of the second to fourth highest bits of the + * first byte. + * @return + */ + uint8_t getPusVersionNumber(); + /** + * This is a getter for the packet's Ack field, which are the lowest four + * bits of the first byte of the Data Field Header. + * + * It is packed in a uint8_t variable. + * @return The packet's PUS Ack field. + */ + uint8_t getAcknowledgeFlags(); + /** + * This is a getter for the packet's PUS Service ID, which is the second + * byte of the Data Field Header. + * @return The packet's PUS Service ID. + */ + uint8_t getService(); + /** + * This is a getter for the packet's PUS Service Subtype, which is the + * third byte of the Data Field Header. + * @return The packet's PUS Service Subtype. + */ + uint8_t getSubService(); + /** + * This is a getter for a pointer to the packet's Application data. + * + * These are the bytes that follow after the Data Field Header. They form + * the packet's application data. + * @return A pointer to the PUS Application Data. + */ + const uint8_t* getApplicationData() const; + /** + * This method calculates the size of the PUS Application data field. + * + * It takes the information stored in the CCSDS Packet Data Length field + * and subtracts the Data Field Header size and the CRC size. + * @return The size of the PUS Application Data (without Error Control + * field) + */ + uint16_t getApplicationDataSize(); + /** + * This getter returns the Error Control Field of the packet. + * + * The field is placed after any possible Application Data. If no + * Application Data is present there's still an Error Control field. It is + * supposed to be a 16bit-CRC. + * @return The PUS Error Control + */ + uint16_t getErrorControl(); + /** + * With this method, the Error Control Field is updated to match the + * current content of the packet. + */ + void setErrorControl(); + + /** + * Copies the supplied data to the internal TC application data field. + * @param pData + * @param dataLen + */ + void setAppData(uint8_t * appData, uint16_t dataLen); + + /** + * With this method, the packet data pointer can be redirected to another + * location. + * + * This call overwrites the parent's setData method to set both its + * \c tc_data pointer and the parent's \c data pointer. + * + * @param p_data A pointer to another PUS Telecommand Packet. + */ + void setData( const uint8_t* pData ); + + /** + * This is a debugging helper method that prints the whole packet content + * to the screen. + */ + void print(); + /** + * Calculate full packet length from application data length. + * @param appDataLen + * @return + */ + static size_t calculateFullPacketLength(size_t appDataLen); +}; + + +#endif /* TCPACKETBASE_H_ */ diff --git a/tmtcpacket/pus/TcPacketStored.cpp b/tmtcpacket/pus/TcPacketStored.cpp index 64aa74dc..3f10cac0 100644 --- a/tmtcpacket/pus/TcPacketStored.cpp +++ b/tmtcpacket/pus/TcPacketStored.cpp @@ -1,118 +1,118 @@ -#include -#include -#include - -#include - -TcPacketStored::TcPacketStored(store_address_t setAddress) : - TcPacketBase(nullptr), storeAddress(setAddress) { - this->setStoreAddress(this->storeAddress); -} - -TcPacketStored::TcPacketStored(uint8_t service, uint8_t subservice, - uint16_t apid, uint8_t sequence_count, const uint8_t* data, - size_t size, uint8_t ack ) : - TcPacketBase(nullptr) { - this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; - if (!this->checkAndSetStore()) { - return; - } - uint8_t* p_data = nullptr; - ReturnValue_t returnValue = this->store->getFreeElement(&this->storeAddress, - (TC_PACKET_MIN_SIZE + size), &p_data); - if (returnValue != this->store->RETURN_OK) { - sif::warning << "TcPacketStored: Could not get free element from store!" - << std::endl; - return; - } - this->setData(p_data); - initializeTcPacket(apid, sequence_count, ack, service, subservice); - memcpy(&tcData->appData, data, size); - this->setPacketDataLength( - size + sizeof(PUSTcDataFieldHeader) + CRC_SIZE - 1); - this->setErrorControl(); -} - -ReturnValue_t TcPacketStored::getData(const uint8_t ** dataPtr, - size_t* dataSize) { - auto result = this->store->getData(storeAddress, dataPtr, dataSize); - if(result != HasReturnvaluesIF::RETURN_OK) { - sif::warning << "TcPacketStored: Could not get data!" << std::endl; - } - return result; -} - -TcPacketStored::TcPacketStored() : - TcPacketBase(NULL) { - this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; - this->checkAndSetStore(); - -} - -ReturnValue_t TcPacketStored::deletePacket() { - ReturnValue_t result = this->store->deleteData(this->storeAddress); - this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; - this->setData( NULL); - return result; -} - -bool TcPacketStored::checkAndSetStore() { - if (this->store == NULL) { - this->store = objectManager->get(objects::TC_STORE); - if (this->store == NULL) { - sif::error << "TcPacketStored::TcPacketStored: TC Store not found!" - << std::endl; - return false; - } - } - return true; -} - -void TcPacketStored::setStoreAddress(store_address_t setAddress) { - this->storeAddress = setAddress; - const uint8_t* temp_data = NULL; - size_t temp_size; - ReturnValue_t status = StorageManagerIF::RETURN_FAILED; - if (this->checkAndSetStore()) { - status = this->store->getData(this->storeAddress, &temp_data, - &temp_size); - } - if (status == StorageManagerIF::RETURN_OK) { - this->setData(temp_data); - } else { - this->setData(NULL); - this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; - } -} - -store_address_t TcPacketStored::getStoreAddress() { - return this->storeAddress; -} - -bool TcPacketStored::isSizeCorrect() { - const uint8_t* temp_data = NULL; - size_t temp_size; - ReturnValue_t status = this->store->getData(this->storeAddress, &temp_data, - &temp_size); - if (status == StorageManagerIF::RETURN_OK) { - if (this->getFullSize() == temp_size) { - return true; - } - } - return false; -} - -StorageManagerIF* TcPacketStored::store = NULL; - -TcPacketStored::TcPacketStored(const uint8_t* data, uint32_t size) : - TcPacketBase(data) { - if (getFullSize() != size) { - return; - } - if (this->checkAndSetStore()) { - ReturnValue_t status = store->addData(&storeAddress, data, size); - if (status != HasReturnvaluesIF::RETURN_OK) { - this->setData(NULL); - } - } -} +#include "../../objectmanager/ObjectManagerIF.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "../../tmtcpacket/pus/TcPacketStored.h" + +#include + +TcPacketStored::TcPacketStored(store_address_t setAddress) : + TcPacketBase(nullptr), storeAddress(setAddress) { + this->setStoreAddress(this->storeAddress); +} + +TcPacketStored::TcPacketStored(uint8_t service, uint8_t subservice, + uint16_t apid, uint8_t sequence_count, const uint8_t* data, + size_t size, uint8_t ack ) : + TcPacketBase(nullptr) { + this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; + if (!this->checkAndSetStore()) { + return; + } + uint8_t* p_data = nullptr; + ReturnValue_t returnValue = this->store->getFreeElement(&this->storeAddress, + (TC_PACKET_MIN_SIZE + size), &p_data); + if (returnValue != this->store->RETURN_OK) { + sif::warning << "TcPacketStored: Could not get free element from store!" + << std::endl; + return; + } + this->setData(p_data); + initializeTcPacket(apid, sequence_count, ack, service, subservice); + memcpy(&tcData->appData, data, size); + this->setPacketDataLength( + size + sizeof(PUSTcDataFieldHeader) + CRC_SIZE - 1); + this->setErrorControl(); +} + +ReturnValue_t TcPacketStored::getData(const uint8_t ** dataPtr, + size_t* dataSize) { + auto result = this->store->getData(storeAddress, dataPtr, dataSize); + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::warning << "TcPacketStored: Could not get data!" << std::endl; + } + return result; +} + +TcPacketStored::TcPacketStored() : + TcPacketBase(NULL) { + this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; + this->checkAndSetStore(); + +} + +ReturnValue_t TcPacketStored::deletePacket() { + ReturnValue_t result = this->store->deleteData(this->storeAddress); + this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; + this->setData( NULL); + return result; +} + +bool TcPacketStored::checkAndSetStore() { + if (this->store == NULL) { + this->store = objectManager->get(objects::TC_STORE); + if (this->store == NULL) { + sif::error << "TcPacketStored::TcPacketStored: TC Store not found!" + << std::endl; + return false; + } + } + return true; +} + +void TcPacketStored::setStoreAddress(store_address_t setAddress) { + this->storeAddress = setAddress; + const uint8_t* temp_data = NULL; + size_t temp_size; + ReturnValue_t status = StorageManagerIF::RETURN_FAILED; + if (this->checkAndSetStore()) { + status = this->store->getData(this->storeAddress, &temp_data, + &temp_size); + } + if (status == StorageManagerIF::RETURN_OK) { + this->setData(temp_data); + } else { + this->setData(NULL); + this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; + } +} + +store_address_t TcPacketStored::getStoreAddress() { + return this->storeAddress; +} + +bool TcPacketStored::isSizeCorrect() { + const uint8_t* temp_data = NULL; + size_t temp_size; + ReturnValue_t status = this->store->getData(this->storeAddress, &temp_data, + &temp_size); + if (status == StorageManagerIF::RETURN_OK) { + if (this->getFullSize() == temp_size) { + return true; + } + } + return false; +} + +StorageManagerIF* TcPacketStored::store = NULL; + +TcPacketStored::TcPacketStored(const uint8_t* data, uint32_t size) : + TcPacketBase(data) { + if (getFullSize() != size) { + return; + } + if (this->checkAndSetStore()) { + ReturnValue_t status = store->addData(&storeAddress, data, size); + if (status != HasReturnvaluesIF::RETURN_OK) { + this->setData(NULL); + } + } +} diff --git a/tmtcpacket/pus/TcPacketStored.h b/tmtcpacket/pus/TcPacketStored.h index de3eb85f..90cf2fba 100644 --- a/tmtcpacket/pus/TcPacketStored.h +++ b/tmtcpacket/pus/TcPacketStored.h @@ -1,110 +1,110 @@ -#ifndef TCPACKETSTORED_H_ -#define TCPACKETSTORED_H_ - -#include -#include - -/** - * This class generates a ECSS PUS Telecommand packet within a given - * intermediate storage. - * As most packets are passed between tasks with the help of a storage - * anyway, it seems logical to create a Packet-In-Storage access class - * which saves the user almost all storage handling operation. - * Packets can both be newly created with the class and be "linked" to - * packets in a store with the help of a storeAddress. - * @ingroup tmtcpackets - */ -class TcPacketStored : public TcPacketBase { -private: - /** - * This is a pointer to the store all instances of the class use. - * If the store is not yet set (i.e. \c store is NULL), every constructor - * call tries to set it and throws an error message in case of failures. - * The default store is objects::TC_STORE. - */ - static StorageManagerIF* store; - /** - * The address where the packet data of the object instance is stored. - */ - store_address_t storeAddress; - /** - * A helper method to check if a store is assigned to the class. - * If not, the method tries to retrieve the store from the global - * ObjectManager. - * @return @li \c true if the store is linked or could be created. - * @li \c false otherwise. - */ - bool checkAndSetStore(); -public: - /** - * This is a default constructor which does not set the data pointer. - * However, it does try to set the packet store. - */ - TcPacketStored(); - /** - * With this constructor, the class instance is linked to an existing - * packet in the packet store. - * The packet content is neither checked nor changed with this call. If - * the packet could not be found, the data pointer is set to NULL. - */ - TcPacketStored( store_address_t setAddress ); - /** - * With this constructor, new space is allocated in the packet store and - * a new PUS Telecommand Packet is created there. - * Packet Application Data passed in data is copied into the packet. - * @param apid Sets the packet's APID field. - * @param ack Set's the packet's Ack field, - * which specifies number and size of verification packets returned - * for this command. - * @param service Sets the packet's Service ID field. - * This specifies the destination service. - * @param subservice Sets the packet's Service Subtype field. - * This specifies the destination sub-service. - * @param sequence_count Sets the packet's Source Sequence Count field. - * @param data The data to be copied to the Application Data Field. - * @param size The amount of data to be copied. - */ - TcPacketStored( uint8_t service, uint8_t subservice, uint16_t apid, - uint8_t sequence_count = 0, const uint8_t* data = nullptr, - size_t size = 0, uint8_t ack = TcPacketBase::ACK_ALL ); - /** - * Another constructor to create a TcPacket from a raw packet stream. - * Takes the data and adds it unchecked to the TcStore. - * @param data Pointer to the complete TC Space Packet. - * @param Size size of the packet. - */ - TcPacketStored( const uint8_t* data, uint32_t size); - - ReturnValue_t getData(const uint8_t ** dataPtr, - size_t* dataSize); - /** - * This is a getter for the current store address of the packet. - * @return The current store address. The (raw) value is \c StorageManagerIF::INVALID_ADDRESS if - * the packet is not linked. - */ - store_address_t getStoreAddress(); - /** - * With this call, the packet is deleted. - * It removes itself from the store and sets its data pointer to NULL. - * @return returncode from deleting the data. - */ - ReturnValue_t deletePacket(); - /** - * With this call, a packet can be linked to another store. This is useful - * if the packet is a class member and used for more than one packet. - * @param setAddress The new packet id to link to. - */ - void setStoreAddress( store_address_t setAddress ); - /** - * This method performs a size check. - * It reads the stored size and compares it with the size entered in the - * packet header. This class is the optimal place for such a check as it - * has access to both the header data and the store. - * @return true if size is correct, false if packet is not registered in - * store or size is incorrect. - */ - bool isSizeCorrect(); -}; - - -#endif /* TCPACKETSTORED_H_ */ +#ifndef TCPACKETSTORED_H_ +#define TCPACKETSTORED_H_ + +#include "../../storagemanager/StorageManagerIF.h" +#include "../../tmtcpacket/pus/TcPacketBase.h" + +/** + * This class generates a ECSS PUS Telecommand packet within a given + * intermediate storage. + * As most packets are passed between tasks with the help of a storage + * anyway, it seems logical to create a Packet-In-Storage access class + * which saves the user almost all storage handling operation. + * Packets can both be newly created with the class and be "linked" to + * packets in a store with the help of a storeAddress. + * @ingroup tmtcpackets + */ +class TcPacketStored : public TcPacketBase { +private: + /** + * This is a pointer to the store all instances of the class use. + * If the store is not yet set (i.e. \c store is NULL), every constructor + * call tries to set it and throws an error message in case of failures. + * The default store is objects::TC_STORE. + */ + static StorageManagerIF* store; + /** + * The address where the packet data of the object instance is stored. + */ + store_address_t storeAddress; + /** + * A helper method to check if a store is assigned to the class. + * If not, the method tries to retrieve the store from the global + * ObjectManager. + * @return @li \c true if the store is linked or could be created. + * @li \c false otherwise. + */ + bool checkAndSetStore(); +public: + /** + * This is a default constructor which does not set the data pointer. + * However, it does try to set the packet store. + */ + TcPacketStored(); + /** + * With this constructor, the class instance is linked to an existing + * packet in the packet store. + * The packet content is neither checked nor changed with this call. If + * the packet could not be found, the data pointer is set to NULL. + */ + TcPacketStored( store_address_t setAddress ); + /** + * With this constructor, new space is allocated in the packet store and + * a new PUS Telecommand Packet is created there. + * Packet Application Data passed in data is copied into the packet. + * @param apid Sets the packet's APID field. + * @param ack Set's the packet's Ack field, + * which specifies number and size of verification packets returned + * for this command. + * @param service Sets the packet's Service ID field. + * This specifies the destination service. + * @param subservice Sets the packet's Service Subtype field. + * This specifies the destination sub-service. + * @param sequence_count Sets the packet's Source Sequence Count field. + * @param data The data to be copied to the Application Data Field. + * @param size The amount of data to be copied. + */ + TcPacketStored( uint8_t service, uint8_t subservice, uint16_t apid, + uint8_t sequence_count = 0, const uint8_t* data = nullptr, + size_t size = 0, uint8_t ack = TcPacketBase::ACK_ALL ); + /** + * Another constructor to create a TcPacket from a raw packet stream. + * Takes the data and adds it unchecked to the TcStore. + * @param data Pointer to the complete TC Space Packet. + * @param Size size of the packet. + */ + TcPacketStored( const uint8_t* data, uint32_t size); + + ReturnValue_t getData(const uint8_t ** dataPtr, + size_t* dataSize); + /** + * This is a getter for the current store address of the packet. + * @return The current store address. The (raw) value is \c StorageManagerIF::INVALID_ADDRESS if + * the packet is not linked. + */ + store_address_t getStoreAddress(); + /** + * With this call, the packet is deleted. + * It removes itself from the store and sets its data pointer to NULL. + * @return returncode from deleting the data. + */ + ReturnValue_t deletePacket(); + /** + * With this call, a packet can be linked to another store. This is useful + * if the packet is a class member and used for more than one packet. + * @param setAddress The new packet id to link to. + */ + void setStoreAddress( store_address_t setAddress ); + /** + * This method performs a size check. + * It reads the stored size and compares it with the size entered in the + * packet header. This class is the optimal place for such a check as it + * has access to both the header data and the store. + * @return true if size is correct, false if packet is not registered in + * store or size is incorrect. + */ + bool isSizeCorrect(); +}; + + +#endif /* TCPACKETSTORED_H_ */ diff --git a/tmtcpacket/pus/TmPacketBase.cpp b/tmtcpacket/pus/TmPacketBase.cpp index a2c27ce1..630471cc 100644 --- a/tmtcpacket/pus/TmPacketBase.cpp +++ b/tmtcpacket/pus/TmPacketBase.cpp @@ -1,119 +1,119 @@ -#include -#include -#include -#include -#include -#include - -TmPacketBase::TmPacketBase(uint8_t* set_data) : - SpacePacketBase(set_data) { - tm_data = (TmPacketPointer*) set_data; -} - -TmPacketBase::~TmPacketBase() { - //Nothing to do. -} - -uint8_t TmPacketBase::getService() { - return tm_data->data_field.service_type; -} - -uint8_t TmPacketBase::getSubService() { - return tm_data->data_field.service_subtype; -} - -uint8_t* TmPacketBase::getSourceData() { - return &tm_data->data; -} - -uint16_t TmPacketBase::getSourceDataSize() { - return getPacketDataLength() - sizeof(tm_data->data_field) - - CRC_SIZE + 1; -} - -uint16_t TmPacketBase::getErrorControl() { - uint32_t size = getSourceDataSize() + CRC_SIZE; - uint8_t* p_to_buffer = &tm_data->data; - return (p_to_buffer[size - 2] << 8) + p_to_buffer[size - 1]; -} - -void TmPacketBase::setErrorControl() { - uint32_t full_size = getFullSize(); - uint16_t crc = CRC::crc16ccitt(getWholeData(), full_size - CRC_SIZE); - uint32_t size = getSourceDataSize(); - getSourceData()[size] = (crc & 0XFF00) >> 8; // CRCH - getSourceData()[size + 1] = (crc) & 0X00FF; // CRCL -} - -void TmPacketBase::setData(const uint8_t* p_Data) { - SpacePacketBase::setData(p_Data); - tm_data = (TmPacketPointer*) p_Data; -} - -void TmPacketBase::print() { - /*uint8_t * wholeData = getWholeData(); - debug << "TmPacket contains: " << std::endl; - for (uint8_t count = 0; count < getFullSize(); ++count ) { - debug << std::hex << (uint16_t)wholeData[count] << " "; - } - debug << std::dec << std::endl;*/ -} - -bool TmPacketBase::checkAndSetStamper() { - if (timeStamper == NULL) { - timeStamper = objectManager->get(timeStamperId); - if (timeStamper == NULL) { - sif::error << "TmPacketBase::checkAndSetStamper: Stamper not found!" - << std::endl; - return false; - } - } - return true; -} - -ReturnValue_t TmPacketBase::getPacketTime(timeval* timestamp) const { - uint32_t tempSize = 0; - return CCSDSTime::convertFromCcsds(timestamp, tm_data->data_field.time, - &tempSize, sizeof(tm_data->data_field.time)); -} - -uint8_t* TmPacketBase::getPacketTimeRaw() const{ - return tm_data->data_field.time; - -} - -void TmPacketBase::initializeTmPacket(uint16_t apid, uint8_t service, uint8_t subservice, uint8_t packetSubcounter) { - //Set primary header: - initSpacePacketHeader(false, true, apid); - //Set data Field Header: - //First, set to zero. - memset(&tm_data->data_field, 0, sizeof(tm_data->data_field)); - //Set CCSDS_secondary header flag to 0, version number to 001 and ack to 0000 - // NOTE: In PUS-C, the PUS Version is 2 and specified for the first 4 bits. - // The other 4 bits of the first byte are the spacecraft time reference status - // To change to PUS-C, set 0b00100000 - tm_data->data_field.version_type_ack = 0b00010000; - tm_data->data_field.service_type = service; - tm_data->data_field.service_subtype = subservice; - tm_data->data_field.subcounter = packetSubcounter; - //Timestamp packet - if (checkAndSetStamper()) { - timeStamper->addTimeStamp(tm_data->data_field.time, sizeof(tm_data->data_field.time)); - } -} - -void TmPacketBase::setSourceData(uint8_t* sourceData, size_t sourceSize) { - memcpy(getSourceData(), sourceData, sourceSize); - setSourceDataSize(sourceSize); -} - -void TmPacketBase::setSourceDataSize(uint16_t size) { - setPacketDataLength(size + sizeof(PUSTmDataFieldHeader) + CRC_SIZE - 1); -} - -uint32_t TmPacketBase::getTimestampSize() const { - return sizeof(tm_data->data_field.time); -} - -TimeStamperIF* TmPacketBase::timeStamper = NULL; -object_id_t TmPacketBase::timeStamperId = 0; +#include "../../globalfunctions/CRC.h" +#include "../../objectmanager/ObjectManagerIF.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "../../tmtcpacket/pus/TmPacketBase.h" +#include "../../timemanager/CCSDSTime.h" +#include + +TmPacketBase::TmPacketBase(uint8_t* set_data) : + SpacePacketBase(set_data) { + tm_data = (TmPacketPointer*) set_data; +} + +TmPacketBase::~TmPacketBase() { + //Nothing to do. +} + +uint8_t TmPacketBase::getService() { + return tm_data->data_field.service_type; +} + +uint8_t TmPacketBase::getSubService() { + return tm_data->data_field.service_subtype; +} + +uint8_t* TmPacketBase::getSourceData() { + return &tm_data->data; +} + +uint16_t TmPacketBase::getSourceDataSize() { + return getPacketDataLength() - sizeof(tm_data->data_field) + - CRC_SIZE + 1; +} + +uint16_t TmPacketBase::getErrorControl() { + uint32_t size = getSourceDataSize() + CRC_SIZE; + uint8_t* p_to_buffer = &tm_data->data; + return (p_to_buffer[size - 2] << 8) + p_to_buffer[size - 1]; +} + +void TmPacketBase::setErrorControl() { + uint32_t full_size = getFullSize(); + uint16_t crc = CRC::crc16ccitt(getWholeData(), full_size - CRC_SIZE); + uint32_t size = getSourceDataSize(); + getSourceData()[size] = (crc & 0XFF00) >> 8; // CRCH + getSourceData()[size + 1] = (crc) & 0X00FF; // CRCL +} + +void TmPacketBase::setData(const uint8_t* p_Data) { + SpacePacketBase::setData(p_Data); + tm_data = (TmPacketPointer*) p_Data; +} + +void TmPacketBase::print() { + /*uint8_t * wholeData = getWholeData(); + debug << "TmPacket contains: " << std::endl; + for (uint8_t count = 0; count < getFullSize(); ++count ) { + debug << std::hex << (uint16_t)wholeData[count] << " "; + } + debug << std::dec << std::endl;*/ +} + +bool TmPacketBase::checkAndSetStamper() { + if (timeStamper == NULL) { + timeStamper = objectManager->get(timeStamperId); + if (timeStamper == NULL) { + sif::error << "TmPacketBase::checkAndSetStamper: Stamper not found!" + << std::endl; + return false; + } + } + return true; +} + +ReturnValue_t TmPacketBase::getPacketTime(timeval* timestamp) const { + uint32_t tempSize = 0; + return CCSDSTime::convertFromCcsds(timestamp, tm_data->data_field.time, + &tempSize, sizeof(tm_data->data_field.time)); +} + +uint8_t* TmPacketBase::getPacketTimeRaw() const{ + return tm_data->data_field.time; + +} + +void TmPacketBase::initializeTmPacket(uint16_t apid, uint8_t service, uint8_t subservice, uint8_t packetSubcounter) { + //Set primary header: + initSpacePacketHeader(false, true, apid); + //Set data Field Header: + //First, set to zero. + memset(&tm_data->data_field, 0, sizeof(tm_data->data_field)); + //Set CCSDS_secondary header flag to 0, version number to 001 and ack to 0000 + // NOTE: In PUS-C, the PUS Version is 2 and specified for the first 4 bits. + // The other 4 bits of the first byte are the spacecraft time reference status + // To change to PUS-C, set 0b00100000 + tm_data->data_field.version_type_ack = 0b00010000; + tm_data->data_field.service_type = service; + tm_data->data_field.service_subtype = subservice; + tm_data->data_field.subcounter = packetSubcounter; + //Timestamp packet + if (checkAndSetStamper()) { + timeStamper->addTimeStamp(tm_data->data_field.time, sizeof(tm_data->data_field.time)); + } +} + +void TmPacketBase::setSourceData(uint8_t* sourceData, size_t sourceSize) { + memcpy(getSourceData(), sourceData, sourceSize); + setSourceDataSize(sourceSize); +} + +void TmPacketBase::setSourceDataSize(uint16_t size) { + setPacketDataLength(size + sizeof(PUSTmDataFieldHeader) + CRC_SIZE - 1); +} + +uint32_t TmPacketBase::getTimestampSize() const { + return sizeof(tm_data->data_field.time); +} + +TimeStamperIF* TmPacketBase::timeStamper = NULL; +object_id_t TmPacketBase::timeStamperId = 0; diff --git a/tmtcpacket/pus/TmPacketBase.h b/tmtcpacket/pus/TmPacketBase.h index 6f3c4b59..acd08d72 100644 --- a/tmtcpacket/pus/TmPacketBase.h +++ b/tmtcpacket/pus/TmPacketBase.h @@ -1,186 +1,186 @@ -#ifndef TMPACKETBASE_H_ -#define TMPACKETBASE_H_ - -#include -#include -#include -#include - -namespace Factory{ -void setStaticFrameworkObjectIds(); -} - -/** - * This struct defines a byte-wise structured PUS TM Data Field Header. - * Any optional fields in the header must be added or removed here. - * Currently, no Destination field is present, but an eigth-byte representation - * for a time tag [TBD]. - * @ingroup tmtcpackets - */ -struct PUSTmDataFieldHeader { - uint8_t version_type_ack; - uint8_t service_type; - uint8_t service_subtype; - uint8_t subcounter; -// uint8_t destination; - uint8_t time[TimeStamperIF::MISSION_TIMESTAMP_SIZE]; -}; - -/** - * This struct defines the data structure of a PUS Telecommand Packet when - * accessed via a pointer. - * @ingroup tmtcpackets - */ -struct TmPacketPointer { - CCSDSPrimaryHeader primary; - PUSTmDataFieldHeader data_field; - uint8_t data; -}; - -/** - * This class is the basic data handler for any ECSS PUS Telemetry packet. - * - * In addition to \SpacePacketBase, the class provides methods to handle - * the standardized entries of the PUS TM Packet Data Field Header. - * It does not contain the packet data itself but a pointer to the - * data must be set on instantiation. An invalid pointer may cause - * damage, as no getter method checks data validity. Anyway, a NULL - * check can be performed by making use of the getWholeData method. - * @ingroup tmtcpackets - */ -class TmPacketBase : public SpacePacketBase { - friend void (Factory::setStaticFrameworkObjectIds)(); -public: - /** - * This constant defines the minimum size of a valid PUS Telemetry Packet. - */ - static const uint32_t TM_PACKET_MIN_SIZE = (sizeof(CCSDSPrimaryHeader) + sizeof(PUSTmDataFieldHeader) + 2); //!< Minimum size of a valid PUS Telemetry Packet. - static const uint32_t MISSION_TM_PACKET_MAX_SIZE = 2048; //!< Maximum size of a TM Packet in this mission. - static const uint8_t VERSION_NUMBER_BYTE_PUS_A = 0b00010000; //!< First byte of secondary header for PUS-A packets. - /** - * This is the default constructor. - * It sets its internal data pointer to the address passed and also - * forwards the data pointer to the parent SpacePacketBase class. - * @param set_address The position where the packet data lies. - */ - TmPacketBase( uint8_t* set_data ); - /** - * This is the empty default destructor. - */ - virtual ~TmPacketBase(); - /** - * Initializes the Tm Packet header. - * Does set the timestamp (to now), but not the error control field. - * @param apid APID used. - * @param service PUS Service - * @param subservice PUS Subservice - * @param packetSubcounter Additional subcounter used. - */ - void initializeTmPacket(uint16_t apid, uint8_t service, uint8_t subservice, uint8_t packetSubcounter); - /** - * This is a getter for the packet's PUS Service ID, which is the second - * byte of the Data Field Header. - * @return The packet's PUS Service ID. - */ - uint8_t getService(); - /** - * This is a getter for the packet's PUS Service Subtype, which is the - * third byte of the Data Field Header. - * @return The packet's PUS Service Subtype. - */ - uint8_t getSubService(); - /** - * This is a getter for a pointer to the packet's Source data. - * - * These are the bytes that follow after the Data Field Header. They form - * the packet's source data. - * @return A pointer to the PUS Source Data. - */ - uint8_t* getSourceData(); - /** - * This method calculates the size of the PUS Source data field. - * - * It takes the information stored in the CCSDS Packet Data Length field - * and subtracts the Data Field Header size and the CRC size. - * @return The size of the PUS Source Data (without Error Control field) - */ - uint16_t getSourceDataSize(); - - /** - * In case data was filled manually (almost never the case). - * @param size Size of source data (without CRC and data filed header!). - */ - void setSourceDataSize(uint16_t size); - /** - * This getter returns the Error Control Field of the packet. - * - * The field is placed after any possible Source Data. If no - * Source Data is present there's still an Error Control field. It is - * supposed to be a 16bit-CRC. - * @return The PUS Error Control - */ - uint16_t getErrorControl(); - /** - * With this method, the Error Control Field is updated to match the - * current content of the packet. - */ - void setErrorControl(); - /** - * This sets the source data. It copies the provided data to - * the internal TmPacketPointer source data location. - * @param sourceData - * @param sourceSize - */ - void setSourceData(uint8_t* sourceData, size_t sourceSize); - /** - * With this method, the packet data pointer can be redirected to another - * location. - * - * This call overwrites the parent's setData method to set both its - * \c tc_data pointer and the parent's \c data pointer. - * - * @param p_data A pointer to another PUS Telemetry Packet. - */ - void setData( const uint8_t* p_Data ); - /** - * This is a debugging helper method that prints the whole packet content - * to the screen. - */ - void print(); - /** - * Interprets the "time"-field in the secondary header and returns it in timeval format. - * @return Converted timestamp of packet. - */ - ReturnValue_t getPacketTime(timeval* timestamp) const; - /** - * Returns a raw pointer to the beginning of the time field. - * @return Raw pointer to time field. - */ - uint8_t* getPacketTimeRaw() const; - - uint32_t getTimestampSize() const; - -protected: - /** - * A pointer to a structure which defines the data structure of - * the packet's data. - * - * To be hardware-safe, all elements are of byte size. - */ - TmPacketPointer* tm_data; - /** - * The timeStamper is responsible for adding a timestamp to the packet. - * It is initialized lazy. - */ - static TimeStamperIF* timeStamper; - - static object_id_t timeStamperId; //!< The ID to use when looking for a time stamper. - /** - * Checks if a time stamper is available and tries to set it if not. - * @return Returns false if setting failed. - */ - bool checkAndSetStamper(); -}; - - -#endif /* TMPACKETBASE_H_ */ +#ifndef TMPACKETBASE_H_ +#define TMPACKETBASE_H_ + +#include "../../timemanager/TimeStamperIF.h" +#include "../../tmtcpacket/SpacePacketBase.h" +#include "../../timemanager/Clock.h" +#include "../../objectmanager/SystemObjectIF.h" + +namespace Factory{ +void setStaticFrameworkObjectIds(); +} + +/** + * This struct defines a byte-wise structured PUS TM Data Field Header. + * Any optional fields in the header must be added or removed here. + * Currently, no Destination field is present, but an eigth-byte representation + * for a time tag [TBD]. + * @ingroup tmtcpackets + */ +struct PUSTmDataFieldHeader { + uint8_t version_type_ack; + uint8_t service_type; + uint8_t service_subtype; + uint8_t subcounter; +// uint8_t destination; + uint8_t time[TimeStamperIF::MISSION_TIMESTAMP_SIZE]; +}; + +/** + * This struct defines the data structure of a PUS Telecommand Packet when + * accessed via a pointer. + * @ingroup tmtcpackets + */ +struct TmPacketPointer { + CCSDSPrimaryHeader primary; + PUSTmDataFieldHeader data_field; + uint8_t data; +}; + +/** + * This class is the basic data handler for any ECSS PUS Telemetry packet. + * + * In addition to \SpacePacketBase, the class provides methods to handle + * the standardized entries of the PUS TM Packet Data Field Header. + * It does not contain the packet data itself but a pointer to the + * data must be set on instantiation. An invalid pointer may cause + * damage, as no getter method checks data validity. Anyway, a NULL + * check can be performed by making use of the getWholeData method. + * @ingroup tmtcpackets + */ +class TmPacketBase : public SpacePacketBase { + friend void (Factory::setStaticFrameworkObjectIds)(); +public: + /** + * This constant defines the minimum size of a valid PUS Telemetry Packet. + */ + static const uint32_t TM_PACKET_MIN_SIZE = (sizeof(CCSDSPrimaryHeader) + sizeof(PUSTmDataFieldHeader) + 2); //!< Minimum size of a valid PUS Telemetry Packet. + static const uint32_t MISSION_TM_PACKET_MAX_SIZE = 2048; //!< Maximum size of a TM Packet in this mission. + static const uint8_t VERSION_NUMBER_BYTE_PUS_A = 0b00010000; //!< First byte of secondary header for PUS-A packets. + /** + * This is the default constructor. + * It sets its internal data pointer to the address passed and also + * forwards the data pointer to the parent SpacePacketBase class. + * @param set_address The position where the packet data lies. + */ + TmPacketBase( uint8_t* set_data ); + /** + * This is the empty default destructor. + */ + virtual ~TmPacketBase(); + /** + * Initializes the Tm Packet header. + * Does set the timestamp (to now), but not the error control field. + * @param apid APID used. + * @param service PUS Service + * @param subservice PUS Subservice + * @param packetSubcounter Additional subcounter used. + */ + void initializeTmPacket(uint16_t apid, uint8_t service, uint8_t subservice, uint8_t packetSubcounter); + /** + * This is a getter for the packet's PUS Service ID, which is the second + * byte of the Data Field Header. + * @return The packet's PUS Service ID. + */ + uint8_t getService(); + /** + * This is a getter for the packet's PUS Service Subtype, which is the + * third byte of the Data Field Header. + * @return The packet's PUS Service Subtype. + */ + uint8_t getSubService(); + /** + * This is a getter for a pointer to the packet's Source data. + * + * These are the bytes that follow after the Data Field Header. They form + * the packet's source data. + * @return A pointer to the PUS Source Data. + */ + uint8_t* getSourceData(); + /** + * This method calculates the size of the PUS Source data field. + * + * It takes the information stored in the CCSDS Packet Data Length field + * and subtracts the Data Field Header size and the CRC size. + * @return The size of the PUS Source Data (without Error Control field) + */ + uint16_t getSourceDataSize(); + + /** + * In case data was filled manually (almost never the case). + * @param size Size of source data (without CRC and data filed header!). + */ + void setSourceDataSize(uint16_t size); + /** + * This getter returns the Error Control Field of the packet. + * + * The field is placed after any possible Source Data. If no + * Source Data is present there's still an Error Control field. It is + * supposed to be a 16bit-CRC. + * @return The PUS Error Control + */ + uint16_t getErrorControl(); + /** + * With this method, the Error Control Field is updated to match the + * current content of the packet. + */ + void setErrorControl(); + /** + * This sets the source data. It copies the provided data to + * the internal TmPacketPointer source data location. + * @param sourceData + * @param sourceSize + */ + void setSourceData(uint8_t* sourceData, size_t sourceSize); + /** + * With this method, the packet data pointer can be redirected to another + * location. + * + * This call overwrites the parent's setData method to set both its + * \c tc_data pointer and the parent's \c data pointer. + * + * @param p_data A pointer to another PUS Telemetry Packet. + */ + void setData( const uint8_t* p_Data ); + /** + * This is a debugging helper method that prints the whole packet content + * to the screen. + */ + void print(); + /** + * Interprets the "time"-field in the secondary header and returns it in timeval format. + * @return Converted timestamp of packet. + */ + ReturnValue_t getPacketTime(timeval* timestamp) const; + /** + * Returns a raw pointer to the beginning of the time field. + * @return Raw pointer to time field. + */ + uint8_t* getPacketTimeRaw() const; + + uint32_t getTimestampSize() const; + +protected: + /** + * A pointer to a structure which defines the data structure of + * the packet's data. + * + * To be hardware-safe, all elements are of byte size. + */ + TmPacketPointer* tm_data; + /** + * The timeStamper is responsible for adding a timestamp to the packet. + * It is initialized lazy. + */ + static TimeStamperIF* timeStamper; + + static object_id_t timeStamperId; //!< The ID to use when looking for a time stamper. + /** + * Checks if a time stamper is available and tries to set it if not. + * @return Returns false if setting failed. + */ + bool checkAndSetStamper(); +}; + + +#endif /* TMPACKETBASE_H_ */ diff --git a/tmtcpacket/pus/TmPacketMinimal.cpp b/tmtcpacket/pus/TmPacketMinimal.cpp index 9df0fe5d..ee56d46f 100644 --- a/tmtcpacket/pus/TmPacketMinimal.cpp +++ b/tmtcpacket/pus/TmPacketMinimal.cpp @@ -1,45 +1,45 @@ -#include -#include -#include -#include - -TmPacketMinimal::TmPacketMinimal(const uint8_t* set_data) : SpacePacketBase( set_data ) { - this->tm_data = (TmPacketMinimalPointer*)set_data; -} - -TmPacketMinimal::~TmPacketMinimal() { -} - -uint8_t TmPacketMinimal::getService() { - return tm_data->data_field.service_type; -} - -uint8_t TmPacketMinimal::getSubService() { - return tm_data->data_field.service_subtype; -} - -uint8_t TmPacketMinimal::getPacketSubcounter() { - return tm_data->data_field.subcounter; -} - -ReturnValue_t TmPacketMinimal::getPacketTime(timeval* timestamp) { - if (timestampInterpreter == NULL) { - return HasReturnvaluesIF::RETURN_FAILED; - } - return timestampInterpreter->getPacketTime(this, timestamp); -} - -ReturnValue_t TmPacketMinimal::getPacketTimeRaw(const uint8_t** timePtr, uint32_t* size) { - if (timestampInterpreter == NULL) { - return HasReturnvaluesIF::RETURN_FAILED; - } - return timestampInterpreter->getPacketTimeRaw(this, timePtr, size); -} - -void TmPacketMinimal::setInterpretTimestampObject(PacketTimestampInterpreterIF* interpreter) { - if (TmPacketMinimal::timestampInterpreter == NULL) { - TmPacketMinimal::timestampInterpreter = interpreter; - } -} - -PacketTimestampInterpreterIF* TmPacketMinimal::timestampInterpreter = NULL; +#include "../../tmtcpacket/pus/TmPacketMinimal.h" +#include +#include +#include "../../tmtcpacket/pus/PacketTimestampInterpreterIF.h" + +TmPacketMinimal::TmPacketMinimal(const uint8_t* set_data) : SpacePacketBase( set_data ) { + this->tm_data = (TmPacketMinimalPointer*)set_data; +} + +TmPacketMinimal::~TmPacketMinimal() { +} + +uint8_t TmPacketMinimal::getService() { + return tm_data->data_field.service_type; +} + +uint8_t TmPacketMinimal::getSubService() { + return tm_data->data_field.service_subtype; +} + +uint8_t TmPacketMinimal::getPacketSubcounter() { + return tm_data->data_field.subcounter; +} + +ReturnValue_t TmPacketMinimal::getPacketTime(timeval* timestamp) { + if (timestampInterpreter == NULL) { + return HasReturnvaluesIF::RETURN_FAILED; + } + return timestampInterpreter->getPacketTime(this, timestamp); +} + +ReturnValue_t TmPacketMinimal::getPacketTimeRaw(const uint8_t** timePtr, uint32_t* size) { + if (timestampInterpreter == NULL) { + return HasReturnvaluesIF::RETURN_FAILED; + } + return timestampInterpreter->getPacketTimeRaw(this, timePtr, size); +} + +void TmPacketMinimal::setInterpretTimestampObject(PacketTimestampInterpreterIF* interpreter) { + if (TmPacketMinimal::timestampInterpreter == NULL) { + TmPacketMinimal::timestampInterpreter = interpreter; + } +} + +PacketTimestampInterpreterIF* TmPacketMinimal::timestampInterpreter = NULL; diff --git a/tmtcpacket/pus/TmPacketMinimal.h b/tmtcpacket/pus/TmPacketMinimal.h index 7bfe0883..e7b362bf 100644 --- a/tmtcpacket/pus/TmPacketMinimal.h +++ b/tmtcpacket/pus/TmPacketMinimal.h @@ -1,84 +1,84 @@ -#ifndef FRAMEWORK_TMTCPACKET_PUS_TMPACKETMINIMAL_H_ -#define FRAMEWORK_TMTCPACKET_PUS_TMPACKETMINIMAL_H_ - - -#include -#include - -struct timeval; -class PacketTimestampInterpreterIF; -/** - * This is a minimal version of a PUS TmPacket without any variable field, or, - * in other words with Service Type, Subtype and subcounter only. - * This is required for handling TM packets with different APIDs with different - * secondary headers. - */ -class TmPacketMinimal : public SpacePacketBase { -public: - /** - * This is the default constructor. - * It sets its internal data pointer to the address passed and also - * forwards the data pointer to the parent SpacePacketBase class. - * @param set_address The position where the packet data lies. - */ - TmPacketMinimal( const uint8_t* set_data ); - /** - * This is the empty default destructor. - */ - virtual ~TmPacketMinimal(); - /** - * This is a getter for the packet's PUS Service ID, which is the second - * byte of the Data Field Header. - * @return The packet's PUS Service ID. - */ - uint8_t getService(); - /** - * This is a getter for the packet's PUS Service Subtype, which is the - * third byte of the Data Field Header. - * @return The packet's PUS Service Subtype. - */ - uint8_t getSubService(); - /** - * Returns the subcounter. - * @return the subcounter of the Data Field Header. - */ - uint8_t getPacketSubcounter(); - struct PUSTmMinimalHeader { - uint8_t version_type_ack; - uint8_t service_type; - uint8_t service_subtype; - uint8_t subcounter; - }; - - ReturnValue_t getPacketTime(timeval* timestamp); - - ReturnValue_t getPacketTimeRaw(const uint8_t** timePtr, uint32_t* size); - - static void setInterpretTimestampObject(PacketTimestampInterpreterIF* interpreter); - /** - * This struct defines the data structure of a PUS Telecommand Packet when - * accessed via a pointer. - * @ingroup tmtcpackets - */ - struct TmPacketMinimalPointer { - CCSDSPrimaryHeader primary; - PUSTmMinimalHeader data_field; - uint8_t rest; - }; - //Must include a checksum and is therefore at least one larger than the above struct. - static const uint16_t MINIMUM_SIZE = sizeof(TmPacketMinimalPointer) +1; -protected: - /** - * A pointer to a structure which defines the data structure of - * the packet's data. - * - * To be hardware-safe, all elements are of byte size. - */ - TmPacketMinimalPointer* tm_data; - - static PacketTimestampInterpreterIF* timestampInterpreter; -}; - - - -#endif /* FRAMEWORK_TMTCPACKET_PUS_TMPACKETMINIMAL_H_ */ +#ifndef FRAMEWORK_TMTCPACKET_PUS_TMPACKETMINIMAL_H_ +#define FRAMEWORK_TMTCPACKET_PUS_TMPACKETMINIMAL_H_ + + +#include "../../tmtcpacket/SpacePacketBase.h" +#include "../../returnvalues/HasReturnvaluesIF.h" + +struct timeval; +class PacketTimestampInterpreterIF; +/** + * This is a minimal version of a PUS TmPacket without any variable field, or, + * in other words with Service Type, Subtype and subcounter only. + * This is required for handling TM packets with different APIDs with different + * secondary headers. + */ +class TmPacketMinimal : public SpacePacketBase { +public: + /** + * This is the default constructor. + * It sets its internal data pointer to the address passed and also + * forwards the data pointer to the parent SpacePacketBase class. + * @param set_address The position where the packet data lies. + */ + TmPacketMinimal( const uint8_t* set_data ); + /** + * This is the empty default destructor. + */ + virtual ~TmPacketMinimal(); + /** + * This is a getter for the packet's PUS Service ID, which is the second + * byte of the Data Field Header. + * @return The packet's PUS Service ID. + */ + uint8_t getService(); + /** + * This is a getter for the packet's PUS Service Subtype, which is the + * third byte of the Data Field Header. + * @return The packet's PUS Service Subtype. + */ + uint8_t getSubService(); + /** + * Returns the subcounter. + * @return the subcounter of the Data Field Header. + */ + uint8_t getPacketSubcounter(); + struct PUSTmMinimalHeader { + uint8_t version_type_ack; + uint8_t service_type; + uint8_t service_subtype; + uint8_t subcounter; + }; + + ReturnValue_t getPacketTime(timeval* timestamp); + + ReturnValue_t getPacketTimeRaw(const uint8_t** timePtr, uint32_t* size); + + static void setInterpretTimestampObject(PacketTimestampInterpreterIF* interpreter); + /** + * This struct defines the data structure of a PUS Telecommand Packet when + * accessed via a pointer. + * @ingroup tmtcpackets + */ + struct TmPacketMinimalPointer { + CCSDSPrimaryHeader primary; + PUSTmMinimalHeader data_field; + uint8_t rest; + }; + //Must include a checksum and is therefore at least one larger than the above struct. + static const uint16_t MINIMUM_SIZE = sizeof(TmPacketMinimalPointer) +1; +protected: + /** + * A pointer to a structure which defines the data structure of + * the packet's data. + * + * To be hardware-safe, all elements are of byte size. + */ + TmPacketMinimalPointer* tm_data; + + static PacketTimestampInterpreterIF* timestampInterpreter; +}; + + + +#endif /* FRAMEWORK_TMTCPACKET_PUS_TMPACKETMINIMAL_H_ */ diff --git a/tmtcpacket/pus/TmPacketStored.cpp b/tmtcpacket/pus/TmPacketStored.cpp index 6eb852f0..e42f8cda 100644 --- a/tmtcpacket/pus/TmPacketStored.cpp +++ b/tmtcpacket/pus/TmPacketStored.cpp @@ -1,145 +1,145 @@ -#include -#include -#include -#include -#include - -TmPacketStored::TmPacketStored(store_address_t setAddress) : - TmPacketBase(NULL), storeAddress(setAddress) { - setStoreAddress(storeAddress); -} - -TmPacketStored::TmPacketStored(uint16_t apid, uint8_t service, - uint8_t subservice, uint8_t packetSubcounter, const uint8_t *data, - uint32_t size, const uint8_t *headerData, uint32_t headerSize) : - TmPacketBase(NULL) { - storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; - if (!checkAndSetStore()) { - return; - } - uint8_t *pData = NULL; - ReturnValue_t returnValue = store->getFreeElement(&storeAddress, - (TmPacketBase::TM_PACKET_MIN_SIZE + size + headerSize), &pData); - - if (returnValue != store->RETURN_OK) { - sif::debug << "TM Packet Stored: Issue getting free storage" << std::endl; - checkAndReportLostTm(); - return; - } - setData(pData); - initializeTmPacket(apid, service, subservice, packetSubcounter); - memcpy(getSourceData(), headerData, headerSize); - memcpy(getSourceData() + headerSize, data, size); - setPacketDataLength( - size + headerSize + sizeof(PUSTmDataFieldHeader) + CRC_SIZE - 1); -} - -// todo: Endianness flags as optional parameter? -TmPacketStored::TmPacketStored(uint16_t apid, uint8_t service, - uint8_t subservice, uint8_t packetSubcounter, SerializeIF *content, - SerializeIF *header) : - TmPacketBase(NULL) { - storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; - if (!checkAndSetStore()) { - return; - } - size_t sourceDataSize = 0; - if (content != NULL) { - sourceDataSize += content->getSerializedSize(); - } - if (header != NULL) { - sourceDataSize += header->getSerializedSize(); - } - uint8_t *p_data = NULL; - ReturnValue_t returnValue = store->getFreeElement(&storeAddress, - (TmPacketBase::TM_PACKET_MIN_SIZE + sourceDataSize), &p_data); - if (returnValue != store->RETURN_OK) { - checkAndReportLostTm(); - } - setData(p_data); - initializeTmPacket(apid, service, subservice, packetSubcounter); - uint8_t *putDataHere = getSourceData(); - size_t size = 0; - if (header != NULL) { - header->serialize(&putDataHere, &size, sourceDataSize, - SerializeIF::Endianness::BIG); - } - if (content != NULL) { - content->serialize(&putDataHere, &size, sourceDataSize, - SerializeIF::Endianness::BIG); - } - setPacketDataLength( - sourceDataSize + sizeof(PUSTmDataFieldHeader) + CRC_SIZE - 1); -} - -store_address_t TmPacketStored::getStoreAddress() { - return storeAddress; -} - -void TmPacketStored::deletePacket() { - store->deleteData(storeAddress); - storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; - setData(NULL); -} - -void TmPacketStored::setStoreAddress(store_address_t setAddress) { - storeAddress = setAddress; - const uint8_t *temp_data = NULL; - size_t temp_size; - if (!checkAndSetStore()) { - return; - } - ReturnValue_t status = store->getData(storeAddress, &temp_data, &temp_size); - if (status == StorageManagerIF::RETURN_OK) { - setData(temp_data); - } else { - setData(NULL); - storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; - } -} - -bool TmPacketStored::checkAndSetStore() { - if (store == NULL) { - store = objectManager->get(objects::TM_STORE); - if (store == NULL) { - sif::error << "TmPacketStored::TmPacketStored: TM Store not found!" - << std::endl; - return false; - } - } - return true; -} - -StorageManagerIF *TmPacketStored::store = NULL; -InternalErrorReporterIF *TmPacketStored::internalErrorReporter = NULL; - -ReturnValue_t TmPacketStored::sendPacket(MessageQueueId_t destination, - MessageQueueId_t sentFrom, bool doErrorReporting) { - if (getWholeData() == NULL) { - //SHOULDDO: More decent code. - return HasReturnvaluesIF::RETURN_FAILED; - } - TmTcMessage tmMessage(getStoreAddress()); - ReturnValue_t result = MessageQueueSenderIF::sendMessage(destination, - &tmMessage, sentFrom); - if (result != HasReturnvaluesIF::RETURN_OK) { - deletePacket(); - if (doErrorReporting) { - checkAndReportLostTm(); - } - return result; - } - //SHOULDDO: In many cases, some counter is incremented for successfully sent packets. The check is often not done, but just incremented. - return HasReturnvaluesIF::RETURN_OK; - -} - -void TmPacketStored::checkAndReportLostTm() { - if (internalErrorReporter == NULL) { - internalErrorReporter = objectManager->get( - objects::INTERNAL_ERROR_REPORTER); - } - if (internalErrorReporter != NULL) { - internalErrorReporter->lostTm(); - } -} +#include "../../objectmanager/ObjectManagerIF.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "../../tmtcpacket/pus/TmPacketStored.h" +#include "../../tmtcservices/TmTcMessage.h" +#include + +TmPacketStored::TmPacketStored(store_address_t setAddress) : + TmPacketBase(NULL), storeAddress(setAddress) { + setStoreAddress(storeAddress); +} + +TmPacketStored::TmPacketStored(uint16_t apid, uint8_t service, + uint8_t subservice, uint8_t packetSubcounter, const uint8_t *data, + uint32_t size, const uint8_t *headerData, uint32_t headerSize) : + TmPacketBase(NULL) { + storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; + if (!checkAndSetStore()) { + return; + } + uint8_t *pData = NULL; + ReturnValue_t returnValue = store->getFreeElement(&storeAddress, + (TmPacketBase::TM_PACKET_MIN_SIZE + size + headerSize), &pData); + + if (returnValue != store->RETURN_OK) { + sif::debug << "TM Packet Stored: Issue getting free storage" << std::endl; + checkAndReportLostTm(); + return; + } + setData(pData); + initializeTmPacket(apid, service, subservice, packetSubcounter); + memcpy(getSourceData(), headerData, headerSize); + memcpy(getSourceData() + headerSize, data, size); + setPacketDataLength( + size + headerSize + sizeof(PUSTmDataFieldHeader) + CRC_SIZE - 1); +} + +// todo: Endianness flags as optional parameter? +TmPacketStored::TmPacketStored(uint16_t apid, uint8_t service, + uint8_t subservice, uint8_t packetSubcounter, SerializeIF *content, + SerializeIF *header) : + TmPacketBase(NULL) { + storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; + if (!checkAndSetStore()) { + return; + } + size_t sourceDataSize = 0; + if (content != NULL) { + sourceDataSize += content->getSerializedSize(); + } + if (header != NULL) { + sourceDataSize += header->getSerializedSize(); + } + uint8_t *p_data = NULL; + ReturnValue_t returnValue = store->getFreeElement(&storeAddress, + (TmPacketBase::TM_PACKET_MIN_SIZE + sourceDataSize), &p_data); + if (returnValue != store->RETURN_OK) { + checkAndReportLostTm(); + } + setData(p_data); + initializeTmPacket(apid, service, subservice, packetSubcounter); + uint8_t *putDataHere = getSourceData(); + size_t size = 0; + if (header != NULL) { + header->serialize(&putDataHere, &size, sourceDataSize, + SerializeIF::Endianness::BIG); + } + if (content != NULL) { + content->serialize(&putDataHere, &size, sourceDataSize, + SerializeIF::Endianness::BIG); + } + setPacketDataLength( + sourceDataSize + sizeof(PUSTmDataFieldHeader) + CRC_SIZE - 1); +} + +store_address_t TmPacketStored::getStoreAddress() { + return storeAddress; +} + +void TmPacketStored::deletePacket() { + store->deleteData(storeAddress); + storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; + setData(NULL); +} + +void TmPacketStored::setStoreAddress(store_address_t setAddress) { + storeAddress = setAddress; + const uint8_t *temp_data = NULL; + size_t temp_size; + if (!checkAndSetStore()) { + return; + } + ReturnValue_t status = store->getData(storeAddress, &temp_data, &temp_size); + if (status == StorageManagerIF::RETURN_OK) { + setData(temp_data); + } else { + setData(NULL); + storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; + } +} + +bool TmPacketStored::checkAndSetStore() { + if (store == NULL) { + store = objectManager->get(objects::TM_STORE); + if (store == NULL) { + sif::error << "TmPacketStored::TmPacketStored: TM Store not found!" + << std::endl; + return false; + } + } + return true; +} + +StorageManagerIF *TmPacketStored::store = NULL; +InternalErrorReporterIF *TmPacketStored::internalErrorReporter = NULL; + +ReturnValue_t TmPacketStored::sendPacket(MessageQueueId_t destination, + MessageQueueId_t sentFrom, bool doErrorReporting) { + if (getWholeData() == NULL) { + //SHOULDDO: More decent code. + return HasReturnvaluesIF::RETURN_FAILED; + } + TmTcMessage tmMessage(getStoreAddress()); + ReturnValue_t result = MessageQueueSenderIF::sendMessage(destination, + &tmMessage, sentFrom); + if (result != HasReturnvaluesIF::RETURN_OK) { + deletePacket(); + if (doErrorReporting) { + checkAndReportLostTm(); + } + return result; + } + //SHOULDDO: In many cases, some counter is incremented for successfully sent packets. The check is often not done, but just incremented. + return HasReturnvaluesIF::RETURN_OK; + +} + +void TmPacketStored::checkAndReportLostTm() { + if (internalErrorReporter == NULL) { + internalErrorReporter = objectManager->get( + objects::INTERNAL_ERROR_REPORTER); + } + if (internalErrorReporter != NULL) { + internalErrorReporter->lostTm(); + } +} diff --git a/tmtcpacket/pus/TmPacketStored.h b/tmtcpacket/pus/TmPacketStored.h index eaa26ce7..195c3272 100644 --- a/tmtcpacket/pus/TmPacketStored.h +++ b/tmtcpacket/pus/TmPacketStored.h @@ -1,96 +1,96 @@ -#ifndef TMPACKETSTORED_H_ -#define TMPACKETSTORED_H_ - -#include -#include -#include -#include -#include - -/** - * This class generates a ECSS PUS Telemetry packet within a given - * intermediate storage. - * As most packets are passed between tasks with the help of a storage - * anyway, it seems logical to create a Packet-In-Storage access class - * which saves the user almost all storage handling operation. - * Packets can both be newly created with the class and be "linked" to - * packets in a store with the help of a storeAddress. - * @ingroup tmtcpackets - */ -class TmPacketStored : public TmPacketBase { -private: - /** - * This is a pointer to the store all instances of the class use. - * If the store is not yet set (i.e. \c store is NULL), every constructor - * call tries to set it and throws an error message in case of failures. - * The default store is objects::TM_STORE. - */ - static StorageManagerIF* store; - - static InternalErrorReporterIF *internalErrorReporter; - - /** - * The address where the packet data of the object instance is stored. - */ - store_address_t storeAddress; - /** - * A helper method to check if a store is assigned to the class. - * If not, the method tries to retrieve the store from the global - * ObjectManager. - * @return @li \c true if the store is linked or could be created. - * @li \c false otherwise. - */ - bool checkAndSetStore(); - - void checkAndReportLostTm(); -public: - /** - * This is a default constructor which does not set the data pointer. - * However, it does try to set the packet store. - */ - TmPacketStored( store_address_t setAddress ); - /** - * With this constructor, new space is allocated in the packet store and - * a new PUS Telemetry Packet is created there. - * Packet Application Data passed in data is copied into the packet. The Application data is - * passed in two parts, first a header, then a data field. This allows building a Telemetry - * Packet from two separate data sources. - * @param apid Sets the packet's APID field. - * @param service Sets the packet's Service ID field. - * This specifies the source service. - * @param subservice Sets the packet's Service Subtype field. - * This specifies the source sub-service. - * @param packet_counter Sets the Packet counter field of this packet - * @param data The payload data to be copied to the Application Data Field - * @param size The amount of data to be copied. - * @param headerData The header Data of the Application field; will be copied in front of data - * @param headerSize The size of the headerDataF - */ - TmPacketStored( uint16_t apid, uint8_t service, uint8_t subservice, uint8_t packet_counter = 0, const uint8_t* data = NULL, uint32_t size = 0, const uint8_t* headerData = NULL, uint32_t headerSize = 0); - /** - * Another ctor to directly pass structured content and header data to the packet to avoid additional buffers. - */ - TmPacketStored( uint16_t apid, uint8_t service, uint8_t subservice, uint8_t packet_counter, SerializeIF* content, SerializeIF* header = NULL); - /** - * This is a getter for the current store address of the packet. - * @return The current store address. The (raw) value is \c StorageManagerIF::INVALID_ADDRESS if - * the packet is not linked. - */ - store_address_t getStoreAddress(); - /** - * With this call, the packet is deleted. - * It removes itself from the store and sets its data pointer to NULL. - */ - void deletePacket(); - /** - * With this call, a packet can be linked to another store. This is useful - * if the packet is a class member and used for more than one packet. - * @param setAddress The new packet id to link to. - */ - void setStoreAddress( store_address_t setAddress ); - - ReturnValue_t sendPacket( MessageQueueId_t destination, MessageQueueId_t sentFrom, bool doErrorReporting = true ); -}; - - -#endif /* TMPACKETSTORED_H_ */ +#ifndef TMPACKETSTORED_H_ +#define TMPACKETSTORED_H_ + +#include "../../serialize/SerializeIF.h" +#include "../../storagemanager/StorageManagerIF.h" +#include "../../tmtcpacket/pus/TmPacketBase.h" +#include "../../internalError/InternalErrorReporterIF.h" +#include "../../ipc/MessageQueueSenderIF.h" + +/** + * This class generates a ECSS PUS Telemetry packet within a given + * intermediate storage. + * As most packets are passed between tasks with the help of a storage + * anyway, it seems logical to create a Packet-In-Storage access class + * which saves the user almost all storage handling operation. + * Packets can both be newly created with the class and be "linked" to + * packets in a store with the help of a storeAddress. + * @ingroup tmtcpackets + */ +class TmPacketStored : public TmPacketBase { +private: + /** + * This is a pointer to the store all instances of the class use. + * If the store is not yet set (i.e. \c store is NULL), every constructor + * call tries to set it and throws an error message in case of failures. + * The default store is objects::TM_STORE. + */ + static StorageManagerIF* store; + + static InternalErrorReporterIF *internalErrorReporter; + + /** + * The address where the packet data of the object instance is stored. + */ + store_address_t storeAddress; + /** + * A helper method to check if a store is assigned to the class. + * If not, the method tries to retrieve the store from the global + * ObjectManager. + * @return @li \c true if the store is linked or could be created. + * @li \c false otherwise. + */ + bool checkAndSetStore(); + + void checkAndReportLostTm(); +public: + /** + * This is a default constructor which does not set the data pointer. + * However, it does try to set the packet store. + */ + TmPacketStored( store_address_t setAddress ); + /** + * With this constructor, new space is allocated in the packet store and + * a new PUS Telemetry Packet is created there. + * Packet Application Data passed in data is copied into the packet. The Application data is + * passed in two parts, first a header, then a data field. This allows building a Telemetry + * Packet from two separate data sources. + * @param apid Sets the packet's APID field. + * @param service Sets the packet's Service ID field. + * This specifies the source service. + * @param subservice Sets the packet's Service Subtype field. + * This specifies the source sub-service. + * @param packet_counter Sets the Packet counter field of this packet + * @param data The payload data to be copied to the Application Data Field + * @param size The amount of data to be copied. + * @param headerData The header Data of the Application field; will be copied in front of data + * @param headerSize The size of the headerDataF + */ + TmPacketStored( uint16_t apid, uint8_t service, uint8_t subservice, uint8_t packet_counter = 0, const uint8_t* data = NULL, uint32_t size = 0, const uint8_t* headerData = NULL, uint32_t headerSize = 0); + /** + * Another ctor to directly pass structured content and header data to the packet to avoid additional buffers. + */ + TmPacketStored( uint16_t apid, uint8_t service, uint8_t subservice, uint8_t packet_counter, SerializeIF* content, SerializeIF* header = NULL); + /** + * This is a getter for the current store address of the packet. + * @return The current store address. The (raw) value is \c StorageManagerIF::INVALID_ADDRESS if + * the packet is not linked. + */ + store_address_t getStoreAddress(); + /** + * With this call, the packet is deleted. + * It removes itself from the store and sets its data pointer to NULL. + */ + void deletePacket(); + /** + * With this call, a packet can be linked to another store. This is useful + * if the packet is a class member and used for more than one packet. + * @param setAddress The new packet id to link to. + */ + void setStoreAddress( store_address_t setAddress ); + + ReturnValue_t sendPacket( MessageQueueId_t destination, MessageQueueId_t sentFrom, bool doErrorReporting = true ); +}; + + +#endif /* TMPACKETSTORED_H_ */ diff --git a/tmtcservices/AcceptsTelecommandsIF.h b/tmtcservices/AcceptsTelecommandsIF.h index 2878dd5d..13928df5 100644 --- a/tmtcservices/AcceptsTelecommandsIF.h +++ b/tmtcservices/AcceptsTelecommandsIF.h @@ -1,43 +1,43 @@ -#ifndef FRAMEWORK_TMTCSERVICES_ACCEPTSTELECOMMANDSIF_H_ -#define FRAMEWORK_TMTCSERVICES_ACCEPTSTELECOMMANDSIF_H_ - -#include - -/** - * @brief This interface is implemented by classes that are sinks for - * Telecommands. - * @details Any service receiving telecommands shall implement this interface - * and thus make the service id and the receiving message queue public. - */ -class AcceptsTelecommandsIF { -public: - static const uint8_t INTERFACE_ID = CLASS_ID::ACCEPTS_TELECOMMANDS_IF; - static const ReturnValue_t ACTIVITY_STARTED = MAKE_RETURN_CODE(1); // is this used anywhere or can it be removed? - static const ReturnValue_t INVALID_SUBSERVICE = MAKE_RETURN_CODE(2); - static const ReturnValue_t ILLEGAL_APPLICATION_DATA = MAKE_RETURN_CODE(3); - static const ReturnValue_t SEND_TM_FAILED = MAKE_RETURN_CODE(4); - static const ReturnValue_t TIMEOUT = MAKE_RETURN_CODE(5); - /** - * @brief The virtual destructor as it is mandatory for C++ interfaces. - */ - virtual ~AcceptsTelecommandsIF() { - - } - /** - * @brief Getter for the service id. - * @details Any receiving service (at least any PUS service) shall have a - * service ID. If the receiver can handle Telecommands, but for - * some reason has no service id, it shall return 0. - * @return The service ID or 0. - */ - virtual uint16_t getIdentifier() = 0; - /** - * @brief This method returns the message queue id of the telecommand - * receiving message queue. - * @return The telecommand reception message queue id. - */ - virtual MessageQueueId_t getRequestQueue() = 0; -}; - - -#endif /* FRAMEWORK_TMTCSERVICES_ACCEPTSTELECOMMANDSIF_H_ */ +#ifndef FRAMEWORK_TMTCSERVICES_ACCEPTSTELECOMMANDSIF_H_ +#define FRAMEWORK_TMTCSERVICES_ACCEPTSTELECOMMANDSIF_H_ + +#include "../ipc/MessageQueueSenderIF.h" + +/** + * @brief This interface is implemented by classes that are sinks for + * Telecommands. + * @details Any service receiving telecommands shall implement this interface + * and thus make the service id and the receiving message queue public. + */ +class AcceptsTelecommandsIF { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::ACCEPTS_TELECOMMANDS_IF; + static const ReturnValue_t ACTIVITY_STARTED = MAKE_RETURN_CODE(1); // is this used anywhere or can it be removed? + static const ReturnValue_t INVALID_SUBSERVICE = MAKE_RETURN_CODE(2); + static const ReturnValue_t ILLEGAL_APPLICATION_DATA = MAKE_RETURN_CODE(3); + static const ReturnValue_t SEND_TM_FAILED = MAKE_RETURN_CODE(4); + static const ReturnValue_t TIMEOUT = MAKE_RETURN_CODE(5); + /** + * @brief The virtual destructor as it is mandatory for C++ interfaces. + */ + virtual ~AcceptsTelecommandsIF() { + + } + /** + * @brief Getter for the service id. + * @details Any receiving service (at least any PUS service) shall have a + * service ID. If the receiver can handle Telecommands, but for + * some reason has no service id, it shall return 0. + * @return The service ID or 0. + */ + virtual uint16_t getIdentifier() = 0; + /** + * @brief This method returns the message queue id of the telecommand + * receiving message queue. + * @return The telecommand reception message queue id. + */ + virtual MessageQueueId_t getRequestQueue() = 0; +}; + + +#endif /* FRAMEWORK_TMTCSERVICES_ACCEPTSTELECOMMANDSIF_H_ */ diff --git a/tmtcservices/AcceptsTelemetryIF.h b/tmtcservices/AcceptsTelemetryIF.h index 8c00b5c6..bcb38666 100644 --- a/tmtcservices/AcceptsTelemetryIF.h +++ b/tmtcservices/AcceptsTelemetryIF.h @@ -1,26 +1,26 @@ -#ifndef ACCEPTSTELEMETRYIF_H_ -#define ACCEPTSTELEMETRYIF_H_ - -#include -/** - * @brief This interface is implemented by classes that are sinks for - * Telemetry. - * @details Any object receiving telemetry shall implement this interface - * and thus make the service id and the receiving message queue public. - */ -class AcceptsTelemetryIF { -public: - /** - * @brief The virtual destructor as it is mandatory for C++ interfaces. - */ - virtual ~AcceptsTelemetryIF() { - } - /** - * @brief This method returns the message queue id of the telemetry - * receiving message queue. - * @return The telemetry reception message queue id. - */ - virtual MessageQueueId_t getReportReceptionQueue(uint8_t virtualChannel = 0) = 0; -}; - -#endif /* ACCEPTSTELEMETRYIF_H_ */ +#ifndef ACCEPTSTELEMETRYIF_H_ +#define ACCEPTSTELEMETRYIF_H_ + +#include "../ipc/MessageQueueSenderIF.h" +/** + * @brief This interface is implemented by classes that are sinks for + * Telemetry. + * @details Any object receiving telemetry shall implement this interface + * and thus make the service id and the receiving message queue public. + */ +class AcceptsTelemetryIF { +public: + /** + * @brief The virtual destructor as it is mandatory for C++ interfaces. + */ + virtual ~AcceptsTelemetryIF() { + } + /** + * @brief This method returns the message queue id of the telemetry + * receiving message queue. + * @return The telemetry reception message queue id. + */ + virtual MessageQueueId_t getReportReceptionQueue(uint8_t virtualChannel = 0) = 0; +}; + +#endif /* ACCEPTSTELEMETRYIF_H_ */ diff --git a/tmtcservices/AcceptsVerifyMessageIF.h b/tmtcservices/AcceptsVerifyMessageIF.h index fe8bb288..a312390e 100644 --- a/tmtcservices/AcceptsVerifyMessageIF.h +++ b/tmtcservices/AcceptsVerifyMessageIF.h @@ -1,15 +1,15 @@ -#ifndef ACCEPTSVERIFICATIONMESSAGEIF_H_ -#define ACCEPTSVERIFICATIONMESSAGEIF_H_ - -#include - -class AcceptsVerifyMessageIF { -public: - virtual ~AcceptsVerifyMessageIF() { - - } - virtual MessageQueueId_t getVerificationQueue() = 0; -}; - - -#endif /* ACCEPTSVERIFICATIONMESSAGEIF_H_ */ +#ifndef ACCEPTSVERIFICATIONMESSAGEIF_H_ +#define ACCEPTSVERIFICATIONMESSAGEIF_H_ + +#include "../ipc/MessageQueueSenderIF.h" + +class AcceptsVerifyMessageIF { +public: + virtual ~AcceptsVerifyMessageIF() { + + } + virtual MessageQueueId_t getVerificationQueue() = 0; +}; + + +#endif /* ACCEPTSVERIFICATIONMESSAGEIF_H_ */ diff --git a/tmtcservices/CommandingServiceBase.cpp b/tmtcservices/CommandingServiceBase.cpp index 330fd00f..3325b10b 100644 --- a/tmtcservices/CommandingServiceBase.cpp +++ b/tmtcservices/CommandingServiceBase.cpp @@ -1,427 +1,427 @@ -#include -#include -#include - -#include -#include -#include -#include -#include - -object_id_t CommandingServiceBase::defaultPacketSource = objects::NO_OBJECT; -object_id_t CommandingServiceBase::defaultPacketDestination = objects::NO_OBJECT; - -CommandingServiceBase::CommandingServiceBase(object_id_t setObjectId, - uint16_t apid, uint8_t service, uint8_t numberOfParallelCommands, - uint16_t commandTimeoutSeconds, size_t queueDepth) : - SystemObject(setObjectId), apid(apid), service(service), - timeoutSeconds(commandTimeoutSeconds), - commandMap(numberOfParallelCommands) { - commandQueue = QueueFactory::instance()->createMessageQueue(queueDepth); - requestQueue = QueueFactory::instance()->createMessageQueue(queueDepth); -} - -void CommandingServiceBase::setPacketSource(object_id_t packetSource) { - this->packetSource = packetSource; -} - -void CommandingServiceBase::setPacketDestination( - object_id_t packetDestination) { - this->packetDestination = packetDestination; -} - - -CommandingServiceBase::~CommandingServiceBase() { - QueueFactory::instance()->deleteMessageQueue(commandQueue); - QueueFactory::instance()->deleteMessageQueue(requestQueue); -} - - -ReturnValue_t CommandingServiceBase::performOperation(uint8_t opCode) { - handleCommandQueue(); - handleRequestQueue(); - checkTimeout(); - doPeriodicOperation(); - return RETURN_OK; -} - - -uint16_t CommandingServiceBase::getIdentifier() { - return service; -} - - -MessageQueueId_t CommandingServiceBase::getRequestQueue() { - return requestQueue->getId(); -} - - -ReturnValue_t CommandingServiceBase::initialize() { - ReturnValue_t result = SystemObject::initialize(); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - if(packetDestination == objects::NO_OBJECT) { - packetDestination = defaultPacketDestination; - } - AcceptsTelemetryIF* packetForwarding = - objectManager->get(packetDestination); - - if(packetSource == objects::NO_OBJECT) { - packetSource = defaultPacketSource; - } - PUSDistributorIF* distributor = objectManager->get( - packetSource); - - if (packetForwarding == nullptr or distributor == nullptr) { - sif::error << "CommandingServiceBase::intialize: Packet source or " - "packet destination invalid!" << std::endl; - return ObjectManagerIF::CHILD_INIT_FAILED; - } - - distributor->registerService(this); - requestQueue->setDefaultDestination( - packetForwarding->getReportReceptionQueue()); - - IPCStore = objectManager->get(objects::IPC_STORE); - TCStore = objectManager->get(objects::TC_STORE); - - if (IPCStore == nullptr or TCStore == nullptr) { - sif::error << "CommandingServiceBase::intialize: IPC store or TC store " - "not initialized yet!" << std::endl; - return ObjectManagerIF::CHILD_INIT_FAILED; - } - - return RETURN_OK; - -} - -void CommandingServiceBase::handleCommandQueue() { - CommandMessage reply; - ReturnValue_t result = RETURN_FAILED; - for (result = commandQueue->receiveMessage(&reply); result == RETURN_OK; - result = commandQueue->receiveMessage(&reply)) { - handleCommandMessage(&reply); - } -} - - -void CommandingServiceBase::handleCommandMessage(CommandMessage* reply) { - bool isStep = false; - CommandMessage nextCommand; - CommandMapIter iter = commandMap.find(reply->getSender()); - - // handle unrequested reply first - if (reply->getSender() == MessageQueueIF::NO_QUEUE or - iter == commandMap.end()) { - handleUnrequestedReply(reply); - return; - } - nextCommand.setCommand(CommandMessage::CMD_NONE); - - - // Implemented by child class, specifies what to do with reply. - ReturnValue_t result = handleReply(reply, iter->command, &iter->state, - &nextCommand, iter->objectId, &isStep); - - /* If the child implementation does not implement special handling for - * rejected replies (RETURN_FAILED or INVALID_REPLY is returned), a - * failure verification will be generated with the reason as the - * return code and the initial command as failure parameter 1 */ - if((reply->getCommand() == CommandMessage::REPLY_REJECTED) and - (result == RETURN_FAILED or result == INVALID_REPLY)) { - result = reply->getReplyRejectedReason(); - failureParameter1 = iter->command; - } - - switch (result) { - case EXECUTION_COMPLETE: - case RETURN_OK: - case NO_STEP_MESSAGE: - // handle result of reply handler implemented by developer. - handleReplyHandlerResult(result, iter, &nextCommand, reply, isStep); - break; - case INVALID_REPLY: - //might be just an unrequested reply at a bad moment - handleUnrequestedReply(reply); - break; - default: - if (isStep) { - verificationReporter.sendFailureReport( - TC_VERIFY::PROGRESS_FAILURE, iter->tcInfo.ackFlags, - iter->tcInfo.tcPacketId, iter->tcInfo.tcSequenceControl, - result, ++iter->step, failureParameter1, - failureParameter2); - } else { - verificationReporter.sendFailureReport( - TC_VERIFY::COMPLETION_FAILURE, iter->tcInfo.ackFlags, - iter->tcInfo.tcPacketId, iter->tcInfo.tcSequenceControl, - result, 0, failureParameter1, failureParameter2); - } - failureParameter1 = 0; - failureParameter2 = 0; - checkAndExecuteFifo(iter); - break; - } - -} - -void CommandingServiceBase::handleReplyHandlerResult(ReturnValue_t result, - CommandMapIter iter, CommandMessage* nextCommand, - CommandMessage* reply, bool& isStep) { - iter->command = nextCommand->getCommand(); - - // In case a new command is to be sent immediately, this is performed here. - // If no new command is sent, only analyse reply result by initializing - // sendResult as RETURN_OK - ReturnValue_t sendResult = RETURN_OK; - if (nextCommand->getCommand() != CommandMessage::CMD_NONE) { - sendResult = commandQueue->sendMessage(reply->getSender(), - nextCommand); - } - - if (sendResult == RETURN_OK) { - if (isStep and result != NO_STEP_MESSAGE) { - verificationReporter.sendSuccessReport( - TC_VERIFY::PROGRESS_SUCCESS, - iter->tcInfo.ackFlags, iter->tcInfo.tcPacketId, - iter->tcInfo.tcSequenceControl, ++iter->step); - } - else { - verificationReporter.sendSuccessReport( - TC_VERIFY::COMPLETION_SUCCESS, - iter->tcInfo.ackFlags, iter->tcInfo.tcPacketId, - iter->tcInfo.tcSequenceControl, 0); - checkAndExecuteFifo(iter); - } - } - else { - if (isStep) { - nextCommand->clearCommandMessage(); - verificationReporter.sendFailureReport( - TC_VERIFY::PROGRESS_FAILURE, iter->tcInfo.ackFlags, - iter->tcInfo.tcPacketId, - iter->tcInfo.tcSequenceControl, sendResult, - ++iter->step, failureParameter1, failureParameter2); - } else { - nextCommand->clearCommandMessage(); - verificationReporter.sendFailureReport( - TC_VERIFY::COMPLETION_FAILURE, - iter->tcInfo.ackFlags, iter->tcInfo.tcPacketId, - iter->tcInfo.tcSequenceControl, sendResult, 0, - failureParameter1, failureParameter2); - } - failureParameter1 = 0; - failureParameter2 = 0; - checkAndExecuteFifo(iter); - } -} - -void CommandingServiceBase::handleRequestQueue() { - TmTcMessage message; - ReturnValue_t result; - store_address_t address; - TcPacketStored packet; - MessageQueueId_t queue; - object_id_t objectId; - for (result = requestQueue->receiveMessage(&message); result == RETURN_OK; - result = requestQueue->receiveMessage(&message)) { - address = message.getStorageId(); - packet.setStoreAddress(address); - - if ((packet.getSubService() == 0) - or (isValidSubservice(packet.getSubService()) != RETURN_OK)) { - rejectPacket(TC_VERIFY::START_FAILURE, &packet, INVALID_SUBSERVICE); - continue; - } - result = getMessageQueueAndObject(packet.getSubService(), - packet.getApplicationData(), packet.getApplicationDataSize(), - &queue, &objectId); - if (result != HasReturnvaluesIF::RETURN_OK) { - rejectPacket(TC_VERIFY::START_FAILURE, &packet, result); - continue; - } - - //Is a command already active for the target object? - CommandMapIter iter; - iter = commandMap.find(queue); - - if (iter != commandMap.end()) { - result = iter->fifo.insert(address); - if (result != RETURN_OK) { - rejectPacket(TC_VERIFY::START_FAILURE, &packet, OBJECT_BUSY); - } - } else { - CommandInfo newInfo; //Info will be set by startExecution if neccessary - newInfo.objectId = objectId; - result = commandMap.insert(queue, newInfo, &iter); - if (result != RETURN_OK) { - rejectPacket(TC_VERIFY::START_FAILURE, &packet, BUSY); - } else { - startExecution(&packet, iter); - } - } - - } -} - - -ReturnValue_t CommandingServiceBase::sendTmPacket(uint8_t subservice, - const uint8_t* data, size_t dataLen, const uint8_t* headerData, - size_t headerSize) { - TmPacketStored tmPacketStored(this->apid, this->service, subservice, - this->tmPacketCounter, data, dataLen, headerData, headerSize); - ReturnValue_t result = tmPacketStored.sendPacket( - requestQueue->getDefaultDestination(), requestQueue->getId()); - if (result == HasReturnvaluesIF::RETURN_OK) { - this->tmPacketCounter++; - } - return result; -} - - -ReturnValue_t CommandingServiceBase::sendTmPacket(uint8_t subservice, - object_id_t objectId, const uint8_t *data, size_t dataLen) { - uint8_t buffer[sizeof(object_id_t)]; - uint8_t* pBuffer = buffer; - size_t size = 0; - SerializeAdapter::serialize(&objectId, &pBuffer, &size, - sizeof(object_id_t), SerializeIF::Endianness::BIG); - TmPacketStored tmPacketStored(this->apid, this->service, subservice, - this->tmPacketCounter, data, dataLen, buffer, size); - ReturnValue_t result = tmPacketStored.sendPacket( - requestQueue->getDefaultDestination(), requestQueue->getId()); - if (result == HasReturnvaluesIF::RETURN_OK) { - this->tmPacketCounter++; - } - return result; -} - - -ReturnValue_t CommandingServiceBase::sendTmPacket(uint8_t subservice, - SerializeIF* content, SerializeIF* header) { - TmPacketStored tmPacketStored(this->apid, this->service, subservice, - this->tmPacketCounter, content, header); - ReturnValue_t result = tmPacketStored.sendPacket( - requestQueue->getDefaultDestination(), requestQueue->getId()); - if (result == HasReturnvaluesIF::RETURN_OK) { - this->tmPacketCounter++; - } - return result; -} - - -void CommandingServiceBase::startExecution(TcPacketStored *storedPacket, - CommandMapIter iter) { - ReturnValue_t result = RETURN_OK; - CommandMessage command; - iter->subservice = storedPacket->getSubService(); - result = prepareCommand(&command, iter->subservice, - storedPacket->getApplicationData(), - storedPacket->getApplicationDataSize(), &iter->state, - iter->objectId); - - ReturnValue_t sendResult = RETURN_OK; - switch (result) { - case RETURN_OK: - if (command.getCommand() != CommandMessage::CMD_NONE) { - sendResult = commandQueue->sendMessage(iter.value->first, - &command); - } - if (sendResult == RETURN_OK) { - Clock::getUptime(&iter->uptimeOfStart); - iter->step = 0; - iter->subservice = storedPacket->getSubService(); - iter->command = command.getCommand(); - iter->tcInfo.ackFlags = storedPacket->getAcknowledgeFlags(); - iter->tcInfo.tcPacketId = storedPacket->getPacketId(); - iter->tcInfo.tcSequenceControl = - storedPacket->getPacketSequenceControl(); - acceptPacket(TC_VERIFY::START_SUCCESS, storedPacket); - } else { - command.clearCommandMessage(); - rejectPacket(TC_VERIFY::START_FAILURE, storedPacket, sendResult); - checkAndExecuteFifo(iter); - } - break; - case EXECUTION_COMPLETE: - if (command.getCommand() != CommandMessage::CMD_NONE) { - //Fire-and-forget command. - sendResult = commandQueue->sendMessage(iter.value->first, - &command); - } - if (sendResult == RETURN_OK) { - verificationReporter.sendSuccessReport(TC_VERIFY::START_SUCCESS, - storedPacket); - acceptPacket(TC_VERIFY::COMPLETION_SUCCESS, storedPacket); - checkAndExecuteFifo(iter); - } else { - command.clearCommandMessage(); - rejectPacket(TC_VERIFY::START_FAILURE, storedPacket, sendResult); - checkAndExecuteFifo(iter); - } - break; - default: - rejectPacket(TC_VERIFY::START_FAILURE, storedPacket, result); - checkAndExecuteFifo(iter); - break; - } -} - - -void CommandingServiceBase::rejectPacket(uint8_t report_id, - TcPacketStored* packet, ReturnValue_t error_code) { - verificationReporter.sendFailureReport(report_id, packet, error_code); - packet->deletePacket(); -} - - -void CommandingServiceBase::acceptPacket(uint8_t reportId, - TcPacketStored* packet) { - verificationReporter.sendSuccessReport(reportId, packet); - packet->deletePacket(); -} - - -void CommandingServiceBase::checkAndExecuteFifo(CommandMapIter iter) { - store_address_t address; - if (iter->fifo.retrieve(&address) != RETURN_OK) { - commandMap.erase(&iter); - } else { - TcPacketStored newPacket(address); - startExecution(&newPacket, iter); - } -} - - -void CommandingServiceBase::handleUnrequestedReply(CommandMessage* reply) { - reply->clearCommandMessage(); -} - - -inline void CommandingServiceBase::doPeriodicOperation() { -} - -MessageQueueId_t CommandingServiceBase::getCommandQueue() { - return commandQueue->getId(); -} - -void CommandingServiceBase::checkTimeout() { - uint32_t uptime; - Clock::getUptime(&uptime); - CommandMapIter iter; - for (iter = commandMap.begin(); iter != commandMap.end(); ++iter) { - if ((iter->uptimeOfStart + (timeoutSeconds * 1000)) < uptime) { - verificationReporter.sendFailureReport( - TC_VERIFY::COMPLETION_FAILURE, iter->tcInfo.ackFlags, - iter->tcInfo.tcPacketId, iter->tcInfo.tcSequenceControl, - TIMEOUT); - checkAndExecuteFifo(iter); - } - } -} - -void CommandingServiceBase::setTaskIF(PeriodicTaskIF* task_) { - executingTask = task_; -} +#include "../tcdistribution/PUSDistributorIF.h" +#include "../tmtcservices/AcceptsTelemetryIF.h" +#include "../objectmanager/ObjectManagerIF.h" + +#include "../tmtcservices/CommandingServiceBase.h" +#include "../tmtcservices/TmTcMessage.h" +#include "../ipc/QueueFactory.h" +#include "../tmtcpacket/pus/TcPacketStored.h" +#include "../tmtcpacket/pus/TmPacketStored.h" + +object_id_t CommandingServiceBase::defaultPacketSource = objects::NO_OBJECT; +object_id_t CommandingServiceBase::defaultPacketDestination = objects::NO_OBJECT; + +CommandingServiceBase::CommandingServiceBase(object_id_t setObjectId, + uint16_t apid, uint8_t service, uint8_t numberOfParallelCommands, + uint16_t commandTimeoutSeconds, size_t queueDepth) : + SystemObject(setObjectId), apid(apid), service(service), + timeoutSeconds(commandTimeoutSeconds), + commandMap(numberOfParallelCommands) { + commandQueue = QueueFactory::instance()->createMessageQueue(queueDepth); + requestQueue = QueueFactory::instance()->createMessageQueue(queueDepth); +} + +void CommandingServiceBase::setPacketSource(object_id_t packetSource) { + this->packetSource = packetSource; +} + +void CommandingServiceBase::setPacketDestination( + object_id_t packetDestination) { + this->packetDestination = packetDestination; +} + + +CommandingServiceBase::~CommandingServiceBase() { + QueueFactory::instance()->deleteMessageQueue(commandQueue); + QueueFactory::instance()->deleteMessageQueue(requestQueue); +} + + +ReturnValue_t CommandingServiceBase::performOperation(uint8_t opCode) { + handleCommandQueue(); + handleRequestQueue(); + checkTimeout(); + doPeriodicOperation(); + return RETURN_OK; +} + + +uint16_t CommandingServiceBase::getIdentifier() { + return service; +} + + +MessageQueueId_t CommandingServiceBase::getRequestQueue() { + return requestQueue->getId(); +} + + +ReturnValue_t CommandingServiceBase::initialize() { + ReturnValue_t result = SystemObject::initialize(); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + if(packetDestination == objects::NO_OBJECT) { + packetDestination = defaultPacketDestination; + } + AcceptsTelemetryIF* packetForwarding = + objectManager->get(packetDestination); + + if(packetSource == objects::NO_OBJECT) { + packetSource = defaultPacketSource; + } + PUSDistributorIF* distributor = objectManager->get( + packetSource); + + if (packetForwarding == nullptr or distributor == nullptr) { + sif::error << "CommandingServiceBase::intialize: Packet source or " + "packet destination invalid!" << std::endl; + return ObjectManagerIF::CHILD_INIT_FAILED; + } + + distributor->registerService(this); + requestQueue->setDefaultDestination( + packetForwarding->getReportReceptionQueue()); + + IPCStore = objectManager->get(objects::IPC_STORE); + TCStore = objectManager->get(objects::TC_STORE); + + if (IPCStore == nullptr or TCStore == nullptr) { + sif::error << "CommandingServiceBase::intialize: IPC store or TC store " + "not initialized yet!" << std::endl; + return ObjectManagerIF::CHILD_INIT_FAILED; + } + + return RETURN_OK; + +} + +void CommandingServiceBase::handleCommandQueue() { + CommandMessage reply; + ReturnValue_t result = RETURN_FAILED; + for (result = commandQueue->receiveMessage(&reply); result == RETURN_OK; + result = commandQueue->receiveMessage(&reply)) { + handleCommandMessage(&reply); + } +} + + +void CommandingServiceBase::handleCommandMessage(CommandMessage* reply) { + bool isStep = false; + CommandMessage nextCommand; + CommandMapIter iter = commandMap.find(reply->getSender()); + + // handle unrequested reply first + if (reply->getSender() == MessageQueueIF::NO_QUEUE or + iter == commandMap.end()) { + handleUnrequestedReply(reply); + return; + } + nextCommand.setCommand(CommandMessage::CMD_NONE); + + + // Implemented by child class, specifies what to do with reply. + ReturnValue_t result = handleReply(reply, iter->command, &iter->state, + &nextCommand, iter->objectId, &isStep); + + /* If the child implementation does not implement special handling for + * rejected replies (RETURN_FAILED or INVALID_REPLY is returned), a + * failure verification will be generated with the reason as the + * return code and the initial command as failure parameter 1 */ + if((reply->getCommand() == CommandMessage::REPLY_REJECTED) and + (result == RETURN_FAILED or result == INVALID_REPLY)) { + result = reply->getReplyRejectedReason(); + failureParameter1 = iter->command; + } + + switch (result) { + case EXECUTION_COMPLETE: + case RETURN_OK: + case NO_STEP_MESSAGE: + // handle result of reply handler implemented by developer. + handleReplyHandlerResult(result, iter, &nextCommand, reply, isStep); + break; + case INVALID_REPLY: + //might be just an unrequested reply at a bad moment + handleUnrequestedReply(reply); + break; + default: + if (isStep) { + verificationReporter.sendFailureReport( + TC_VERIFY::PROGRESS_FAILURE, iter->tcInfo.ackFlags, + iter->tcInfo.tcPacketId, iter->tcInfo.tcSequenceControl, + result, ++iter->step, failureParameter1, + failureParameter2); + } else { + verificationReporter.sendFailureReport( + TC_VERIFY::COMPLETION_FAILURE, iter->tcInfo.ackFlags, + iter->tcInfo.tcPacketId, iter->tcInfo.tcSequenceControl, + result, 0, failureParameter1, failureParameter2); + } + failureParameter1 = 0; + failureParameter2 = 0; + checkAndExecuteFifo(iter); + break; + } + +} + +void CommandingServiceBase::handleReplyHandlerResult(ReturnValue_t result, + CommandMapIter iter, CommandMessage* nextCommand, + CommandMessage* reply, bool& isStep) { + iter->command = nextCommand->getCommand(); + + // In case a new command is to be sent immediately, this is performed here. + // If no new command is sent, only analyse reply result by initializing + // sendResult as RETURN_OK + ReturnValue_t sendResult = RETURN_OK; + if (nextCommand->getCommand() != CommandMessage::CMD_NONE) { + sendResult = commandQueue->sendMessage(reply->getSender(), + nextCommand); + } + + if (sendResult == RETURN_OK) { + if (isStep and result != NO_STEP_MESSAGE) { + verificationReporter.sendSuccessReport( + TC_VERIFY::PROGRESS_SUCCESS, + iter->tcInfo.ackFlags, iter->tcInfo.tcPacketId, + iter->tcInfo.tcSequenceControl, ++iter->step); + } + else { + verificationReporter.sendSuccessReport( + TC_VERIFY::COMPLETION_SUCCESS, + iter->tcInfo.ackFlags, iter->tcInfo.tcPacketId, + iter->tcInfo.tcSequenceControl, 0); + checkAndExecuteFifo(iter); + } + } + else { + if (isStep) { + nextCommand->clearCommandMessage(); + verificationReporter.sendFailureReport( + TC_VERIFY::PROGRESS_FAILURE, iter->tcInfo.ackFlags, + iter->tcInfo.tcPacketId, + iter->tcInfo.tcSequenceControl, sendResult, + ++iter->step, failureParameter1, failureParameter2); + } else { + nextCommand->clearCommandMessage(); + verificationReporter.sendFailureReport( + TC_VERIFY::COMPLETION_FAILURE, + iter->tcInfo.ackFlags, iter->tcInfo.tcPacketId, + iter->tcInfo.tcSequenceControl, sendResult, 0, + failureParameter1, failureParameter2); + } + failureParameter1 = 0; + failureParameter2 = 0; + checkAndExecuteFifo(iter); + } +} + +void CommandingServiceBase::handleRequestQueue() { + TmTcMessage message; + ReturnValue_t result; + store_address_t address; + TcPacketStored packet; + MessageQueueId_t queue; + object_id_t objectId; + for (result = requestQueue->receiveMessage(&message); result == RETURN_OK; + result = requestQueue->receiveMessage(&message)) { + address = message.getStorageId(); + packet.setStoreAddress(address); + + if ((packet.getSubService() == 0) + or (isValidSubservice(packet.getSubService()) != RETURN_OK)) { + rejectPacket(TC_VERIFY::START_FAILURE, &packet, INVALID_SUBSERVICE); + continue; + } + result = getMessageQueueAndObject(packet.getSubService(), + packet.getApplicationData(), packet.getApplicationDataSize(), + &queue, &objectId); + if (result != HasReturnvaluesIF::RETURN_OK) { + rejectPacket(TC_VERIFY::START_FAILURE, &packet, result); + continue; + } + + //Is a command already active for the target object? + CommandMapIter iter; + iter = commandMap.find(queue); + + if (iter != commandMap.end()) { + result = iter->fifo.insert(address); + if (result != RETURN_OK) { + rejectPacket(TC_VERIFY::START_FAILURE, &packet, OBJECT_BUSY); + } + } else { + CommandInfo newInfo; //Info will be set by startExecution if neccessary + newInfo.objectId = objectId; + result = commandMap.insert(queue, newInfo, &iter); + if (result != RETURN_OK) { + rejectPacket(TC_VERIFY::START_FAILURE, &packet, BUSY); + } else { + startExecution(&packet, iter); + } + } + + } +} + + +ReturnValue_t CommandingServiceBase::sendTmPacket(uint8_t subservice, + const uint8_t* data, size_t dataLen, const uint8_t* headerData, + size_t headerSize) { + TmPacketStored tmPacketStored(this->apid, this->service, subservice, + this->tmPacketCounter, data, dataLen, headerData, headerSize); + ReturnValue_t result = tmPacketStored.sendPacket( + requestQueue->getDefaultDestination(), requestQueue->getId()); + if (result == HasReturnvaluesIF::RETURN_OK) { + this->tmPacketCounter++; + } + return result; +} + + +ReturnValue_t CommandingServiceBase::sendTmPacket(uint8_t subservice, + object_id_t objectId, const uint8_t *data, size_t dataLen) { + uint8_t buffer[sizeof(object_id_t)]; + uint8_t* pBuffer = buffer; + size_t size = 0; + SerializeAdapter::serialize(&objectId, &pBuffer, &size, + sizeof(object_id_t), SerializeIF::Endianness::BIG); + TmPacketStored tmPacketStored(this->apid, this->service, subservice, + this->tmPacketCounter, data, dataLen, buffer, size); + ReturnValue_t result = tmPacketStored.sendPacket( + requestQueue->getDefaultDestination(), requestQueue->getId()); + if (result == HasReturnvaluesIF::RETURN_OK) { + this->tmPacketCounter++; + } + return result; +} + + +ReturnValue_t CommandingServiceBase::sendTmPacket(uint8_t subservice, + SerializeIF* content, SerializeIF* header) { + TmPacketStored tmPacketStored(this->apid, this->service, subservice, + this->tmPacketCounter, content, header); + ReturnValue_t result = tmPacketStored.sendPacket( + requestQueue->getDefaultDestination(), requestQueue->getId()); + if (result == HasReturnvaluesIF::RETURN_OK) { + this->tmPacketCounter++; + } + return result; +} + + +void CommandingServiceBase::startExecution(TcPacketStored *storedPacket, + CommandMapIter iter) { + ReturnValue_t result = RETURN_OK; + CommandMessage command; + iter->subservice = storedPacket->getSubService(); + result = prepareCommand(&command, iter->subservice, + storedPacket->getApplicationData(), + storedPacket->getApplicationDataSize(), &iter->state, + iter->objectId); + + ReturnValue_t sendResult = RETURN_OK; + switch (result) { + case RETURN_OK: + if (command.getCommand() != CommandMessage::CMD_NONE) { + sendResult = commandQueue->sendMessage(iter.value->first, + &command); + } + if (sendResult == RETURN_OK) { + Clock::getUptime(&iter->uptimeOfStart); + iter->step = 0; + iter->subservice = storedPacket->getSubService(); + iter->command = command.getCommand(); + iter->tcInfo.ackFlags = storedPacket->getAcknowledgeFlags(); + iter->tcInfo.tcPacketId = storedPacket->getPacketId(); + iter->tcInfo.tcSequenceControl = + storedPacket->getPacketSequenceControl(); + acceptPacket(TC_VERIFY::START_SUCCESS, storedPacket); + } else { + command.clearCommandMessage(); + rejectPacket(TC_VERIFY::START_FAILURE, storedPacket, sendResult); + checkAndExecuteFifo(iter); + } + break; + case EXECUTION_COMPLETE: + if (command.getCommand() != CommandMessage::CMD_NONE) { + //Fire-and-forget command. + sendResult = commandQueue->sendMessage(iter.value->first, + &command); + } + if (sendResult == RETURN_OK) { + verificationReporter.sendSuccessReport(TC_VERIFY::START_SUCCESS, + storedPacket); + acceptPacket(TC_VERIFY::COMPLETION_SUCCESS, storedPacket); + checkAndExecuteFifo(iter); + } else { + command.clearCommandMessage(); + rejectPacket(TC_VERIFY::START_FAILURE, storedPacket, sendResult); + checkAndExecuteFifo(iter); + } + break; + default: + rejectPacket(TC_VERIFY::START_FAILURE, storedPacket, result); + checkAndExecuteFifo(iter); + break; + } +} + + +void CommandingServiceBase::rejectPacket(uint8_t report_id, + TcPacketStored* packet, ReturnValue_t error_code) { + verificationReporter.sendFailureReport(report_id, packet, error_code); + packet->deletePacket(); +} + + +void CommandingServiceBase::acceptPacket(uint8_t reportId, + TcPacketStored* packet) { + verificationReporter.sendSuccessReport(reportId, packet); + packet->deletePacket(); +} + + +void CommandingServiceBase::checkAndExecuteFifo(CommandMapIter iter) { + store_address_t address; + if (iter->fifo.retrieve(&address) != RETURN_OK) { + commandMap.erase(&iter); + } else { + TcPacketStored newPacket(address); + startExecution(&newPacket, iter); + } +} + + +void CommandingServiceBase::handleUnrequestedReply(CommandMessage* reply) { + reply->clearCommandMessage(); +} + + +inline void CommandingServiceBase::doPeriodicOperation() { +} + +MessageQueueId_t CommandingServiceBase::getCommandQueue() { + return commandQueue->getId(); +} + +void CommandingServiceBase::checkTimeout() { + uint32_t uptime; + Clock::getUptime(&uptime); + CommandMapIter iter; + for (iter = commandMap.begin(); iter != commandMap.end(); ++iter) { + if ((iter->uptimeOfStart + (timeoutSeconds * 1000)) < uptime) { + verificationReporter.sendFailureReport( + TC_VERIFY::COMPLETION_FAILURE, iter->tcInfo.ackFlags, + iter->tcInfo.tcPacketId, iter->tcInfo.tcSequenceControl, + TIMEOUT); + checkAndExecuteFifo(iter); + } + } +} + +void CommandingServiceBase::setTaskIF(PeriodicTaskIF* task_) { + executingTask = task_; +} diff --git a/tmtcservices/CommandingServiceBase.h b/tmtcservices/CommandingServiceBase.h index b3a15985..32173d81 100644 --- a/tmtcservices/CommandingServiceBase.h +++ b/tmtcservices/CommandingServiceBase.h @@ -1,348 +1,348 @@ -#ifndef FRAMEWORK_TMTCSERVICES_COMMANDINGSERVICEBASE_H_ -#define FRAMEWORK_TMTCSERVICES_COMMANDINGSERVICEBASE_H_ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -class TcPacketStored; - -namespace Factory{ -void setStaticFrameworkObjectIds(); -} - -/** - * @brief This class is the basis for all PUS Services, which have to - * relay Telecommands to software bus. - * - * It manages Telecommand reception and the generation of Verification Reports - * similar to PusServiceBase. This class is used if a telecommand can't be - * handled immediately and must be relayed to the internal software bus. - * - isValidSubservice - * - getMessageQueueAndObject - * - prepareCommand - * - handleReply - * @author gaisser - * @ingroup pus_services - */ -class CommandingServiceBase: public SystemObject, - public AcceptsTelecommandsIF, - public ExecutableObjectIF, - public HasReturnvaluesIF { - friend void (Factory::setStaticFrameworkObjectIds)(); -public: - static const uint8_t INTERFACE_ID = CLASS_ID::COMMAND_SERVICE_BASE; - static const ReturnValue_t EXECUTION_COMPLETE = MAKE_RETURN_CODE(1); - static const ReturnValue_t NO_STEP_MESSAGE = MAKE_RETURN_CODE(2); - static const ReturnValue_t OBJECT_BUSY = MAKE_RETURN_CODE(3); - static const ReturnValue_t BUSY = MAKE_RETURN_CODE(4); - static const ReturnValue_t INVALID_TC = MAKE_RETURN_CODE(5); - static const ReturnValue_t INVALID_OBJECT = MAKE_RETURN_CODE(6); - static const ReturnValue_t INVALID_REPLY = MAKE_RETURN_CODE(7); - - /** - * Class constructor. Initializes two important MessageQueues: - * commandQueue for command reception and requestQueue for device reception - * @param setObjectId - * @param apid - * @param service - * @param numberOfParallelCommands - * @param commandTimeout_seconds - * @param setPacketSource - * @param setPacketDestination - * @param queueDepth - */ - CommandingServiceBase(object_id_t setObjectId, uint16_t apid, - uint8_t service, uint8_t numberOfParallelCommands, - uint16_t commandTimeoutSeconds, size_t queueDepth = 20); - virtual ~CommandingServiceBase(); - - /** - * This setter can be used to set the packet source individually instead - * of using the default static framework ID set in the factory. - * This should be called at object initialization and not during run-time! - * @param packetSource - */ - void setPacketSource(object_id_t packetSource); - /** - * This setter can be used to set the packet destination individually - * instead of using the default static framework ID set in the factory. - * This should be called at object initialization and not during run-time! - * @param packetDestination - */ - void setPacketDestination(object_id_t packetDestination); - - /*** - * This is the periodically called function. - * Handle request queue for external commands. - * Handle command Queue for internal commands. - * @param opCode is unused here at the moment - * @return RETURN_OK - */ - virtual ReturnValue_t performOperation(uint8_t opCode) override; - - virtual uint16_t getIdentifier(); - - /** - * Returns the requestQueue MessageQueueId_t - * - * The requestQueue is the queue for external commands (TC) - * - * @return requestQueue messageQueueId_t - */ - virtual MessageQueueId_t getRequestQueue(); - - /** - * Returns the commandQueue MessageQueueId_t - * - * Remember the CommandQueue is the queue for internal communication - * @return commandQueue messageQueueId_t - */ - virtual MessageQueueId_t getCommandQueue(); - - virtual ReturnValue_t initialize() override; - - /** - * Implementation of ExecutableObjectIF function - * - * Used to setup the reference of the task, that executes this component - * @param task Pointer to the taskIF of this task - */ - virtual void setTaskIF(PeriodicTaskIF* task) override; - -protected: - /** - * Check the target subservice - * @param subservice[in] - * @return - * -@c RETURN_OK Subservice valid, continue message handling - * -@c INVALID_SUBSERVICE if service is not known, rejects packet. - */ - virtual ReturnValue_t isValidSubservice(uint8_t subservice) = 0; - - /** - * Once a TC Request is valid, the existence of the destination and its - * target interface is checked and retrieved. The target message queue ID - * can then be acquired by using the target interface. - * @param subservice - * @param tcData Application Data of TC Packet - * @param tcDataLen - * @param id MessageQueue ID is stored here - * @param objectId Object ID is extracted and stored here - * @return - * - @c RETURN_OK Cotinue message handling - * - @c RETURN_FAILED Reject the packet and generates a start failure - * verification - */ - virtual ReturnValue_t getMessageQueueAndObject(uint8_t subservice, - const uint8_t *tcData, size_t tcDataLen, MessageQueueId_t *id, - object_id_t *objectId) = 0; - - /** - * After the Message Queue and Object ID are determined, the command is - * prepared by using an implementation specific CommandMessage type - * which is sent to the target object. It contains all necessary information - * for the device to execute telecommands. - * @param message [out] message which can be set and is sent to the object - * @param subservice Subservice of the current communication - * @param tcData Application data of command - * @param tcDataLen Application data length - * @param state [out/in] Setable state of the communication. - * communication - * @param objectId Target object ID - * @return - * - @c RETURN_OK to generate a verification start message - * - @c EXECUTION_COMPELTE Fire-and-forget command. Generate a completion - * verification message. - * - @c Anything else rejects the packets and generates a start failure - * verification. - */ - virtual ReturnValue_t prepareCommand(CommandMessage* message, - uint8_t subservice, const uint8_t *tcData, size_t tcDataLen, - uint32_t *state, object_id_t objectId) = 0; - - /** - * This function is implemented by child services to specify how replies - * to a command from another software component are handled. - * @param reply - * This is the reply in form of a generic read-only command message. - * @param previousCommand - * Command_t of related command - * @param state [out/in] - * Additional parameter which can be used to pass state information. - * State of the communication - * @param optionalNextCommand [out] - * An optional next command which can be set in this function - * @param objectId Source object ID - * @param isStep Flag value to mark steps of command execution - * @return - * - @c RETURN_OK, @c EXECUTION_COMPLETE or @c NO_STEP_MESSAGE to - * generate TC verification success - * - @c INVALID_REPLY Calls handleUnrequestedReply - * - Anything else triggers a TC verification failure. If RETURN_FAILED or - * INVALID_REPLY is returned and the command ID is - * CommandMessage::REPLY_REJECTED, a failure verification message with - * the reason as the error parameter and the initial command as - * failure parameter 1 is generated. - */ - virtual ReturnValue_t handleReply(const CommandMessage* reply, - Command_t previousCommand, uint32_t *state, - CommandMessage* optionalNextCommand, object_id_t objectId, - bool *isStep) = 0; - - /** - * This function can be overidden to handle unrequested reply, - * when the reply sender ID is unknown or is not found is the command map. - * The default implementation will clear the command message and all - * its contents. - * @param reply - * Reply which is non-const so the default implementation can clear the - * message. - */ - virtual void handleUnrequestedReply(CommandMessage* reply); - - virtual void doPeriodicOperation(); - - - struct CommandInfo { - struct tcInfo { - uint8_t ackFlags; - uint16_t tcPacketId; - uint16_t tcSequenceControl; - } tcInfo; - uint32_t uptimeOfStart; - uint8_t step; - uint8_t subservice; - uint32_t state; - Command_t command; - object_id_t objectId; - FIFO fifo; - }; - - using CommandMapIter = FixedMap::Iterator; - - const uint16_t apid; - - const uint8_t service; - - const uint16_t timeoutSeconds; - - uint8_t tmPacketCounter = 0; - - StorageManagerIF *IPCStore = nullptr; - - StorageManagerIF *TCStore = nullptr; - - MessageQueueIF* commandQueue = nullptr; - - MessageQueueIF* requestQueue = nullptr; - - VerificationReporter verificationReporter; - - FixedMap commandMap; - - /* May be set be children to return a more precise failure condition. */ - uint32_t failureParameter1 = 0; - uint32_t failureParameter2 = 0; - - static object_id_t defaultPacketSource; - object_id_t packetSource = objects::NO_OBJECT; - static object_id_t defaultPacketDestination; - object_id_t packetDestination = objects::NO_OBJECT; - - /** - * Pointer to the task which executes this component, - * is invalid before setTaskIF was called. - */ - PeriodicTaskIF* executingTask = nullptr; - - /** - * @brief Send TM data from pointer to data. - * If a header is supplied it is added before data - * @param subservice Number of subservice - * @param data Pointer to the data in the Packet - * @param dataLen Lenght of data in the Packet - * @param headerData HeaderData will be placed before data - * @param headerSize Size of HeaderData - */ - ReturnValue_t sendTmPacket(uint8_t subservice, const uint8_t *data, - size_t dataLen, const uint8_t* headerData = nullptr, - size_t headerSize = 0); - - /** - * @brief To send TM packets of objects that still need to be serialized - * and consist of an object ID with appended data. - * @param subservice Number of subservice - * @param objectId ObjectId is placed before data - * @param data Data to append to the packet - * @param dataLen Length of Data - */ - ReturnValue_t sendTmPacket(uint8_t subservice, object_id_t objectId, - const uint8_t *data, size_t dataLen); - - /** - * @brief To send packets which are contained inside a class implementing - * SerializeIF. - * @param subservice Number of subservice - * @param content This is a pointer to the serialized packet - * @param header Serialize IF header which will be placed before content - */ - ReturnValue_t sendTmPacket(uint8_t subservice, SerializeIF* content, - SerializeIF* header = nullptr); - - void checkAndExecuteFifo(CommandMapIter iter); - -private: - /** - * This method handles internal execution of a command, - * once it has been started by @sa{startExecution()} in the request - * queue handler. - * It handles replies generated by the devices and relayed by the specific - * service implementation. This means that it determines further course of - * action depending on the return values specified in the service - * implementation. - * This includes the generation of TC verification messages. Note that - * the static framework object ID @c VerificationReporter::messageReceiver - * needs to be set. - * - TM[1,5] Step Successs - * - TM[1,6] Step Failure - * - TM[1,7] Completion Success - * - TM[1,8] Completion Failure - */ - void handleCommandQueue(); - - /** - * @brief Handler function for request queue - * @details - * Sequence of request queue handling: - * isValidSubservice -> getMessageQueueAndObject -> startExecution - * Generates a Start Success Reports TM[1,3] in subfunction - * @sa{startExecution()} or a Start Failure Report TM[1,4] by using the - * TC Verification Service. - */ - void handleRequestQueue(); - - void rejectPacket(uint8_t reportId, TcPacketStored* packet, - ReturnValue_t errorCode); - - void acceptPacket(uint8_t reportId, TcPacketStored* packet); - - void startExecution(TcPacketStored *storedPacket, CommandMapIter iter); - - void handleCommandMessage(CommandMessage* reply); - void handleReplyHandlerResult(ReturnValue_t result, CommandMapIter iter, - CommandMessage* nextCommand, CommandMessage* reply, bool& isStep); - - void checkTimeout(); -}; - -#endif /* COMMANDINGSERVICEBASE_H_ */ +#ifndef FRAMEWORK_TMTCSERVICES_COMMANDINGSERVICEBASE_H_ +#define FRAMEWORK_TMTCSERVICES_COMMANDINGSERVICEBASE_H_ + +#include "../objectmanager/SystemObject.h" +#include "../storagemanager/StorageManagerIF.h" +#include "../tasks/ExecutableObjectIF.h" +#include "../ipc/MessageQueueIF.h" +#include "../tmtcservices/AcceptsTelecommandsIF.h" + +#include "../tmtcservices/VerificationReporter.h" +#include "../ipc/CommandMessage.h" +#include "../container/FixedMap.h" +#include "../container/FIFO.h" +#include "../serialize/SerializeIF.h" + +class TcPacketStored; + +namespace Factory{ +void setStaticFrameworkObjectIds(); +} + +/** + * @brief This class is the basis for all PUS Services, which have to + * relay Telecommands to software bus. + * + * It manages Telecommand reception and the generation of Verification Reports + * similar to PusServiceBase. This class is used if a telecommand can't be + * handled immediately and must be relayed to the internal software bus. + * - isValidSubservice + * - getMessageQueueAndObject + * - prepareCommand + * - handleReply + * @author gaisser + * @ingroup pus_services + */ +class CommandingServiceBase: public SystemObject, + public AcceptsTelecommandsIF, + public ExecutableObjectIF, + public HasReturnvaluesIF { + friend void (Factory::setStaticFrameworkObjectIds)(); +public: + static const uint8_t INTERFACE_ID = CLASS_ID::COMMAND_SERVICE_BASE; + static const ReturnValue_t EXECUTION_COMPLETE = MAKE_RETURN_CODE(1); + static const ReturnValue_t NO_STEP_MESSAGE = MAKE_RETURN_CODE(2); + static const ReturnValue_t OBJECT_BUSY = MAKE_RETURN_CODE(3); + static const ReturnValue_t BUSY = MAKE_RETURN_CODE(4); + static const ReturnValue_t INVALID_TC = MAKE_RETURN_CODE(5); + static const ReturnValue_t INVALID_OBJECT = MAKE_RETURN_CODE(6); + static const ReturnValue_t INVALID_REPLY = MAKE_RETURN_CODE(7); + + /** + * Class constructor. Initializes two important MessageQueues: + * commandQueue for command reception and requestQueue for device reception + * @param setObjectId + * @param apid + * @param service + * @param numberOfParallelCommands + * @param commandTimeout_seconds + * @param setPacketSource + * @param setPacketDestination + * @param queueDepth + */ + CommandingServiceBase(object_id_t setObjectId, uint16_t apid, + uint8_t service, uint8_t numberOfParallelCommands, + uint16_t commandTimeoutSeconds, size_t queueDepth = 20); + virtual ~CommandingServiceBase(); + + /** + * This setter can be used to set the packet source individually instead + * of using the default static framework ID set in the factory. + * This should be called at object initialization and not during run-time! + * @param packetSource + */ + void setPacketSource(object_id_t packetSource); + /** + * This setter can be used to set the packet destination individually + * instead of using the default static framework ID set in the factory. + * This should be called at object initialization and not during run-time! + * @param packetDestination + */ + void setPacketDestination(object_id_t packetDestination); + + /*** + * This is the periodically called function. + * Handle request queue for external commands. + * Handle command Queue for internal commands. + * @param opCode is unused here at the moment + * @return RETURN_OK + */ + virtual ReturnValue_t performOperation(uint8_t opCode) override; + + virtual uint16_t getIdentifier(); + + /** + * Returns the requestQueue MessageQueueId_t + * + * The requestQueue is the queue for external commands (TC) + * + * @return requestQueue messageQueueId_t + */ + virtual MessageQueueId_t getRequestQueue(); + + /** + * Returns the commandQueue MessageQueueId_t + * + * Remember the CommandQueue is the queue for internal communication + * @return commandQueue messageQueueId_t + */ + virtual MessageQueueId_t getCommandQueue(); + + virtual ReturnValue_t initialize() override; + + /** + * Implementation of ExecutableObjectIF function + * + * Used to setup the reference of the task, that executes this component + * @param task Pointer to the taskIF of this task + */ + virtual void setTaskIF(PeriodicTaskIF* task) override; + +protected: + /** + * Check the target subservice + * @param subservice[in] + * @return + * -@c RETURN_OK Subservice valid, continue message handling + * -@c INVALID_SUBSERVICE if service is not known, rejects packet. + */ + virtual ReturnValue_t isValidSubservice(uint8_t subservice) = 0; + + /** + * Once a TC Request is valid, the existence of the destination and its + * target interface is checked and retrieved. The target message queue ID + * can then be acquired by using the target interface. + * @param subservice + * @param tcData Application Data of TC Packet + * @param tcDataLen + * @param id MessageQueue ID is stored here + * @param objectId Object ID is extracted and stored here + * @return + * - @c RETURN_OK Cotinue message handling + * - @c RETURN_FAILED Reject the packet and generates a start failure + * verification + */ + virtual ReturnValue_t getMessageQueueAndObject(uint8_t subservice, + const uint8_t *tcData, size_t tcDataLen, MessageQueueId_t *id, + object_id_t *objectId) = 0; + + /** + * After the Message Queue and Object ID are determined, the command is + * prepared by using an implementation specific CommandMessage type + * which is sent to the target object. It contains all necessary information + * for the device to execute telecommands. + * @param message [out] message which can be set and is sent to the object + * @param subservice Subservice of the current communication + * @param tcData Application data of command + * @param tcDataLen Application data length + * @param state [out/in] Setable state of the communication. + * communication + * @param objectId Target object ID + * @return + * - @c RETURN_OK to generate a verification start message + * - @c EXECUTION_COMPELTE Fire-and-forget command. Generate a completion + * verification message. + * - @c Anything else rejects the packets and generates a start failure + * verification. + */ + virtual ReturnValue_t prepareCommand(CommandMessage* message, + uint8_t subservice, const uint8_t *tcData, size_t tcDataLen, + uint32_t *state, object_id_t objectId) = 0; + + /** + * This function is implemented by child services to specify how replies + * to a command from another software component are handled. + * @param reply + * This is the reply in form of a generic read-only command message. + * @param previousCommand + * Command_t of related command + * @param state [out/in] + * Additional parameter which can be used to pass state information. + * State of the communication + * @param optionalNextCommand [out] + * An optional next command which can be set in this function + * @param objectId Source object ID + * @param isStep Flag value to mark steps of command execution + * @return + * - @c RETURN_OK, @c EXECUTION_COMPLETE or @c NO_STEP_MESSAGE to + * generate TC verification success + * - @c INVALID_REPLY Calls handleUnrequestedReply + * - Anything else triggers a TC verification failure. If RETURN_FAILED or + * INVALID_REPLY is returned and the command ID is + * CommandMessage::REPLY_REJECTED, a failure verification message with + * the reason as the error parameter and the initial command as + * failure parameter 1 is generated. + */ + virtual ReturnValue_t handleReply(const CommandMessage* reply, + Command_t previousCommand, uint32_t *state, + CommandMessage* optionalNextCommand, object_id_t objectId, + bool *isStep) = 0; + + /** + * This function can be overidden to handle unrequested reply, + * when the reply sender ID is unknown or is not found is the command map. + * The default implementation will clear the command message and all + * its contents. + * @param reply + * Reply which is non-const so the default implementation can clear the + * message. + */ + virtual void handleUnrequestedReply(CommandMessage* reply); + + virtual void doPeriodicOperation(); + + + struct CommandInfo { + struct tcInfo { + uint8_t ackFlags; + uint16_t tcPacketId; + uint16_t tcSequenceControl; + } tcInfo; + uint32_t uptimeOfStart; + uint8_t step; + uint8_t subservice; + uint32_t state; + Command_t command; + object_id_t objectId; + FIFO fifo; + }; + + using CommandMapIter = FixedMap::Iterator; + + const uint16_t apid; + + const uint8_t service; + + const uint16_t timeoutSeconds; + + uint8_t tmPacketCounter = 0; + + StorageManagerIF *IPCStore = nullptr; + + StorageManagerIF *TCStore = nullptr; + + MessageQueueIF* commandQueue = nullptr; + + MessageQueueIF* requestQueue = nullptr; + + VerificationReporter verificationReporter; + + FixedMap commandMap; + + /* May be set be children to return a more precise failure condition. */ + uint32_t failureParameter1 = 0; + uint32_t failureParameter2 = 0; + + static object_id_t defaultPacketSource; + object_id_t packetSource = objects::NO_OBJECT; + static object_id_t defaultPacketDestination; + object_id_t packetDestination = objects::NO_OBJECT; + + /** + * Pointer to the task which executes this component, + * is invalid before setTaskIF was called. + */ + PeriodicTaskIF* executingTask = nullptr; + + /** + * @brief Send TM data from pointer to data. + * If a header is supplied it is added before data + * @param subservice Number of subservice + * @param data Pointer to the data in the Packet + * @param dataLen Lenght of data in the Packet + * @param headerData HeaderData will be placed before data + * @param headerSize Size of HeaderData + */ + ReturnValue_t sendTmPacket(uint8_t subservice, const uint8_t *data, + size_t dataLen, const uint8_t* headerData = nullptr, + size_t headerSize = 0); + + /** + * @brief To send TM packets of objects that still need to be serialized + * and consist of an object ID with appended data. + * @param subservice Number of subservice + * @param objectId ObjectId is placed before data + * @param data Data to append to the packet + * @param dataLen Length of Data + */ + ReturnValue_t sendTmPacket(uint8_t subservice, object_id_t objectId, + const uint8_t *data, size_t dataLen); + + /** + * @brief To send packets which are contained inside a class implementing + * SerializeIF. + * @param subservice Number of subservice + * @param content This is a pointer to the serialized packet + * @param header Serialize IF header which will be placed before content + */ + ReturnValue_t sendTmPacket(uint8_t subservice, SerializeIF* content, + SerializeIF* header = nullptr); + + void checkAndExecuteFifo(CommandMapIter iter); + +private: + /** + * This method handles internal execution of a command, + * once it has been started by @sa{startExecution()} in the request + * queue handler. + * It handles replies generated by the devices and relayed by the specific + * service implementation. This means that it determines further course of + * action depending on the return values specified in the service + * implementation. + * This includes the generation of TC verification messages. Note that + * the static framework object ID @c VerificationReporter::messageReceiver + * needs to be set. + * - TM[1,5] Step Successs + * - TM[1,6] Step Failure + * - TM[1,7] Completion Success + * - TM[1,8] Completion Failure + */ + void handleCommandQueue(); + + /** + * @brief Handler function for request queue + * @details + * Sequence of request queue handling: + * isValidSubservice -> getMessageQueueAndObject -> startExecution + * Generates a Start Success Reports TM[1,3] in subfunction + * @sa{startExecution()} or a Start Failure Report TM[1,4] by using the + * TC Verification Service. + */ + void handleRequestQueue(); + + void rejectPacket(uint8_t reportId, TcPacketStored* packet, + ReturnValue_t errorCode); + + void acceptPacket(uint8_t reportId, TcPacketStored* packet); + + void startExecution(TcPacketStored *storedPacket, CommandMapIter iter); + + void handleCommandMessage(CommandMessage* reply); + void handleReplyHandlerResult(ReturnValue_t result, CommandMapIter iter, + CommandMessage* nextCommand, CommandMessage* reply, bool& isStep); + + void checkTimeout(); +}; + +#endif /* COMMANDINGSERVICEBASE_H_ */ diff --git a/tmtcservices/PusParser.cpp b/tmtcservices/PusParser.cpp index 3dd34a84..f9a0fc57 100644 --- a/tmtcservices/PusParser.cpp +++ b/tmtcservices/PusParser.cpp @@ -1,114 +1,114 @@ -#include -#include - -PusParser::PusParser(uint16_t maxExpectedPusPackets, - bool storeSplitPackets): indexSizePairFIFO(maxExpectedPusPackets) { -} - -ReturnValue_t PusParser::parsePusPackets(const uint8_t *frame, - size_t frameSize) { - if(frame == nullptr or frameSize < 5) { - sif::error << "PusParser::parsePusPackets: Frame invalid!" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - - if(indexSizePairFIFO.full()) { - sif::error << "PusParser::parsePusPackets: FIFO is full!" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - - size_t lengthField = frame[4] << 8 | frame[5]; - - if(lengthField == 0) { - return NO_PACKET_FOUND; - } - - size_t packetSize = lengthField + 7; - // sif::debug << frameSize << std::endl; - // Size of a pus packet is the value in the packet length field plus 7. - if(packetSize > frameSize) { - if(storeSplitPackets) { - indexSizePairFIFO.insert(indexSizePair(0, frameSize)); - } - else { - sif::debug << "TcSerialPollingTask::readNextPacket: Next packet " - "larger than remaining frame," << std::endl; - sif::debug << "Throwing away packet. Detected packet size: " - << packetSize << std::endl; - } - return SPLIT_PACKET; - } - else { - indexSizePairFIFO.insert(indexSizePair(0, packetSize)); - if(packetSize == frameSize) { - return HasReturnvaluesIF::RETURN_OK; - } - } - - // packet size is smaller than frame size, parse for more packets. - return readMultiplePackets(frame, frameSize, packetSize); -} - -ReturnValue_t PusParser::readMultiplePackets(const uint8_t *frame, - size_t frameSize, size_t startIndex) { - while (startIndex < frameSize) { - ReturnValue_t result = readNextPacket(frame, frameSize, startIndex); - if(result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - } - return HasReturnvaluesIF::RETURN_OK; -} - -DynamicFIFO* PusParser::fifo(){ - return &indexSizePairFIFO; -} - -PusParser::indexSizePair PusParser::getNextFifoPair() { - indexSizePair nextIndexSizePair; - indexSizePairFIFO.retrieve(&nextIndexSizePair); - return nextIndexSizePair; -} - -ReturnValue_t PusParser::readNextPacket(const uint8_t *frame, - size_t frameSize, size_t& currentIndex) { - // sif::debug << startIndex << std::endl; - if(currentIndex + 5 > frameSize) { - currentIndex = frameSize; - return HasReturnvaluesIF::RETURN_OK; - } - - uint16_t lengthField = frame[currentIndex + 4] << 8 | - frame[currentIndex + 5]; - if(lengthField == 0) { - // It is assumed that no packet follows. - currentIndex = frameSize; - return HasReturnvaluesIF::RETURN_OK; - } - size_t nextPacketSize = lengthField + 7; - size_t remainingSize = frameSize - currentIndex; - if(nextPacketSize > remainingSize) - { - if(storeSplitPackets) { - indexSizePairFIFO.insert(indexSizePair(currentIndex, remainingSize)); - } - else { - sif::debug << "TcSerialPollingTask::readNextPacket: Next packet " - "larger than remaining frame," << std::endl; - sif::debug << "Throwing away packet. Detected packet size: " - << nextPacketSize << std::endl; - } - return SPLIT_PACKET; - } - - ReturnValue_t result = indexSizePairFIFO.insert(indexSizePair(currentIndex, - nextPacketSize)); - if (result != HasReturnvaluesIF::RETURN_OK) { - // FIFO full. - sif::debug << "PusParser: Issue inserting into start index size " - "FIFO, it is full!" << std::endl; - } - currentIndex += nextPacketSize; - - return result; -} +#include "../tmtcservices/PusParser.h" +#include "../serviceinterface/ServiceInterfaceStream.h" + +PusParser::PusParser(uint16_t maxExpectedPusPackets, + bool storeSplitPackets): indexSizePairFIFO(maxExpectedPusPackets) { +} + +ReturnValue_t PusParser::parsePusPackets(const uint8_t *frame, + size_t frameSize) { + if(frame == nullptr or frameSize < 5) { + sif::error << "PusParser::parsePusPackets: Frame invalid!" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + + if(indexSizePairFIFO.full()) { + sif::error << "PusParser::parsePusPackets: FIFO is full!" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + + size_t lengthField = frame[4] << 8 | frame[5]; + + if(lengthField == 0) { + return NO_PACKET_FOUND; + } + + size_t packetSize = lengthField + 7; + // sif::debug << frameSize << std::endl; + // Size of a pus packet is the value in the packet length field plus 7. + if(packetSize > frameSize) { + if(storeSplitPackets) { + indexSizePairFIFO.insert(indexSizePair(0, frameSize)); + } + else { + sif::debug << "TcSerialPollingTask::readNextPacket: Next packet " + "larger than remaining frame," << std::endl; + sif::debug << "Throwing away packet. Detected packet size: " + << packetSize << std::endl; + } + return SPLIT_PACKET; + } + else { + indexSizePairFIFO.insert(indexSizePair(0, packetSize)); + if(packetSize == frameSize) { + return HasReturnvaluesIF::RETURN_OK; + } + } + + // packet size is smaller than frame size, parse for more packets. + return readMultiplePackets(frame, frameSize, packetSize); +} + +ReturnValue_t PusParser::readMultiplePackets(const uint8_t *frame, + size_t frameSize, size_t startIndex) { + while (startIndex < frameSize) { + ReturnValue_t result = readNextPacket(frame, frameSize, startIndex); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + return HasReturnvaluesIF::RETURN_OK; +} + +DynamicFIFO* PusParser::fifo(){ + return &indexSizePairFIFO; +} + +PusParser::indexSizePair PusParser::getNextFifoPair() { + indexSizePair nextIndexSizePair; + indexSizePairFIFO.retrieve(&nextIndexSizePair); + return nextIndexSizePair; +} + +ReturnValue_t PusParser::readNextPacket(const uint8_t *frame, + size_t frameSize, size_t& currentIndex) { + // sif::debug << startIndex << std::endl; + if(currentIndex + 5 > frameSize) { + currentIndex = frameSize; + return HasReturnvaluesIF::RETURN_OK; + } + + uint16_t lengthField = frame[currentIndex + 4] << 8 | + frame[currentIndex + 5]; + if(lengthField == 0) { + // It is assumed that no packet follows. + currentIndex = frameSize; + return HasReturnvaluesIF::RETURN_OK; + } + size_t nextPacketSize = lengthField + 7; + size_t remainingSize = frameSize - currentIndex; + if(nextPacketSize > remainingSize) + { + if(storeSplitPackets) { + indexSizePairFIFO.insert(indexSizePair(currentIndex, remainingSize)); + } + else { + sif::debug << "TcSerialPollingTask::readNextPacket: Next packet " + "larger than remaining frame," << std::endl; + sif::debug << "Throwing away packet. Detected packet size: " + << nextPacketSize << std::endl; + } + return SPLIT_PACKET; + } + + ReturnValue_t result = indexSizePairFIFO.insert(indexSizePair(currentIndex, + nextPacketSize)); + if (result != HasReturnvaluesIF::RETURN_OK) { + // FIFO full. + sif::debug << "PusParser: Issue inserting into start index size " + "FIFO, it is full!" << std::endl; + } + currentIndex += nextPacketSize; + + return result; +} diff --git a/tmtcservices/PusParser.h b/tmtcservices/PusParser.h index d59673f6..24cba0c0 100644 --- a/tmtcservices/PusParser.h +++ b/tmtcservices/PusParser.h @@ -1,82 +1,82 @@ -#ifndef FRAMEWORK_TMTCSERVICES_PUSPARSER_H_ -#define FRAMEWORK_TMTCSERVICES_PUSPARSER_H_ - -#include -#include -#include - -/** - * @brief This small helper class scans a given buffer for PUS packets. - * Can be used if PUS packets are serialized in a tightly packed frame. - * @details - * The parser uses the payload length field of PUS packets to find - * the respective PUS packet sizes. - * - * The parser parses a buffer by taking a pointer and the maximum size to scan. - * If PUS packets are found, they are stored in a FIFO which stores pairs - * consisting of the index in the buffer and the respective packet sizes. - * - * If the parser detects split packets (which means that the size of the - * next packet is larger than the remaining size to scan), it can either - * store that split packet or throw away the packet. - */ -class PusParser { -public: - //! The first entry is the index inside the buffer while the second index - //! is the size of the PUS packet starting at that index. - using indexSizePair = std::pair; - - static constexpr uint8_t INTERFACE_ID = CLASS_ID::PUS_PARSER; - static constexpr ReturnValue_t NO_PACKET_FOUND = MAKE_RETURN_CODE(0x00); - static constexpr ReturnValue_t SPLIT_PACKET = MAKE_RETURN_CODE(0x01); - /** - * Parser constructor. - * @param maxExpectedPusPackets - * Maximum expected number of PUS packets. A good estimate is to divide - * the frame size by the minimum size of a PUS packet (12 bytes) - * @param storeSplitPackets - * Specifies whether split packets are also stored inside the FIFO, - * with the size being the remaining frame size. - */ - PusParser(uint16_t maxExpectedPusPackets, bool storeSplitPackets); - - /** - * Parse a given frame for PUS packets - * @param frame - * @param frameSize - * @return -@c NO_PACKET_FOUND if no packet was found. - */ - ReturnValue_t parsePusPackets(const uint8_t* frame, size_t frameSize); - - /** - * Accessor function to get a reference to the internal FIFO which - * stores pairs of indexi and packet sizes. This FIFO is filled - * by the parsePusPackets() function. - * @return - */ - DynamicFIFO* fifo(); - - /** - * Retrieve the next index and packet size pair from the FIFO. - * This also removed it from the FIFO. Please note that if the FIFO - * is empty, an empty pair will be returned. - * @return - */ - indexSizePair getNextFifoPair(); - -private: - /** A FIFO is used to store information about multiple PUS packets - * inside the receive buffer. The maximum number of entries is defined - * by the first constructor argument. - */ - DynamicFIFO indexSizePairFIFO; - - bool storeSplitPackets = false; - - ReturnValue_t readMultiplePackets(const uint8_t *frame, size_t frameSize, - size_t startIndex); - ReturnValue_t readNextPacket(const uint8_t *frame, - size_t frameSize, size_t& startIndex); -}; - -#endif /* FRAMEWORK_TMTCSERVICES_PUSPARSER_H_ */ +#ifndef FRAMEWORK_TMTCSERVICES_PUSPARSER_H_ +#define FRAMEWORK_TMTCSERVICES_PUSPARSER_H_ + +#include "../container/DynamicFIFO.h" +#include +#include + +/** + * @brief This small helper class scans a given buffer for PUS packets. + * Can be used if PUS packets are serialized in a tightly packed frame. + * @details + * The parser uses the payload length field of PUS packets to find + * the respective PUS packet sizes. + * + * The parser parses a buffer by taking a pointer and the maximum size to scan. + * If PUS packets are found, they are stored in a FIFO which stores pairs + * consisting of the index in the buffer and the respective packet sizes. + * + * If the parser detects split packets (which means that the size of the + * next packet is larger than the remaining size to scan), it can either + * store that split packet or throw away the packet. + */ +class PusParser { +public: + //! The first entry is the index inside the buffer while the second index + //! is the size of the PUS packet starting at that index. + using indexSizePair = std::pair; + + static constexpr uint8_t INTERFACE_ID = CLASS_ID::PUS_PARSER; + static constexpr ReturnValue_t NO_PACKET_FOUND = MAKE_RETURN_CODE(0x00); + static constexpr ReturnValue_t SPLIT_PACKET = MAKE_RETURN_CODE(0x01); + /** + * Parser constructor. + * @param maxExpectedPusPackets + * Maximum expected number of PUS packets. A good estimate is to divide + * the frame size by the minimum size of a PUS packet (12 bytes) + * @param storeSplitPackets + * Specifies whether split packets are also stored inside the FIFO, + * with the size being the remaining frame size. + */ + PusParser(uint16_t maxExpectedPusPackets, bool storeSplitPackets); + + /** + * Parse a given frame for PUS packets + * @param frame + * @param frameSize + * @return -@c NO_PACKET_FOUND if no packet was found. + */ + ReturnValue_t parsePusPackets(const uint8_t* frame, size_t frameSize); + + /** + * Accessor function to get a reference to the internal FIFO which + * stores pairs of indexi and packet sizes. This FIFO is filled + * by the parsePusPackets() function. + * @return + */ + DynamicFIFO* fifo(); + + /** + * Retrieve the next index and packet size pair from the FIFO. + * This also removed it from the FIFO. Please note that if the FIFO + * is empty, an empty pair will be returned. + * @return + */ + indexSizePair getNextFifoPair(); + +private: + /** A FIFO is used to store information about multiple PUS packets + * inside the receive buffer. The maximum number of entries is defined + * by the first constructor argument. + */ + DynamicFIFO indexSizePairFIFO; + + bool storeSplitPackets = false; + + ReturnValue_t readMultiplePackets(const uint8_t *frame, size_t frameSize, + size_t startIndex); + ReturnValue_t readNextPacket(const uint8_t *frame, + size_t frameSize, size_t& startIndex); +}; + +#endif /* FRAMEWORK_TMTCSERVICES_PUSPARSER_H_ */ diff --git a/tmtcservices/PusServiceBase.cpp b/tmtcservices/PusServiceBase.cpp index 877eff3e..a8b74e39 100644 --- a/tmtcservices/PusServiceBase.cpp +++ b/tmtcservices/PusServiceBase.cpp @@ -1,123 +1,123 @@ -#include -#include -#include -#include -#include -#include -#include - -object_id_t PusServiceBase::packetSource = 0; -object_id_t PusServiceBase::packetDestination = 0; - -PusServiceBase::PusServiceBase(object_id_t setObjectId, uint16_t setApid, - uint8_t setServiceId) : - SystemObject(setObjectId), apid(setApid), serviceId(setServiceId) { - requestQueue = QueueFactory::instance()-> - createMessageQueue(PUS_SERVICE_MAX_RECEPTION); -} - -PusServiceBase::~PusServiceBase() { - QueueFactory::instance()->deleteMessageQueue(requestQueue); -} - -ReturnValue_t PusServiceBase::performOperation(uint8_t opCode) { - handleRequestQueue(); - ReturnValue_t result = this->performService(); - if (result != RETURN_OK) { - sif::error << "PusService " << (uint16_t) this->serviceId - << ": performService returned with " << (int16_t) result - << std::endl; - return RETURN_FAILED; - } - return RETURN_OK; -} - -void PusServiceBase::setTaskIF(PeriodicTaskIF* taskHandle) { - this->taskHandle = taskHandle; -} - -void PusServiceBase::handleRequestQueue() { - TmTcMessage message; - ReturnValue_t result = RETURN_FAILED; - for (uint8_t count = 0; count < PUS_SERVICE_MAX_RECEPTION; count++) { - ReturnValue_t status = this->requestQueue->receiveMessage(&message); -// if(status != MessageQueueIF::EMPTY) { -// sif::debug << "PusServiceBase::performOperation: Receiving from " -// << "MQ ID: " << std::hex << "0x" << std::setw(8) -// << std::setfill('0') << this->requestQueue->getId() -// << std::dec << " returned: " << status << std::setfill(' ') -// << std::endl; -// } - - if (status == RETURN_OK) { - this->currentPacket.setStoreAddress(message.getStorageId()); - //info << "Service " << (uint16_t) this->serviceId << - // ": new packet!" << std::endl; - - result = this->handleRequest(currentPacket.getSubService()); - - // debug << "Service " << (uint16_t)this->serviceId << - // ": handleRequest returned: " << (int)return_code << std::endl; - if (result == RETURN_OK) { - this->verifyReporter.sendSuccessReport( - TC_VERIFY::COMPLETION_SUCCESS, &this->currentPacket); - } - else { - this->verifyReporter.sendFailureReport( - TC_VERIFY::COMPLETION_FAILURE, &this->currentPacket, - result, 0, errorParameter1, errorParameter2); - } - this->currentPacket.deletePacket(); - errorParameter1 = 0; - errorParameter2 = 0; - } - else if (status == MessageQueueIF::EMPTY) { - status = RETURN_OK; - // debug << "PusService " << (uint16_t)this->serviceId << - // ": no new packet." << std::endl; - break; - } - else { - sif::error << "PusServiceBase::performOperation: Service " - << this->serviceId << ": Error receiving packet. Code: " - << std::hex << status << std::dec << std::endl; - } - } -} - -uint16_t PusServiceBase::getIdentifier() { - return this->serviceId; -} - -MessageQueueId_t PusServiceBase::getRequestQueue() { - return this->requestQueue->getId(); -} - -ReturnValue_t PusServiceBase::initialize() { - ReturnValue_t result = SystemObject::initialize(); - if (result != RETURN_OK) { - return result; - } - AcceptsTelemetryIF* destService = objectManager->get( - packetDestination); - PUSDistributorIF* distributor = objectManager->get( - packetSource); - if (destService == nullptr or distributor == nullptr) { - sif::error << "PusServiceBase::PusServiceBase: Service " - << this->serviceId << ": Configuration error. Make sure " - << "packetSource and packetDestination are defined correctly" - << std::endl; - return ObjectManagerIF::CHILD_INIT_FAILED; - } - this->requestQueue->setDefaultDestination( - destService->getReportReceptionQueue()); - distributor->registerService(this); - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t PusServiceBase::initializeAfterTaskCreation() { - // If task parameters, for example task frequency are required, this - // function should be overriden and the system object task IF can - // be used to get those parameters. - return HasReturnvaluesIF::RETURN_OK; -} +#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../tcdistribution/PUSDistributorIF.h" +#include "../tmtcservices/AcceptsTelemetryIF.h" +#include "../tmtcservices/PusServiceBase.h" +#include "../tmtcservices/PusVerificationReport.h" +#include "../tmtcservices/TmTcMessage.h" +#include "../ipc/QueueFactory.h" + +object_id_t PusServiceBase::packetSource = 0; +object_id_t PusServiceBase::packetDestination = 0; + +PusServiceBase::PusServiceBase(object_id_t setObjectId, uint16_t setApid, + uint8_t setServiceId) : + SystemObject(setObjectId), apid(setApid), serviceId(setServiceId) { + requestQueue = QueueFactory::instance()-> + createMessageQueue(PUS_SERVICE_MAX_RECEPTION); +} + +PusServiceBase::~PusServiceBase() { + QueueFactory::instance()->deleteMessageQueue(requestQueue); +} + +ReturnValue_t PusServiceBase::performOperation(uint8_t opCode) { + handleRequestQueue(); + ReturnValue_t result = this->performService(); + if (result != RETURN_OK) { + sif::error << "PusService " << (uint16_t) this->serviceId + << ": performService returned with " << (int16_t) result + << std::endl; + return RETURN_FAILED; + } + return RETURN_OK; +} + +void PusServiceBase::setTaskIF(PeriodicTaskIF* taskHandle) { + this->taskHandle = taskHandle; +} + +void PusServiceBase::handleRequestQueue() { + TmTcMessage message; + ReturnValue_t result = RETURN_FAILED; + for (uint8_t count = 0; count < PUS_SERVICE_MAX_RECEPTION; count++) { + ReturnValue_t status = this->requestQueue->receiveMessage(&message); +// if(status != MessageQueueIF::EMPTY) { +// sif::debug << "PusServiceBase::performOperation: Receiving from " +// << "MQ ID: " << std::hex << "0x" << std::setw(8) +// << std::setfill('0') << this->requestQueue->getId() +// << std::dec << " returned: " << status << std::setfill(' ') +// << std::endl; +// } + + if (status == RETURN_OK) { + this->currentPacket.setStoreAddress(message.getStorageId()); + //info << "Service " << (uint16_t) this->serviceId << + // ": new packet!" << std::endl; + + result = this->handleRequest(currentPacket.getSubService()); + + // debug << "Service " << (uint16_t)this->serviceId << + // ": handleRequest returned: " << (int)return_code << std::endl; + if (result == RETURN_OK) { + this->verifyReporter.sendSuccessReport( + TC_VERIFY::COMPLETION_SUCCESS, &this->currentPacket); + } + else { + this->verifyReporter.sendFailureReport( + TC_VERIFY::COMPLETION_FAILURE, &this->currentPacket, + result, 0, errorParameter1, errorParameter2); + } + this->currentPacket.deletePacket(); + errorParameter1 = 0; + errorParameter2 = 0; + } + else if (status == MessageQueueIF::EMPTY) { + status = RETURN_OK; + // debug << "PusService " << (uint16_t)this->serviceId << + // ": no new packet." << std::endl; + break; + } + else { + sif::error << "PusServiceBase::performOperation: Service " + << this->serviceId << ": Error receiving packet. Code: " + << std::hex << status << std::dec << std::endl; + } + } +} + +uint16_t PusServiceBase::getIdentifier() { + return this->serviceId; +} + +MessageQueueId_t PusServiceBase::getRequestQueue() { + return this->requestQueue->getId(); +} + +ReturnValue_t PusServiceBase::initialize() { + ReturnValue_t result = SystemObject::initialize(); + if (result != RETURN_OK) { + return result; + } + AcceptsTelemetryIF* destService = objectManager->get( + packetDestination); + PUSDistributorIF* distributor = objectManager->get( + packetSource); + if (destService == nullptr or distributor == nullptr) { + sif::error << "PusServiceBase::PusServiceBase: Service " + << this->serviceId << ": Configuration error. Make sure " + << "packetSource and packetDestination are defined correctly" + << std::endl; + return ObjectManagerIF::CHILD_INIT_FAILED; + } + this->requestQueue->setDefaultDestination( + destService->getReportReceptionQueue()); + distributor->registerService(this); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t PusServiceBase::initializeAfterTaskCreation() { + // If task parameters, for example task frequency are required, this + // function should be overriden and the system object task IF can + // be used to get those parameters. + return HasReturnvaluesIF::RETURN_OK; +} diff --git a/tmtcservices/PusServiceBase.h b/tmtcservices/PusServiceBase.h index 6d3d9bac..f9431275 100644 --- a/tmtcservices/PusServiceBase.h +++ b/tmtcservices/PusServiceBase.h @@ -1,159 +1,159 @@ -#ifndef FRAMEWORK_TMTCSERVICES_PUSSERVICEBASE_H_ -#define FRAMEWORK_TMTCSERVICES_PUSSERVICEBASE_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Factory{ -void setStaticFrameworkObjectIds(); -} - -/** - * @defgroup pus_services PUS Service Framework - * These group contains all implementations of PUS Services in the OBSW. - * Most of the Services are directly taken from the ECSS PUS Standard. - */ - -/** - * @brief This class is the basis for all PUS Services, - * which can immediately process Telecommand Packets. - * @details - * It manages Telecommand reception and the generation of Verification Reports. - * Every class that inherits from this abstract class has to implement - * handleRequest and performService. Services that are created with this - * Base class have to handle any kind of request immediately on reception. - * All PUS Services are System Objects, so an Object ID needs to be specified - * on construction. - * @ingroup pus_services - */ -class PusServiceBase : public ExecutableObjectIF, - public AcceptsTelecommandsIF, - public SystemObject, - public HasReturnvaluesIF { - friend void (Factory::setStaticFrameworkObjectIds)(); -public: - /** - * @brief The passed values are set, but inter-object initialization is - * done in the initialize method. - * @param setObjectId - * The system object identifier of this Service instance. - * @param setApid - * The APID the Service is instantiated for. - * @param setServiceId - * The Service Identifier as specified in ECSS PUS. - */ - PusServiceBase( object_id_t setObjectId, uint16_t setApid, - uint8_t setServiceId); - /** - * The destructor is empty. - */ - virtual ~PusServiceBase(); - /** - * @brief The handleRequest method shall handle any kind of Telecommand - * Request immediately. - * @details - * Implemetations can take the Telecommand in currentPacket and perform - * any kind of operation. - * They may send additional "Start Success (1,3)" messages with the - * verifyReporter, but Completion Success or Failure Reports are generated - * automatically after execution of this method. - * - * If a Telecommand can not be executed within one call cycle, - * this Base class is not the right parent. - * - * The child class may add additional error information by setting - * #errorParameters which aren attached to the generated verification - * message. - * - * Subservice checking should be implemented in this method. - * - * @return The returned status_code is directly taken as main error code - * in the Verification Report. - * On success, RETURN_OK shall be returned. - */ - virtual ReturnValue_t handleRequest(uint8_t subservice) = 0; - /** - * In performService, implementations can handle periodic, - * non-TC-triggered activities. - * The performService method is always called. - * @return Currently, everything other that RETURN_OK only triggers - * diagnostic output. - */ - virtual ReturnValue_t performService() = 0; - /** - * This method implements the typical activity of a simple PUS Service. - * It checks for new requests, and, if found, calls handleRequest, sends - * completion verification messages and deletes - * the TC requests afterwards. - * performService is always executed afterwards. - * @return @c RETURN_OK if the periodic performService was successful. - * @c RETURN_FAILED else. - */ - ReturnValue_t performOperation(uint8_t opCode) override; - virtual uint16_t getIdentifier() override; - MessageQueueId_t getRequestQueue() override; - virtual ReturnValue_t initialize() override; - - virtual void setTaskIF(PeriodicTaskIF* taskHandle) override; - virtual ReturnValue_t initializeAfterTaskCreation() override; -protected: - /** - * @brief Handle to the underlying task - * @details - * Will be set by setTaskIF(), which is called on task creation. - */ - PeriodicTaskIF* taskHandle = nullptr; - /** - * The APID of this instance of the Service. - */ - uint16_t apid; - /** - * The Service Identifier. - */ - uint8_t serviceId; - /** - * One of two error parameters for additional error information. - */ - uint32_t errorParameter1 = 0; - /** - * One of two error parameters for additional error information. - */ - uint32_t errorParameter2 = 0; - /** - * This is a complete instance of the telecommand reception queue - * of the class. It is initialized on construction of the class. - */ - MessageQueueIF* requestQueue = nullptr; - /** - * An instance of the VerificationReporter class, that simplifies - * sending any kind of verification message to the TC Verification Service. - */ - VerificationReporter verifyReporter; - /** - * The current Telecommand to be processed. - * It is deleted after handleRequest was executed. - */ - TcPacketStored currentPacket; - - static object_id_t packetSource; - - static object_id_t packetDestination; -private: - /** - * This constant sets the maximum number of packets accepted per call. - * Remember that one packet must be completely handled in one - * #handleRequest call. - */ - static const uint8_t PUS_SERVICE_MAX_RECEPTION = 10; - - void handleRequestQueue(); -}; - -#endif /* PUSSERVICEBASE_H_ */ +#ifndef FRAMEWORK_TMTCSERVICES_PUSSERVICEBASE_H_ +#define FRAMEWORK_TMTCSERVICES_PUSSERVICEBASE_H_ + +#include "../objectmanager/ObjectManagerIF.h" +#include "../objectmanager/SystemObject.h" +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../tasks/ExecutableObjectIF.h" +#include "../tmtcpacket/pus/TcPacketStored.h" +#include "../tmtcservices/AcceptsTelecommandsIF.h" +#include "../tmtcservices/VerificationCodes.h" +#include "../tmtcservices/VerificationReporter.h" +#include "../ipc/MessageQueueIF.h" + +namespace Factory{ +void setStaticFrameworkObjectIds(); +} + +/** + * @defgroup pus_services PUS Service Framework + * These group contains all implementations of PUS Services in the OBSW. + * Most of the Services are directly taken from the ECSS PUS Standard. + */ + +/** + * @brief This class is the basis for all PUS Services, + * which can immediately process Telecommand Packets. + * @details + * It manages Telecommand reception and the generation of Verification Reports. + * Every class that inherits from this abstract class has to implement + * handleRequest and performService. Services that are created with this + * Base class have to handle any kind of request immediately on reception. + * All PUS Services are System Objects, so an Object ID needs to be specified + * on construction. + * @ingroup pus_services + */ +class PusServiceBase : public ExecutableObjectIF, + public AcceptsTelecommandsIF, + public SystemObject, + public HasReturnvaluesIF { + friend void (Factory::setStaticFrameworkObjectIds)(); +public: + /** + * @brief The passed values are set, but inter-object initialization is + * done in the initialize method. + * @param setObjectId + * The system object identifier of this Service instance. + * @param setApid + * The APID the Service is instantiated for. + * @param setServiceId + * The Service Identifier as specified in ECSS PUS. + */ + PusServiceBase( object_id_t setObjectId, uint16_t setApid, + uint8_t setServiceId); + /** + * The destructor is empty. + */ + virtual ~PusServiceBase(); + /** + * @brief The handleRequest method shall handle any kind of Telecommand + * Request immediately. + * @details + * Implemetations can take the Telecommand in currentPacket and perform + * any kind of operation. + * They may send additional "Start Success (1,3)" messages with the + * verifyReporter, but Completion Success or Failure Reports are generated + * automatically after execution of this method. + * + * If a Telecommand can not be executed within one call cycle, + * this Base class is not the right parent. + * + * The child class may add additional error information by setting + * #errorParameters which aren attached to the generated verification + * message. + * + * Subservice checking should be implemented in this method. + * + * @return The returned status_code is directly taken as main error code + * in the Verification Report. + * On success, RETURN_OK shall be returned. + */ + virtual ReturnValue_t handleRequest(uint8_t subservice) = 0; + /** + * In performService, implementations can handle periodic, + * non-TC-triggered activities. + * The performService method is always called. + * @return Currently, everything other that RETURN_OK only triggers + * diagnostic output. + */ + virtual ReturnValue_t performService() = 0; + /** + * This method implements the typical activity of a simple PUS Service. + * It checks for new requests, and, if found, calls handleRequest, sends + * completion verification messages and deletes + * the TC requests afterwards. + * performService is always executed afterwards. + * @return @c RETURN_OK if the periodic performService was successful. + * @c RETURN_FAILED else. + */ + ReturnValue_t performOperation(uint8_t opCode) override; + virtual uint16_t getIdentifier() override; + MessageQueueId_t getRequestQueue() override; + virtual ReturnValue_t initialize() override; + + virtual void setTaskIF(PeriodicTaskIF* taskHandle) override; + virtual ReturnValue_t initializeAfterTaskCreation() override; +protected: + /** + * @brief Handle to the underlying task + * @details + * Will be set by setTaskIF(), which is called on task creation. + */ + PeriodicTaskIF* taskHandle = nullptr; + /** + * The APID of this instance of the Service. + */ + uint16_t apid; + /** + * The Service Identifier. + */ + uint8_t serviceId; + /** + * One of two error parameters for additional error information. + */ + uint32_t errorParameter1 = 0; + /** + * One of two error parameters for additional error information. + */ + uint32_t errorParameter2 = 0; + /** + * This is a complete instance of the telecommand reception queue + * of the class. It is initialized on construction of the class. + */ + MessageQueueIF* requestQueue = nullptr; + /** + * An instance of the VerificationReporter class, that simplifies + * sending any kind of verification message to the TC Verification Service. + */ + VerificationReporter verifyReporter; + /** + * The current Telecommand to be processed. + * It is deleted after handleRequest was executed. + */ + TcPacketStored currentPacket; + + static object_id_t packetSource; + + static object_id_t packetDestination; +private: + /** + * This constant sets the maximum number of packets accepted per call. + * Remember that one packet must be completely handled in one + * #handleRequest call. + */ + static const uint8_t PUS_SERVICE_MAX_RECEPTION = 10; + + void handleRequestQueue(); +}; + +#endif /* PUSSERVICEBASE_H_ */ diff --git a/tmtcservices/PusVerificationReport.cpp b/tmtcservices/PusVerificationReport.cpp index 07631801..d83380a2 100644 --- a/tmtcservices/PusVerificationReport.cpp +++ b/tmtcservices/PusVerificationReport.cpp @@ -1,163 +1,163 @@ -#include -#include - -PusVerificationMessage::PusVerificationMessage() { -} - -//PusVerificationMessage::PusVerificationMessage(uint8_t set_report_id, -// TcPacketBase* current_packet, ReturnValue_t set_error_code, -// uint8_t set_step, uint32_t parameter1, uint32_t parameter2) { -// uint8_t ackFlags = current_packet->getAcknowledgeFlags(); -// uint16_t tcPacketId = current_packet->getPacketId(); -// uint16_t tcSequenceControl = current_packet->getPacketSequenceControl(); -// uint8_t* data = this->getBuffer(); -// data[messageSize] = set_report_id; -// messageSize += sizeof(set_report_id); -// data[messageSize] = ackFlags; -// messageSize += sizeof(ackFlags); -// memcpy(&data[messageSize], &tcPacketId, sizeof(tcPacketId)); -// messageSize += sizeof(tcPacketId); -// memcpy(&data[messageSize], &tcSequenceControl, sizeof(tcSequenceControl)); -// messageSize += sizeof(tcSequenceControl); -// data[messageSize] = set_step; -// messageSize += sizeof(set_step); -// memcpy(&data[messageSize], &set_error_code, sizeof(set_error_code)); -// messageSize += sizeof(set_error_code); -// memcpy(&data[messageSize], ¶meter1, sizeof(parameter1)); -// messageSize += sizeof(parameter1); -// memcpy(&data[messageSize], ¶meter2, sizeof(parameter2)); -// messageSize += sizeof(parameter2); -//} - -PusVerificationMessage::PusVerificationMessage(uint8_t set_report_id, - uint8_t ackFlags, uint16_t tcPacketId, uint16_t tcSequenceControl, - ReturnValue_t set_error_code, uint8_t set_step, uint32_t parameter1, - uint32_t parameter2) { - uint8_t *data = this->getBuffer(); - data[messageSize] = set_report_id; - messageSize += sizeof(set_report_id); - data[messageSize] = ackFlags; - messageSize += sizeof(ackFlags); - memcpy(&data[messageSize], &tcPacketId, sizeof(tcPacketId)); - messageSize += sizeof(tcPacketId); - memcpy(&data[messageSize], &tcSequenceControl, sizeof(tcSequenceControl)); - messageSize += sizeof(tcSequenceControl); - data[messageSize] = set_step; - messageSize += sizeof(set_step); - memcpy(&data[messageSize], &set_error_code, sizeof(set_error_code)); - messageSize += sizeof(set_error_code); - memcpy(&data[messageSize], ¶meter1, sizeof(parameter1)); - messageSize += sizeof(parameter1); - memcpy(&data[messageSize], ¶meter2, sizeof(parameter2)); - messageSize += sizeof(parameter2); -} - -uint8_t PusVerificationMessage::getReportId() { - - return getContent()->reportId; -} - -uint8_t PusVerificationMessage::getAckFlags() { - - return getContent()->ackFlags; -} - -uint16_t PusVerificationMessage::getTcPacketId() { - - uint16_t tcPacketId; - memcpy(&tcPacketId, &getContent()->packetId_0, sizeof(tcPacketId)); - return tcPacketId; -} - -uint16_t PusVerificationMessage::getTcSequenceControl() { - - uint16_t tcSequenceControl; - memcpy(&tcSequenceControl, &getContent()->tcSequenceControl_0, - sizeof(tcSequenceControl)); - return tcSequenceControl; -} - -uint8_t PusVerificationMessage::getStep() { - - return getContent()->step; -} - -ReturnValue_t PusVerificationMessage::getErrorCode() { - ReturnValue_t errorCode; - memcpy(&errorCode, &getContent()->error_code_0, sizeof(errorCode)); - return errorCode; -} - -PusVerificationMessage::verifciationMessageContent* PusVerificationMessage::getContent() { - return (verifciationMessageContent*) this->getData(); -} - -uint32_t PusVerificationMessage::getParameter1() { - uint32_t parameter; - memcpy(¶meter, &getContent()->parameter1_0, sizeof(parameter)); - return parameter; -} - -uint32_t PusVerificationMessage::getParameter2() { - uint32_t parameter; - memcpy(¶meter, &getContent()->parameter2_0, sizeof(parameter)); - return parameter; -} - -PusSuccessReport::PusSuccessReport(uint16_t setPacketId, - uint16_t setSequenceControl, uint8_t setStep) : - reportSize(0), pBuffer(reportBuffer) { - //Serialization won't fail, because we know the necessary max-size of the buffer. - SerializeAdapter::serialize(&setPacketId, &pBuffer, &reportSize, - sizeof(reportBuffer), SerializeIF::Endianness::BIG); - SerializeAdapter::serialize(&setSequenceControl, &pBuffer, &reportSize, - sizeof(reportBuffer), SerializeIF::Endianness::BIG); - if (setStep != 0) { - SerializeAdapter::serialize(&setStep, &pBuffer, &reportSize, - sizeof(reportBuffer), SerializeIF::Endianness::BIG); - } -} - -PusSuccessReport::~PusSuccessReport() { - -} - -uint32_t PusSuccessReport::getSize() { - return reportSize; -} - -uint8_t* PusSuccessReport::getReport() { - return reportBuffer; -} - -PusFailureReport::PusFailureReport(uint16_t setPacketId, - uint16_t setSequenceControl, ReturnValue_t setErrorCode, - uint8_t setStep, uint32_t parameter1, uint32_t parameter2) : - reportSize(0), pBuffer(reportBuffer) { - //Serialization won't fail, because we know the necessary max-size of the buffer. - SerializeAdapter::serialize(&setPacketId, &pBuffer, &reportSize, - sizeof(reportBuffer), SerializeIF::Endianness::BIG); - SerializeAdapter::serialize(&setSequenceControl, &pBuffer, &reportSize, - sizeof(reportBuffer), SerializeIF::Endianness::BIG); - if (setStep != 0) { - SerializeAdapter::serialize(&setStep, &pBuffer, &reportSize, - sizeof(reportBuffer), SerializeIF::Endianness::BIG); - } - SerializeAdapter::serialize(&setErrorCode, &pBuffer, &reportSize, - sizeof(reportBuffer), SerializeIF::Endianness::BIG); - SerializeAdapter::serialize(¶meter1, &pBuffer, &reportSize, - sizeof(reportBuffer), SerializeIF::Endianness::BIG); - SerializeAdapter::serialize(¶meter2, &pBuffer, &reportSize, - sizeof(reportBuffer), SerializeIF::Endianness::BIG); -} - -PusFailureReport::~PusFailureReport() { -} - -size_t PusFailureReport::getSize() { - return reportSize; -} - -uint8_t* PusFailureReport::getReport() { - return reportBuffer; -} +#include "../serialize/SerializeAdapter.h" +#include "../tmtcservices/PusVerificationReport.h" + +PusVerificationMessage::PusVerificationMessage() { +} + +//PusVerificationMessage::PusVerificationMessage(uint8_t set_report_id, +// TcPacketBase* current_packet, ReturnValue_t set_error_code, +// uint8_t set_step, uint32_t parameter1, uint32_t parameter2) { +// uint8_t ackFlags = current_packet->getAcknowledgeFlags(); +// uint16_t tcPacketId = current_packet->getPacketId(); +// uint16_t tcSequenceControl = current_packet->getPacketSequenceControl(); +// uint8_t* data = this->getBuffer(); +// data[messageSize] = set_report_id; +// messageSize += sizeof(set_report_id); +// data[messageSize] = ackFlags; +// messageSize += sizeof(ackFlags); +// memcpy(&data[messageSize], &tcPacketId, sizeof(tcPacketId)); +// messageSize += sizeof(tcPacketId); +// memcpy(&data[messageSize], &tcSequenceControl, sizeof(tcSequenceControl)); +// messageSize += sizeof(tcSequenceControl); +// data[messageSize] = set_step; +// messageSize += sizeof(set_step); +// memcpy(&data[messageSize], &set_error_code, sizeof(set_error_code)); +// messageSize += sizeof(set_error_code); +// memcpy(&data[messageSize], ¶meter1, sizeof(parameter1)); +// messageSize += sizeof(parameter1); +// memcpy(&data[messageSize], ¶meter2, sizeof(parameter2)); +// messageSize += sizeof(parameter2); +//} + +PusVerificationMessage::PusVerificationMessage(uint8_t set_report_id, + uint8_t ackFlags, uint16_t tcPacketId, uint16_t tcSequenceControl, + ReturnValue_t set_error_code, uint8_t set_step, uint32_t parameter1, + uint32_t parameter2) { + uint8_t *data = this->getBuffer(); + data[messageSize] = set_report_id; + messageSize += sizeof(set_report_id); + data[messageSize] = ackFlags; + messageSize += sizeof(ackFlags); + memcpy(&data[messageSize], &tcPacketId, sizeof(tcPacketId)); + messageSize += sizeof(tcPacketId); + memcpy(&data[messageSize], &tcSequenceControl, sizeof(tcSequenceControl)); + messageSize += sizeof(tcSequenceControl); + data[messageSize] = set_step; + messageSize += sizeof(set_step); + memcpy(&data[messageSize], &set_error_code, sizeof(set_error_code)); + messageSize += sizeof(set_error_code); + memcpy(&data[messageSize], ¶meter1, sizeof(parameter1)); + messageSize += sizeof(parameter1); + memcpy(&data[messageSize], ¶meter2, sizeof(parameter2)); + messageSize += sizeof(parameter2); +} + +uint8_t PusVerificationMessage::getReportId() { + + return getContent()->reportId; +} + +uint8_t PusVerificationMessage::getAckFlags() { + + return getContent()->ackFlags; +} + +uint16_t PusVerificationMessage::getTcPacketId() { + + uint16_t tcPacketId; + memcpy(&tcPacketId, &getContent()->packetId_0, sizeof(tcPacketId)); + return tcPacketId; +} + +uint16_t PusVerificationMessage::getTcSequenceControl() { + + uint16_t tcSequenceControl; + memcpy(&tcSequenceControl, &getContent()->tcSequenceControl_0, + sizeof(tcSequenceControl)); + return tcSequenceControl; +} + +uint8_t PusVerificationMessage::getStep() { + + return getContent()->step; +} + +ReturnValue_t PusVerificationMessage::getErrorCode() { + ReturnValue_t errorCode; + memcpy(&errorCode, &getContent()->error_code_0, sizeof(errorCode)); + return errorCode; +} + +PusVerificationMessage::verifciationMessageContent* PusVerificationMessage::getContent() { + return (verifciationMessageContent*) this->getData(); +} + +uint32_t PusVerificationMessage::getParameter1() { + uint32_t parameter; + memcpy(¶meter, &getContent()->parameter1_0, sizeof(parameter)); + return parameter; +} + +uint32_t PusVerificationMessage::getParameter2() { + uint32_t parameter; + memcpy(¶meter, &getContent()->parameter2_0, sizeof(parameter)); + return parameter; +} + +PusSuccessReport::PusSuccessReport(uint16_t setPacketId, + uint16_t setSequenceControl, uint8_t setStep) : + reportSize(0), pBuffer(reportBuffer) { + //Serialization won't fail, because we know the necessary max-size of the buffer. + SerializeAdapter::serialize(&setPacketId, &pBuffer, &reportSize, + sizeof(reportBuffer), SerializeIF::Endianness::BIG); + SerializeAdapter::serialize(&setSequenceControl, &pBuffer, &reportSize, + sizeof(reportBuffer), SerializeIF::Endianness::BIG); + if (setStep != 0) { + SerializeAdapter::serialize(&setStep, &pBuffer, &reportSize, + sizeof(reportBuffer), SerializeIF::Endianness::BIG); + } +} + +PusSuccessReport::~PusSuccessReport() { + +} + +uint32_t PusSuccessReport::getSize() { + return reportSize; +} + +uint8_t* PusSuccessReport::getReport() { + return reportBuffer; +} + +PusFailureReport::PusFailureReport(uint16_t setPacketId, + uint16_t setSequenceControl, ReturnValue_t setErrorCode, + uint8_t setStep, uint32_t parameter1, uint32_t parameter2) : + reportSize(0), pBuffer(reportBuffer) { + //Serialization won't fail, because we know the necessary max-size of the buffer. + SerializeAdapter::serialize(&setPacketId, &pBuffer, &reportSize, + sizeof(reportBuffer), SerializeIF::Endianness::BIG); + SerializeAdapter::serialize(&setSequenceControl, &pBuffer, &reportSize, + sizeof(reportBuffer), SerializeIF::Endianness::BIG); + if (setStep != 0) { + SerializeAdapter::serialize(&setStep, &pBuffer, &reportSize, + sizeof(reportBuffer), SerializeIF::Endianness::BIG); + } + SerializeAdapter::serialize(&setErrorCode, &pBuffer, &reportSize, + sizeof(reportBuffer), SerializeIF::Endianness::BIG); + SerializeAdapter::serialize(¶meter1, &pBuffer, &reportSize, + sizeof(reportBuffer), SerializeIF::Endianness::BIG); + SerializeAdapter::serialize(¶meter2, &pBuffer, &reportSize, + sizeof(reportBuffer), SerializeIF::Endianness::BIG); +} + +PusFailureReport::~PusFailureReport() { +} + +size_t PusFailureReport::getSize() { + return reportSize; +} + +uint8_t* PusFailureReport::getReport() { + return reportBuffer; +} diff --git a/tmtcservices/PusVerificationReport.h b/tmtcservices/PusVerificationReport.h index ee84f0c1..26a1eaed 100644 --- a/tmtcservices/PusVerificationReport.h +++ b/tmtcservices/PusVerificationReport.h @@ -1,77 +1,77 @@ -#ifndef PUSVERIFICATIONREPORT_H_ -#define PUSVERIFICATIONREPORT_H_ - -#include -#include -#include - -class PusVerificationMessage: public MessageQueueMessage { -private: - struct verifciationMessageContent { - uint8_t reportId; - uint8_t ackFlags; - uint8_t packetId_0; - uint8_t packetId_1; - uint8_t tcSequenceControl_0; - uint8_t tcSequenceControl_1; - uint8_t step; - uint8_t error_code_0; - uint8_t error_code_1; - uint8_t parameter1_0; - uint8_t parameter1_1; - uint8_t parameter1_2; - uint8_t parameter1_3; - uint8_t parameter2_0; - uint8_t parameter2_1; - uint8_t parameter2_2; - uint8_t parameter2_3; - }; - verifciationMessageContent* getContent(); -public: - static const uint8_t VERIFICATION_MIN_SIZE = 6; - PusVerificationMessage(); -// PusVerificationMessage( uint8_t set_report_id, TcPacketBase* current_packet, ReturnValue_t set_error_code = 0, uint8_t set_step = 0, uint32_t parameter1 = 0, uint32_t parameter2 = 0 ); - PusVerificationMessage(uint8_t set_report_id, uint8_t ackFlags, - uint16_t tcPacketId, uint16_t tcSequenceControl, - ReturnValue_t set_error_code = 0, uint8_t set_step = 0, - uint32_t parameter1 = 0, uint32_t parameter2 = 0); - uint8_t getReportId(); - uint8_t getAckFlags(); - uint16_t getTcPacketId(); - uint16_t getTcSequenceControl(); - ReturnValue_t getErrorCode(); - uint8_t getStep(); - uint32_t getParameter1(); - uint32_t getParameter2(); -}; - -class PusSuccessReport { -private: - static const uint16_t MAX_SIZE = 7; - uint8_t reportBuffer[MAX_SIZE]; - size_t reportSize; - uint8_t * pBuffer; -public: - PusSuccessReport(uint16_t setPacketId, uint16_t setSequenceControl, - uint8_t set_step = 0); - ~PusSuccessReport(); - uint32_t getSize(); - uint8_t* getReport(); -}; - -class PusFailureReport { -private: - static const uint16_t MAX_SIZE = 16; - uint8_t reportBuffer[MAX_SIZE]; - size_t reportSize; - uint8_t * pBuffer; -public: - PusFailureReport(uint16_t setPacketId, uint16_t setSequenceControl, - ReturnValue_t setErrorCode, uint8_t setStep = 0, - uint32_t parameter1 = 0, uint32_t parameter2 = 0); - ~PusFailureReport(); - size_t getSize(); - uint8_t* getReport(); -}; - -#endif /* PUSVERIFICATIONREPORT_H_ */ +#ifndef PUSVERIFICATIONREPORT_H_ +#define PUSVERIFICATIONREPORT_H_ + +#include "../ipc/MessageQueueMessage.h" +#include "../tmtcpacket/pus/TcPacketBase.h" +#include "../tmtcservices/VerificationCodes.h" + +class PusVerificationMessage: public MessageQueueMessage { +private: + struct verifciationMessageContent { + uint8_t reportId; + uint8_t ackFlags; + uint8_t packetId_0; + uint8_t packetId_1; + uint8_t tcSequenceControl_0; + uint8_t tcSequenceControl_1; + uint8_t step; + uint8_t error_code_0; + uint8_t error_code_1; + uint8_t parameter1_0; + uint8_t parameter1_1; + uint8_t parameter1_2; + uint8_t parameter1_3; + uint8_t parameter2_0; + uint8_t parameter2_1; + uint8_t parameter2_2; + uint8_t parameter2_3; + }; + verifciationMessageContent* getContent(); +public: + static const uint8_t VERIFICATION_MIN_SIZE = 6; + PusVerificationMessage(); +// PusVerificationMessage( uint8_t set_report_id, TcPacketBase* current_packet, ReturnValue_t set_error_code = 0, uint8_t set_step = 0, uint32_t parameter1 = 0, uint32_t parameter2 = 0 ); + PusVerificationMessage(uint8_t set_report_id, uint8_t ackFlags, + uint16_t tcPacketId, uint16_t tcSequenceControl, + ReturnValue_t set_error_code = 0, uint8_t set_step = 0, + uint32_t parameter1 = 0, uint32_t parameter2 = 0); + uint8_t getReportId(); + uint8_t getAckFlags(); + uint16_t getTcPacketId(); + uint16_t getTcSequenceControl(); + ReturnValue_t getErrorCode(); + uint8_t getStep(); + uint32_t getParameter1(); + uint32_t getParameter2(); +}; + +class PusSuccessReport { +private: + static const uint16_t MAX_SIZE = 7; + uint8_t reportBuffer[MAX_SIZE]; + size_t reportSize; + uint8_t * pBuffer; +public: + PusSuccessReport(uint16_t setPacketId, uint16_t setSequenceControl, + uint8_t set_step = 0); + ~PusSuccessReport(); + uint32_t getSize(); + uint8_t* getReport(); +}; + +class PusFailureReport { +private: + static const uint16_t MAX_SIZE = 16; + uint8_t reportBuffer[MAX_SIZE]; + size_t reportSize; + uint8_t * pBuffer; +public: + PusFailureReport(uint16_t setPacketId, uint16_t setSequenceControl, + ReturnValue_t setErrorCode, uint8_t setStep = 0, + uint32_t parameter1 = 0, uint32_t parameter2 = 0); + ~PusFailureReport(); + size_t getSize(); + uint8_t* getReport(); +}; + +#endif /* PUSVERIFICATIONREPORT_H_ */ diff --git a/tmtcservices/SourceSequenceCounter.h b/tmtcservices/SourceSequenceCounter.h index b92a5c84..0db53380 100644 --- a/tmtcservices/SourceSequenceCounter.h +++ b/tmtcservices/SourceSequenceCounter.h @@ -1,30 +1,30 @@ -/** - * @file SourceSequenceCounter.h - * @brief This file defines the SourceSequenceCounter class. - * @date 04.02.2013 - * @author baetz - */ - -#ifndef SOURCESEQUENCECOUNTER_H_ -#define SOURCESEQUENCECOUNTER_H_ -#include - -class SourceSequenceCounter { -private: - uint16_t sequenceCount; -public: - SourceSequenceCounter() : sequenceCount(0) {} - void increment() { - sequenceCount = (sequenceCount+1) % (SpacePacketBase::LIMIT_SEQUENCE_COUNT); - } - void decrement() { - sequenceCount = (sequenceCount-1) % (SpacePacketBase::LIMIT_SEQUENCE_COUNT); - } - uint16_t get() { return this->sequenceCount; } - void reset(uint16_t toValue = 0) { - sequenceCount = toValue % (SpacePacketBase::LIMIT_SEQUENCE_COUNT); - } -}; - - -#endif /* SOURCESEQUENCECOUNTER_H_ */ +/** + * @file SourceSequenceCounter.h + * @brief This file defines the SourceSequenceCounter class. + * @date 04.02.2013 + * @author baetz + */ + +#ifndef SOURCESEQUENCECOUNTER_H_ +#define SOURCESEQUENCECOUNTER_H_ +#include "../tmtcpacket/SpacePacketBase.h" + +class SourceSequenceCounter { +private: + uint16_t sequenceCount; +public: + SourceSequenceCounter() : sequenceCount(0) {} + void increment() { + sequenceCount = (sequenceCount+1) % (SpacePacketBase::LIMIT_SEQUENCE_COUNT); + } + void decrement() { + sequenceCount = (sequenceCount-1) % (SpacePacketBase::LIMIT_SEQUENCE_COUNT); + } + uint16_t get() { return this->sequenceCount; } + void reset(uint16_t toValue = 0) { + sequenceCount = toValue % (SpacePacketBase::LIMIT_SEQUENCE_COUNT); + } +}; + + +#endif /* SOURCESEQUENCECOUNTER_H_ */ diff --git a/tmtcservices/TmTcBridge.cpp b/tmtcservices/TmTcBridge.cpp index b55803cb..732a2ea1 100644 --- a/tmtcservices/TmTcBridge.cpp +++ b/tmtcservices/TmTcBridge.cpp @@ -1,9 +1,9 @@ -#include +#include "../tmtcservices/TmTcBridge.h" -#include -#include -#include -#include +#include "../ipc/QueueFactory.h" +#include "../tmtcservices/AcceptsTelecommandsIF.h" +#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../globalfunctions/arrayprinter.h" TmTcBridge::TmTcBridge(object_id_t objectId, object_id_t tcDestination, object_id_t tmStoreId, object_id_t tcStoreId): @@ -105,8 +105,8 @@ ReturnValue_t TmTcBridge::handleTm() { ReturnValue_t TmTcBridge::handleTmQueue() { TmTcMessage message; - const uint8_t* data = nullptr; - size_t size = 0; + const uint8_t* data = nullptr; + size_t size = 0; for (ReturnValue_t result = tmTcReceptionQueue->receiveMessage(&message); result == RETURN_OK; result = tmTcReceptionQueue->receiveMessage(&message)) { @@ -155,8 +155,8 @@ ReturnValue_t TmTcBridge::handleStoredTm() { //info << "TMTC Bridge: Sending stored TM data. There are " // << (int) fifo.size() << " left to send\r\n" << std::flush; store_address_t storeId; - const uint8_t* data = nullptr; - size_t size = 0; + const uint8_t* data = nullptr; + size_t size = 0; tmFifo.retrieve(&storeId); result = tmStore->getData(storeId, &data, &size); diff --git a/tmtcservices/TmTcBridge.h b/tmtcservices/TmTcBridge.h index 993cd5b9..b91425e1 100644 --- a/tmtcservices/TmTcBridge.h +++ b/tmtcservices/TmTcBridge.h @@ -1,15 +1,15 @@ #ifndef FRAMEWORK_TMTCSERVICES_TMTCBRIDGE_H_ #define FRAMEWORK_TMTCSERVICES_TMTCBRIDGE_H_ -#include -#include -#include -#include -#include -#include +#include "../objectmanager/SystemObject.h" +#include "../tmtcservices/AcceptsTelemetryIF.h" +#include "../tasks/ExecutableObjectIF.h" +#include "../ipc/MessageQueueIF.h" +#include "../storagemanager/StorageManagerIF.h" +#include "../tmtcservices/AcceptsTelecommandsIF.h" -#include -#include +#include "../container/FIFO.h" +#include "../tmtcservices/TmTcMessage.h" class TmTcBridge : public AcceptsTelemetryIF, public AcceptsTelecommandsIF, diff --git a/tmtcservices/TmTcMessage.cpp b/tmtcservices/TmTcMessage.cpp index d437b41e..0fe3229c 100644 --- a/tmtcservices/TmTcMessage.cpp +++ b/tmtcservices/TmTcMessage.cpp @@ -1,29 +1,29 @@ -#include -#include - - -TmTcMessage::TmTcMessage() { - this->messageSize += sizeof(store_address_t); -} - -TmTcMessage::~TmTcMessage() { -} - -store_address_t TmTcMessage::getStorageId() { - store_address_t temp_id; - memcpy(&temp_id, this->getData(), sizeof(store_address_t) ); - return temp_id; -} - -TmTcMessage::TmTcMessage(store_address_t store_id) { - this->messageSize += sizeof(store_address_t); - this->setStorageId(store_id); -} - -size_t TmTcMessage::getMinimumMessageSize() { - return this->HEADER_SIZE + sizeof(store_address_t); -} - -void TmTcMessage::setStorageId(store_address_t store_id) { - memcpy(this->getData(), &store_id, sizeof(store_address_t) ); -} +#include "../tmtcservices/TmTcMessage.h" +#include + + +TmTcMessage::TmTcMessage() { + this->messageSize += sizeof(store_address_t); +} + +TmTcMessage::~TmTcMessage() { +} + +store_address_t TmTcMessage::getStorageId() { + store_address_t temp_id; + memcpy(&temp_id, this->getData(), sizeof(store_address_t) ); + return temp_id; +} + +TmTcMessage::TmTcMessage(store_address_t store_id) { + this->messageSize += sizeof(store_address_t); + this->setStorageId(store_id); +} + +size_t TmTcMessage::getMinimumMessageSize() { + return this->HEADER_SIZE + sizeof(store_address_t); +} + +void TmTcMessage::setStorageId(store_address_t store_id) { + memcpy(this->getData(), &store_id, sizeof(store_address_t) ); +} diff --git a/tmtcservices/TmTcMessage.h b/tmtcservices/TmTcMessage.h index 73f741fb..ad97c056 100644 --- a/tmtcservices/TmTcMessage.h +++ b/tmtcservices/TmTcMessage.h @@ -1,50 +1,50 @@ -#ifndef TMTCMESSAGE_H_ -#define TMTCMESSAGE_H_ - -#include -#include -/** - * @brief This message class is used to pass Telecommand and Telemetry - * packets between tasks. - * @details Within such a packet, nothing is transported but the identifier of - * a packet stored in one of the IPC stores (typically a special TM and - * a special TC store). This makes passing commands very simple and - * efficient. - * \ingroup message_queue - */ -class TmTcMessage : public MessageQueueMessage { -protected: - /** - * @brief This call always returns the same fixed size of the message. - * @return Returns HEADER_SIZE + \c sizeof(store_address_t). - */ - size_t getMinimumMessageSize(); -public: - /** - * @brief In the default constructor, only the message_size is set. - */ - TmTcMessage(); - /** - * @brief With this constructor, the passed packet id is directly put - * into the message. - * @param packet_id The packet id to put into the message. - */ - TmTcMessage( store_address_t packet_id ); - /** - * @brief The class's destructor is empty. - */ - ~TmTcMessage(); - /** - * @brief This getter returns the packet id in the correct format. - * @return Returns the packet id. - */ - store_address_t getStorageId(); - /** - * @brief In some cases it might be useful to have a setter for packet id - * as well. - * @param packet_id The packet id to put into the message. - */ - void setStorageId( store_address_t packet_id ); -}; - -#endif /* TMTCMESSAGE_H_ */ +#ifndef TMTCMESSAGE_H_ +#define TMTCMESSAGE_H_ + +#include "../ipc/MessageQueueMessage.h" +#include "../storagemanager/StorageManagerIF.h" +/** + * @brief This message class is used to pass Telecommand and Telemetry + * packets between tasks. + * @details Within such a packet, nothing is transported but the identifier of + * a packet stored in one of the IPC stores (typically a special TM and + * a special TC store). This makes passing commands very simple and + * efficient. + * \ingroup message_queue + */ +class TmTcMessage : public MessageQueueMessage { +protected: + /** + * @brief This call always returns the same fixed size of the message. + * @return Returns HEADER_SIZE + \c sizeof(store_address_t). + */ + size_t getMinimumMessageSize(); +public: + /** + * @brief In the default constructor, only the message_size is set. + */ + TmTcMessage(); + /** + * @brief With this constructor, the passed packet id is directly put + * into the message. + * @param packet_id The packet id to put into the message. + */ + TmTcMessage( store_address_t packet_id ); + /** + * @brief The class's destructor is empty. + */ + ~TmTcMessage(); + /** + * @brief This getter returns the packet id in the correct format. + * @return Returns the packet id. + */ + store_address_t getStorageId(); + /** + * @brief In some cases it might be useful to have a setter for packet id + * as well. + * @param packet_id The packet id to put into the message. + */ + void setStorageId( store_address_t packet_id ); +}; + +#endif /* TMTCMESSAGE_H_ */ diff --git a/tmtcservices/VerificationReporter.cpp b/tmtcservices/VerificationReporter.cpp index 79e650f1..e9a43855 100644 --- a/tmtcservices/VerificationReporter.cpp +++ b/tmtcservices/VerificationReporter.cpp @@ -1,105 +1,105 @@ -#include - -#include -#include -#include -#include -#include - -object_id_t VerificationReporter::messageReceiver = objects::PUS_SERVICE_1; - -VerificationReporter::VerificationReporter() : - acknowledgeQueue(MessageQueueIF::NO_QUEUE) { -} - -VerificationReporter::~VerificationReporter() {} - -void VerificationReporter::sendSuccessReport(uint8_t set_report_id, - TcPacketBase* current_packet, uint8_t set_step) { - if (acknowledgeQueue == MessageQueueIF::NO_QUEUE) { - this->initialize(); - } - PusVerificationMessage message(set_report_id, - current_packet->getAcknowledgeFlags(), - current_packet->getPacketId(), - current_packet->getPacketSequenceControl(), 0, set_step); - ReturnValue_t status = MessageQueueSenderIF::sendMessage(acknowledgeQueue, - &message); - if (status != HasReturnvaluesIF::RETURN_OK) { - sif::error << "VerificationReporter::sendSuccessReport: Error writing " - << "to queue. Code: " << std::hex << status << std::dec - << std::endl; - } -} - -void VerificationReporter::sendSuccessReport(uint8_t set_report_id, - uint8_t ackFlags, uint16_t tcPacketId, uint16_t tcSequenceControl, - uint8_t set_step) { - if (acknowledgeQueue == MessageQueueIF::NO_QUEUE) { - this->initialize(); - } - PusVerificationMessage message(set_report_id, ackFlags, tcPacketId, - tcSequenceControl, 0, set_step); - ReturnValue_t status = MessageQueueSenderIF::sendMessage(acknowledgeQueue, - &message); - if (status != HasReturnvaluesIF::RETURN_OK) { - sif::error << "VerificationReporter::sendSuccessReport: Error writing " - << "to queue. Code: " << std::hex << status << std::dec - << std::endl; - } -} - -void VerificationReporter::sendFailureReport(uint8_t report_id, - TcPacketBase* current_packet, ReturnValue_t error_code, uint8_t step, - uint32_t parameter1, uint32_t parameter2) { - if (acknowledgeQueue == MessageQueueIF::NO_QUEUE) { - this->initialize(); - } - PusVerificationMessage message(report_id, - current_packet->getAcknowledgeFlags(), - current_packet->getPacketId(), - current_packet->getPacketSequenceControl(), error_code, step, - parameter1, parameter2); - ReturnValue_t status = MessageQueueSenderIF::sendMessage(acknowledgeQueue, - &message); - if (status != HasReturnvaluesIF::RETURN_OK) { - sif::error << "VerificationReporter::sendFailureReport Error writing " - << "to queue. Code: " << std::hex << status << std::dec - << std::endl; - } -} - -void VerificationReporter::sendFailureReport(uint8_t report_id, - uint8_t ackFlags, uint16_t tcPacketId, uint16_t tcSequenceControl, - ReturnValue_t error_code, uint8_t step, uint32_t parameter1, - uint32_t parameter2) { - if (acknowledgeQueue == MessageQueueIF::NO_QUEUE) { - this->initialize(); - } - PusVerificationMessage message(report_id, ackFlags, tcPacketId, - tcSequenceControl, error_code, step, parameter1, parameter2); - ReturnValue_t status = MessageQueueSenderIF::sendMessage(acknowledgeQueue, - &message); - if (status != HasReturnvaluesIF::RETURN_OK) { - sif::error << "VerificationReporter::sendFailureReport Error writing " - << "to queue. Code: " << std::hex << status << std::dec - << std::endl; - } -} - -void VerificationReporter::initialize() { - if(messageReceiver == objects::NO_OBJECT) { - sif::warning << "VerificationReporter::initialize: Verification message" - " receiver object ID not set yet in Factory!" << std::endl; - return; - } - AcceptsVerifyMessageIF* temp = objectManager->get( - messageReceiver); - if (temp == nullptr) { - sif::error << "VerificationReporter::initialize: Message " - << "receiver invalid. Make sure it is set up properly and " - <<"implementsAcceptsVerifyMessageIF" << std::endl; - - } - this->acknowledgeQueue = temp->getVerificationQueue(); -} +#include "../tmtcservices/VerificationReporter.h" + +#include "../ipc/MessageQueueIF.h" +#include "../tmtcservices/AcceptsVerifyMessageIF.h" +#include "../tmtcservices/PusVerificationReport.h" +#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../objectmanager/frameworkObjects.h" + +object_id_t VerificationReporter::messageReceiver = objects::PUS_SERVICE_1; + +VerificationReporter::VerificationReporter() : + acknowledgeQueue(MessageQueueIF::NO_QUEUE) { +} + +VerificationReporter::~VerificationReporter() {} + +void VerificationReporter::sendSuccessReport(uint8_t set_report_id, + TcPacketBase* current_packet, uint8_t set_step) { + if (acknowledgeQueue == MessageQueueIF::NO_QUEUE) { + this->initialize(); + } + PusVerificationMessage message(set_report_id, + current_packet->getAcknowledgeFlags(), + current_packet->getPacketId(), + current_packet->getPacketSequenceControl(), 0, set_step); + ReturnValue_t status = MessageQueueSenderIF::sendMessage(acknowledgeQueue, + &message); + if (status != HasReturnvaluesIF::RETURN_OK) { + sif::error << "VerificationReporter::sendSuccessReport: Error writing " + << "to queue. Code: " << std::hex << status << std::dec + << std::endl; + } +} + +void VerificationReporter::sendSuccessReport(uint8_t set_report_id, + uint8_t ackFlags, uint16_t tcPacketId, uint16_t tcSequenceControl, + uint8_t set_step) { + if (acknowledgeQueue == MessageQueueIF::NO_QUEUE) { + this->initialize(); + } + PusVerificationMessage message(set_report_id, ackFlags, tcPacketId, + tcSequenceControl, 0, set_step); + ReturnValue_t status = MessageQueueSenderIF::sendMessage(acknowledgeQueue, + &message); + if (status != HasReturnvaluesIF::RETURN_OK) { + sif::error << "VerificationReporter::sendSuccessReport: Error writing " + << "to queue. Code: " << std::hex << status << std::dec + << std::endl; + } +} + +void VerificationReporter::sendFailureReport(uint8_t report_id, + TcPacketBase* current_packet, ReturnValue_t error_code, uint8_t step, + uint32_t parameter1, uint32_t parameter2) { + if (acknowledgeQueue == MessageQueueIF::NO_QUEUE) { + this->initialize(); + } + PusVerificationMessage message(report_id, + current_packet->getAcknowledgeFlags(), + current_packet->getPacketId(), + current_packet->getPacketSequenceControl(), error_code, step, + parameter1, parameter2); + ReturnValue_t status = MessageQueueSenderIF::sendMessage(acknowledgeQueue, + &message); + if (status != HasReturnvaluesIF::RETURN_OK) { + sif::error << "VerificationReporter::sendFailureReport Error writing " + << "to queue. Code: " << std::hex << status << std::dec + << std::endl; + } +} + +void VerificationReporter::sendFailureReport(uint8_t report_id, + uint8_t ackFlags, uint16_t tcPacketId, uint16_t tcSequenceControl, + ReturnValue_t error_code, uint8_t step, uint32_t parameter1, + uint32_t parameter2) { + if (acknowledgeQueue == MessageQueueIF::NO_QUEUE) { + this->initialize(); + } + PusVerificationMessage message(report_id, ackFlags, tcPacketId, + tcSequenceControl, error_code, step, parameter1, parameter2); + ReturnValue_t status = MessageQueueSenderIF::sendMessage(acknowledgeQueue, + &message); + if (status != HasReturnvaluesIF::RETURN_OK) { + sif::error << "VerificationReporter::sendFailureReport Error writing " + << "to queue. Code: " << std::hex << status << std::dec + << std::endl; + } +} + +void VerificationReporter::initialize() { + if(messageReceiver == objects::NO_OBJECT) { + sif::warning << "VerificationReporter::initialize: Verification message" + " receiver object ID not set yet in Factory!" << std::endl; + return; + } + AcceptsVerifyMessageIF* temp = objectManager->get( + messageReceiver); + if (temp == nullptr) { + sif::error << "VerificationReporter::initialize: Message " + << "receiver invalid. Make sure it is set up properly and " + <<"implementsAcceptsVerifyMessageIF" << std::endl; + + } + this->acknowledgeQueue = temp->getVerificationQueue(); +} diff --git a/tmtcservices/VerificationReporter.h b/tmtcservices/VerificationReporter.h index f13998d9..86aea826 100644 --- a/tmtcservices/VerificationReporter.h +++ b/tmtcservices/VerificationReporter.h @@ -1,50 +1,50 @@ -#ifndef FRAMEWORK_TMTCSERVICES_VERIFICATIONREPORTER_H_ -#define FRAMEWORK_TMTCSERVICES_VERIFICATIONREPORTER_H_ - -#include -#include - -namespace Factory{ -void setStaticFrameworkObjectIds(); -} - -/** - * @brief This helper object is used to forward verification messages - * which are generated by the Flight Software Framework. - * @details - * The messages can be relayed to an arbitrary object, for example a dedicated - * Verification Reporter. The destination is set by setting the static framework - * Id VerificationReporter::messageReceiver. The default verification reporter - * will be the PUS service 1, which sends verification messages according - * to the PUS standard. - * - */ -class VerificationReporter { - friend void (Factory::setStaticFrameworkObjectIds)(); -public: - VerificationReporter(); - virtual ~VerificationReporter(); - - void sendSuccessReport( uint8_t set_report_id, TcPacketBase* current_packet, - uint8_t set_step = 0 ); - void sendSuccessReport(uint8_t set_report_id, uint8_t ackFlags, - uint16_t tcPacketId, uint16_t tcSequenceControl, - uint8_t set_step = 0); - - void sendFailureReport( uint8_t report_id, TcPacketBase* current_packet, - ReturnValue_t error_code = 0, - uint8_t step = 0, uint32_t parameter1 = 0, - uint32_t parameter2 = 0 ); - void sendFailureReport(uint8_t report_id, - uint8_t ackFlags, uint16_t tcPacketId, uint16_t tcSequenceControl, - ReturnValue_t error_code = 0, uint8_t step = 0, - uint32_t parameter1 = 0, uint32_t parameter2 = 0); - - void initialize(); - -private: - static object_id_t messageReceiver; - MessageQueueId_t acknowledgeQueue; -}; - -#endif /* FRAMEWORK_TMTCSERVICES_VERIFICATIONREPORTER_H_ */ +#ifndef FRAMEWORK_TMTCSERVICES_VERIFICATIONREPORTER_H_ +#define FRAMEWORK_TMTCSERVICES_VERIFICATIONREPORTER_H_ + +#include "../objectmanager/ObjectManagerIF.h" +#include "../tmtcservices/PusVerificationReport.h" + +namespace Factory{ +void setStaticFrameworkObjectIds(); +} + +/** + * @brief This helper object is used to forward verification messages + * which are generated by the Flight Software Framework. + * @details + * The messages can be relayed to an arbitrary object, for example a dedicated + * Verification Reporter. The destination is set by setting the static framework + * Id VerificationReporter::messageReceiver. The default verification reporter + * will be the PUS service 1, which sends verification messages according + * to the PUS standard. + * + */ +class VerificationReporter { + friend void (Factory::setStaticFrameworkObjectIds)(); +public: + VerificationReporter(); + virtual ~VerificationReporter(); + + void sendSuccessReport( uint8_t set_report_id, TcPacketBase* current_packet, + uint8_t set_step = 0 ); + void sendSuccessReport(uint8_t set_report_id, uint8_t ackFlags, + uint16_t tcPacketId, uint16_t tcSequenceControl, + uint8_t set_step = 0); + + void sendFailureReport( uint8_t report_id, TcPacketBase* current_packet, + ReturnValue_t error_code = 0, + uint8_t step = 0, uint32_t parameter1 = 0, + uint32_t parameter2 = 0 ); + void sendFailureReport(uint8_t report_id, + uint8_t ackFlags, uint16_t tcPacketId, uint16_t tcSequenceControl, + ReturnValue_t error_code = 0, uint8_t step = 0, + uint32_t parameter1 = 0, uint32_t parameter2 = 0); + + void initialize(); + +private: + static object_id_t messageReceiver; + MessageQueueId_t acknowledgeQueue; +}; + +#endif /* FRAMEWORK_TMTCSERVICES_VERIFICATIONREPORTER_H_ */