diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..e69de29b diff --git a/FSFWVersion.h b/FSFWVersion.h new file mode 100644 index 00000000..dcb592dc --- /dev/null +++ b/FSFWVersion.h @@ -0,0 +1,11 @@ +#ifndef FSFW_DEFAULTCFG_VERSION_H_ +#define FSFW_DEFAULTCFG_VERSION_H_ + +const char* const FSFW_VERSION_NAME = "fsfw"; + +#define FSFW_VERSION 0 +#define FSFW_SUBVERSION 0 + + + +#endif /* FSFW_DEFAULTCFG_VERSION_H_ */ diff --git a/README.md b/README.md new file mode 100644 index 00000000..fc86fca7 --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +Flight Software Framework (FSFW) +====== + +I want to be written! diff --git a/action/ActionHelper.cpp b/action/ActionHelper.cpp index 361f7dc3..0d3baa88 100644 --- a/action/ActionHelper.cpp +++ b/action/ActionHelper.cpp @@ -3,8 +3,9 @@ #include "../ipc/MessageQueueSenderIF.h" #include "../objectmanager/ObjectManagerIF.h" -ActionHelper::ActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue) : - owner(setOwner), queueToUse(useThisQueue), ipcStore(nullptr) { +ActionHelper::ActionHelper(HasActionsIF* setOwner, + MessageQueueIF* useThisQueue) : + owner(setOwner), queueToUse(useThisQueue) { } ActionHelper::~ActionHelper() { @@ -33,13 +34,15 @@ ReturnValue_t ActionHelper::initialize(MessageQueueIF* queueToUse_) { return HasReturnvaluesIF::RETURN_OK; } -void ActionHelper::step(uint8_t step, MessageQueueId_t reportTo, ActionId_t commandId, ReturnValue_t result) { +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) { +void ActionHelper::finish(MessageQueueId_t reportTo, ActionId_t commandId, + ReturnValue_t result) { CommandMessage reply; ActionMessage::setCompletionReply(&reply, commandId, result); queueToUse->sendMessage(reportTo, &reply); @@ -49,8 +52,8 @@ void ActionHelper::setQueueToUse(MessageQueueIF* queue) { queueToUse = queue; } -void ActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId, - store_address_t dataAddress) { +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); @@ -62,6 +65,11 @@ void ActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId_t act } result = owner->executeAction(actionId, commandedBy, dataPtr, size); ipcStore->deleteData(dataAddress); + if(result == HasActionsIF::EXECUTION_FINISHED) { + CommandMessage reply; + ActionMessage::setCompletionReply(&reply, actionId, result); + queueToUse->sendMessage(commandedBy, &reply); + } if (result != HasReturnvaluesIF::RETURN_OK) { CommandMessage reply; ActionMessage::setStepReply(&reply, actionId, 0, result); @@ -86,22 +94,28 @@ ReturnValue_t ActionHelper::reportData(MessageQueueId_t reportTo, if (result != HasReturnvaluesIF::RETURN_OK) { return result; } - result = data->serialize(&dataPtr, &size, maxSize, SerializeIF::Endianness::BIG); + 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. + // 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){ + // If the sender needs to be hidden, for example to handle packet + // as unrequested reply, this will be done here. + if (hideSender) { result = MessageQueueSenderIF::sendMessage(reportTo, &reply); - } else { + } + else { result = queueToUse->sendMessage(reportTo, &reply); } - if ( result != HasReturnvaluesIF::RETURN_OK){ + + if (result != HasReturnvaluesIF::RETURN_OK){ ipcStore->deleteData(storeAddress); } return result; @@ -109,3 +123,39 @@ ReturnValue_t ActionHelper::reportData(MessageQueueId_t reportTo, void ActionHelper::resetHelper() { } + +ReturnValue_t ActionHelper::reportData(MessageQueueId_t reportTo, + ActionId_t replyId, const uint8_t *data, size_t dataSize, + bool hideSender) { + CommandMessage reply; + store_address_t storeAddress; + ReturnValue_t result = ipcStore->addData(&storeAddress, data, dataSize); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + 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); + + // If the sender needs to be hidden, for example to handle packet + // as unrequested reply, this will be done here. + if (hideSender) { + result = MessageQueueSenderIF::sendMessage(reportTo, &reply); + } + else { + result = queueToUse->sendMessage(reportTo, &reply); + } + + if (result != HasReturnvaluesIF::RETURN_OK){ + ipcStore->deleteData(storeAddress); + } + return result; +} diff --git a/action/ActionHelper.h b/action/ActionHelper.h index bbc6d114..a91722f3 100644 --- a/action/ActionHelper.h +++ b/action/ActionHelper.h @@ -1,15 +1,18 @@ -#ifndef ACTIONHELPER_H_ -#define ACTIONHELPER_H_ +#ifndef FSFW_ACTION_ACTIONHELPER_H_ +#define FSFW_ACTION_ACTIONHELPER_H_ #include "ActionMessage.h" #include "../serialize/SerializeIF.h" #include "../ipc/MessageQueueIF.h" /** - * \brief Action Helper is a helper class which handles action messages + * @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! + * 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 needs a + * valid MessageQueueIF pointer! */ class HasActionsIF; @@ -18,7 +21,8 @@ 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. + * @param useThisQueue messageQueue to be used, can be set during + * initialize function as well. */ ActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue); @@ -26,28 +30,36 @@ public: /** * 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. + * 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 + * @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, optional if queue was set in constructor + * Helper initialize function. Must be called before use of any other + * helper function + * @param queueToUse_ Pointer to the messageQueue to be used, optional + * if queue was set in constructor * @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. + * 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); + 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 * @@ -55,39 +67,59 @@ public: * @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); + 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 + * Function to be called by the owner if an action does report data. + * Takes a SerializeIF* pointer and serializes it into the IPC store. + * @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); + ReturnValue_t reportData(MessageQueueId_t reportTo, ActionId_t replyId, + SerializeIF* data, bool hideSender = false); + /** + * Function to be called by the owner if an action does report data. + * Takes the raw data and writes it into the IPC store. + * @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, + const uint8_t* data, size_t dataSize, 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. + * 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 + //!< Increase of value of this per step + static const uint8_t STEP_OFFSET = 1; 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) + //! Queue to be used as response sender, has to be set in ctor or with + //! setQueueToUse + MessageQueueIF* queueToUse; + //! Pointer to an IPC Store, initialized during construction or + StorageManagerIF* ipcStore = nullptr; + /** - *Internal function called by handleActionMessage(CommandMessage* command) - * + * Internal function called by handleActionMessage * @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 prepareExecution(MessageQueueId_t commandedBy, + ActionId_t actionId, store_address_t dataAddress); /** - * + * @brief Default implementation is empty. */ virtual void resetHelper(); }; -#endif /* ACTIONHELPER_H_ */ +#endif /* FSFW_ACTION_ACTIONHELPER_H_ */ diff --git a/action/HasActionsIF.h b/action/HasActionsIF.h index 886d0837..690f0369 100644 --- a/action/HasActionsIF.h +++ b/action/HasActionsIF.h @@ -1,11 +1,12 @@ -#ifndef FRAMEWORK_ACTION_HASACTIONSIF_H_ -#define FRAMEWORK_ACTION_HASACTIONSIF_H_ +#ifndef FSFW_ACTION_HASACTIONSIF_H_ +#define FSFW_ACTION_HASACTIONSIF_H_ #include "ActionHelper.h" #include "ActionMessage.h" #include "SimpleActionHelper.h" #include "../returnvalues/HasReturnvaluesIF.h" #include "../ipc/MessageQueueIF.h" + /** * @brief * Interface for component which uses actions @@ -47,14 +48,16 @@ public: 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! + * The ActionHelpers will execute this function and behave differently + * depending on the returnvalue. + * + * @return + * -@c EXECUTION_FINISHED Finish reply will be generated + * -@c Not RETURN_OK Step failure reply will be generated */ virtual ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy, const uint8_t* data, size_t size) = 0; }; -#endif /* FRAMEWORK_ACTION_HASACTIONSIF_H_ */ +#endif /* FSFW_ACTION_HASACTIONSIF_H_ */ diff --git a/action/SimpleActionHelper.cpp b/action/SimpleActionHelper.cpp index d79a3c97..af57736c 100644 --- a/action/SimpleActionHelper.cpp +++ b/action/SimpleActionHelper.cpp @@ -1,16 +1,17 @@ #include "HasActionsIF.h" #include "SimpleActionHelper.h" + SimpleActionHelper::SimpleActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue) : - ActionHelper(setOwner, useThisQueue), isExecuting(false), lastCommander( - 0), lastAction(0), stepCount(0) { + ActionHelper(setOwner, useThisQueue), isExecuting(false) { } 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. + // 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) { diff --git a/action/SimpleActionHelper.h b/action/SimpleActionHelper.h index 1329b5fb..1f35d9fd 100644 --- a/action/SimpleActionHelper.h +++ b/action/SimpleActionHelper.h @@ -1,8 +1,13 @@ -#ifndef SIMPLEACTIONHELPER_H_ -#define SIMPLEACTIONHELPER_H_ +#ifndef FSFW_ACTION_SIMPLEACTIONHELPER_H_ +#define FSFW_ACTION_SIMPLEACTIONHELPER_H_ #include "ActionHelper.h" +/** + * @brief This is an action helper which is only able to service one action + * at a time but remembers last commander and last action which + * simplifies usage + */ class SimpleActionHelper: public ActionHelper { public: SimpleActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue); @@ -12,13 +17,14 @@ public: ReturnValue_t reportData(SerializeIF* data); protected: - void prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId, store_address_t dataAddress); - virtual void resetHelper(); + 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; + MessageQueueId_t lastCommander = MessageQueueIF::NO_QUEUE; + ActionId_t lastAction = 0; + uint8_t stepCount = 0; }; #endif /* SIMPLEACTIONHELPER_H_ */ diff --git a/container/SharedRingBuffer.cpp b/container/SharedRingBuffer.cpp index 800e75d3..6ddb3d3e 100644 --- a/container/SharedRingBuffer.cpp +++ b/container/SharedRingBuffer.cpp @@ -9,6 +9,7 @@ SharedRingBuffer::SharedRingBuffer(object_id_t objectId, const size_t size, 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, @@ -16,6 +17,11 @@ SharedRingBuffer::SharedRingBuffer(object_id_t objectId, uint8_t *buffer, mutex = MutexFactory::instance()->createMutex(); } + +void SharedRingBuffer::setToUseReceiveSizeFIFO(size_t fifoDepth) { + this->fifoDepth = fifoDepth; +} + ReturnValue_t SharedRingBuffer::lockRingBufferMutex( MutexIF::TimeoutType timeoutType, dur_millis_t timeout) { return mutex->lockMutex(timeoutType, timeout); @@ -25,6 +31,25 @@ ReturnValue_t SharedRingBuffer::unlockRingBufferMutex() { return mutex->unlockMutex(); } + + MutexIF* SharedRingBuffer::getMutexHandle() const { return mutex; } + +ReturnValue_t SharedRingBuffer::initialize() { + if(fifoDepth > 0) { + receiveSizesFIFO = new DynamicFIFO(fifoDepth); + } + return SystemObject::initialize(); +} + +DynamicFIFO* SharedRingBuffer::getReceiveSizesFIFO() { + if(receiveSizesFIFO == nullptr) { + // Configuration error. + sif::warning << "SharedRingBuffer::getReceiveSizesFIFO: Ring buffer" + << " was not configured to have sizes FIFO, returning nullptr!" + << std::endl; + } + return receiveSizesFIFO; +} diff --git a/container/SharedRingBuffer.h b/container/SharedRingBuffer.h index 80c068b3..64d7ee29 100644 --- a/container/SharedRingBuffer.h +++ b/container/SharedRingBuffer.h @@ -2,6 +2,7 @@ #define FSFW_CONTAINER_SHAREDRINGBUFFER_H_ #include "SimpleRingBuffer.h" +#include "DynamicFIFO.h" #include "../ipc/MutexIF.h" #include "../objectmanager/SystemObject.h" #include "../timemanager/Clock.h" @@ -26,6 +27,16 @@ public: SharedRingBuffer(object_id_t objectId, const size_t size, bool overwriteOld, size_t maxExcessBytes); + /** + * @brief This function can be used to add an optional FIFO to the class + * @details + * This FIFO will be allocated in the initialize function (and will + * have a fixed maximum size after that). It can be used to store + * values like packet sizes, for example for a shared ring buffer + * used by producer/consumer tasks. + */ + void setToUseReceiveSizeFIFO(size_t fifoDepth); + /** * This constructor takes an external buffer with the specified size. * @param buffer @@ -59,8 +70,21 @@ public: * @return */ MutexIF* getMutexHandle() const; + + ReturnValue_t initialize() override; + + /** + * If the shared ring buffer was configured to have a sizes FIFO, a handle + * to that FIFO can be retrieved with this function. + * Do not forget to protect access with a lock if required! + * @return + */ + DynamicFIFO* getReceiveSizesFIFO(); private: MutexIF* mutex = nullptr; + + size_t fifoDepth = 0; + DynamicFIFO* receiveSizesFIFO = nullptr; }; diff --git a/defaultcfg/README.md b/defaultcfg/README.md new file mode 100644 index 00000000..8446cda4 --- /dev/null +++ b/defaultcfg/README.md @@ -0,0 +1,6 @@ +# How to setup configuration folder for FSFW + +It is recommended to copy the content of the defaultcfg folder +into a config folder which is in the same directory as the Flight +Software Framework submodule. After that, the config.mk folder should be +included by the primary Makefile with CURRENTPATH set correctly. diff --git a/defaultcfg/config/FSFWConfig.h b/defaultcfg/config/FSFWConfig.h new file mode 100644 index 00000000..ea86152c --- /dev/null +++ b/defaultcfg/config/FSFWConfig.h @@ -0,0 +1,54 @@ +#ifndef CONFIG_FSFWCONFIG_H_ +#define CONFIG_FSFWCONFIG_H_ + +#include +#include + +//! Used to determine whether C++ ostreams are used +//! Those can lead to code bloat. +#define FSFW_CPP_OSTREAM_ENABLED 1 + +//! Reduced printout to further decrese code size +//! Be careful, this also turns off most diagnostic prinouts! +#define FSFW_REDUCED_PRINTOUT 0 + +//! Can be used to enable debugging printouts for developing the FSFW +#define FSFW_DEBUGGING 0 + +//! Defines the FIFO depth of each commanding service base which +//! also determines how many commands a CSB service can handle in one cycle +//! simulataneously. This will increase the required RAM for +//! each CSB service ! +#define FSFW_CSB_FIFO_DEPTH 6 + +//! If FSFW_OBJ_EVENT_TRANSLATION is set to one, +//! additional output which requires the translation files translateObjects +//! and translateEvents (and their compiled source files) +#define FSFW_OBJ_EVENT_TRANSLATION 0 + +#if FSFW_OBJ_EVENT_TRANSLATION == 1 +#define FSFW_DEBUG_OUTPUT 1 +//! Specify whether info events are printed too. +#define FSFW_DEBUG_INFO 1 +#include +#include +#else +#define FSFW_DEBUG_OUTPUT 0 +#endif + +//! When using the newlib nano library, C99 support for stdio facilities +//! will not be provided. This define should be set to 1 if this is the case. +#define FSFW_NO_C99_IO 1 + +namespace fsfwconfig { +//! Default timestamp size. The default timestamp will be an eight byte CDC +//! short timestamp. +static constexpr uint8_t FSFW_MISSION_TIMESTAMP_SIZE = 8; + +//! Configure the allocated pool sizes for the event manager. +static constexpr size_t FSFW_EVENTMGMR_MATCHTREE_NODES = 240; +static constexpr size_t FSFW_EVENTMGMT_EVENTIDMATCHERS = 120; +static constexpr size_t FSFW_EVENTMGMR_RANGEMATCHERS = 120; +} + +#endif /* CONFIG_FSFWCONFIG_H_ */ diff --git a/defaultcfg/config/OBSWConfig.h b/defaultcfg/config/OBSWConfig.h new file mode 100644 index 00000000..a9f57638 --- /dev/null +++ b/defaultcfg/config/OBSWConfig.h @@ -0,0 +1,16 @@ +#ifndef CONFIG_OBSWCONFIG_H_ +#define CONFIG_OBSWCONFIG_H_ + +#include "OBSWVersion.h" + +#ifdef __cplusplus +namespace config { +#endif + +/* Add mission configuration flags here */ + +#ifdef __cplusplus +} +#endif + +#endif /* CONFIG_OBSWCONFIG_H_ */ diff --git a/defaultcfg/config/OBSWVersion.h b/defaultcfg/config/OBSWVersion.h new file mode 100644 index 00000000..3c60317c --- /dev/null +++ b/defaultcfg/config/OBSWVersion.h @@ -0,0 +1,9 @@ +#ifndef CONFIG_VERSION_H_ +#define CONFIG_VERSION_H_ + +/* OBSW versioning can be specified in this file */ + +#define OBSW_VERSION 0 +#define OBSW_SUBVERSION 0 + +#endif /* CONFIG_VERSION_H_ */ diff --git a/defaultcfg/config/config.mk b/defaultcfg/config/config.mk new file mode 100644 index 00000000..51543eba --- /dev/null +++ b/defaultcfg/config/config.mk @@ -0,0 +1,15 @@ +CXXSRC += $(wildcard $(CURRENTPATH)/ipc/*.cpp) +CXXSRC += $(wildcard $(CURRENTPATH)/objects/*.cpp) +CXXSRC += $(wildcard $(CURRENTPATH)/pollingsequence/*.cpp) +CXXSRC += $(wildcard $(CURRENTPATH)/events/*.cpp) +CXXSRC += $(wildcard $(CURRENTPATH)/tmtc/*.cpp) +CXXSRC += $(wildcard $(CURRENTPATH)/devices/*.cpp) + +INCLUDES += $(CURRENTPATH) +INCLUDES += $(CURRENTPATH)/objects +INCLUDES += $(CURRENTPATH)/returnvalues +INCLUDES += $(CURRENTPATH)/tmtc +INCLUDES += $(CURRENTPATH)/events +INCLUDES += $(CURRENTPATH)/devices +INCLUDES += $(CURRENTPATH)/pollingsequence +INCLUDES += $(CURRENTPATH)/ipc diff --git a/defaultcfg/config/devices/logicalAddresses.cpp b/defaultcfg/config/devices/logicalAddresses.cpp new file mode 100644 index 00000000..c7ce314d --- /dev/null +++ b/defaultcfg/config/devices/logicalAddresses.cpp @@ -0,0 +1,5 @@ +#include "logicalAddresses.h" + + + + diff --git a/defaultcfg/config/devices/logicalAddresses.h b/defaultcfg/config/devices/logicalAddresses.h new file mode 100644 index 00000000..174fa788 --- /dev/null +++ b/defaultcfg/config/devices/logicalAddresses.h @@ -0,0 +1,18 @@ +#ifndef CONFIG_DEVICES_LOGICALADDRESSES_H_ +#define CONFIG_DEVICES_LOGICALADDRESSES_H_ + +#include +#include +#include + +/** + * Can be used for addresses for physical devices like I2C adresses. + */ +namespace addresses { + /* Logical addresses have uint32_t datatype */ + enum logicalAddresses: address_t { + }; +} + + +#endif /* CONFIG_DEVICES_LOGICALADDRESSES_H_ */ diff --git a/defaultcfg/config/devices/powerSwitcherList.cpp b/defaultcfg/config/devices/powerSwitcherList.cpp new file mode 100644 index 00000000..343f78d0 --- /dev/null +++ b/defaultcfg/config/devices/powerSwitcherList.cpp @@ -0,0 +1,4 @@ +#include "powerSwitcherList.h" + + + diff --git a/defaultcfg/config/devices/powerSwitcherList.h b/defaultcfg/config/devices/powerSwitcherList.h new file mode 100644 index 00000000..86ddea57 --- /dev/null +++ b/defaultcfg/config/devices/powerSwitcherList.h @@ -0,0 +1,12 @@ +#ifndef CONFIG_DEVICES_POWERSWITCHERLIST_H_ +#define CONFIG_DEVICES_POWERSWITCHERLIST_H_ + +namespace switches { + /* Switches are uint8_t datatype and go from 0 to 255 */ + enum switcherList { + }; + +} + + +#endif /* CONFIG_DEVICES_POWERSWITCHERLIST_H_ */ diff --git a/defaultcfg/config/events/subsystemIdRanges.h b/defaultcfg/config/events/subsystemIdRanges.h new file mode 100644 index 00000000..24eee819 --- /dev/null +++ b/defaultcfg/config/events/subsystemIdRanges.h @@ -0,0 +1,18 @@ +#ifndef CONFIG_EVENTS_SUBSYSTEMIDRANGES_H_ +#define CONFIG_EVENTS_SUBSYSTEMIDRANGES_H_ + +#include +#include + +/** + * @brief Custom subsystem IDs can be added here + * @details + * Subsystem IDs are used to create unique events. + */ +namespace SUBSYSTEM_ID { +enum: uint8_t { + SUBSYSTEM_ID_START = FW_SUBSYSTEM_ID_RANGE, +}; +} + +#endif /* CONFIG_EVENTS_SUBSYSTEMIDRANGES_H_ */ diff --git a/defaultcfg/config/ipc/missionMessageTypes.cpp b/defaultcfg/config/ipc/missionMessageTypes.cpp new file mode 100644 index 00000000..e2edbf9c --- /dev/null +++ b/defaultcfg/config/ipc/missionMessageTypes.cpp @@ -0,0 +1,11 @@ +#include +#include + +void messagetypes::clearMissionMessage(CommandMessage* message) { + switch(message->getMessageType()) { + default: + break; + } +} + + diff --git a/defaultcfg/config/ipc/missionMessageTypes.h b/defaultcfg/config/ipc/missionMessageTypes.h new file mode 100644 index 00000000..8b2e2fcc --- /dev/null +++ b/defaultcfg/config/ipc/missionMessageTypes.h @@ -0,0 +1,21 @@ +#ifndef CONFIG_IPC_MISSIONMESSAGETYPES_H_ +#define CONFIG_IPC_MISSIONMESSAGETYPES_H_ + +#include +#include + +/** + * Custom command messages are specified here. + * Most messages needed to use FSFW are already located in + * + * @param message Generic Command Message + */ +namespace messagetypes { +enum CustomMessageTypes { + MISSION_MESSAGE_TYPE_START = FW_MESSAGES_COUNT +}; + +void clearMissionMessage(CommandMessage* message); +} + +#endif /* CONFIG_IPC_MISSIONMESSAGETYPES_H_ */ diff --git a/defaultcfg/config/objects/Factory.cpp b/defaultcfg/config/objects/Factory.cpp new file mode 100644 index 00000000..51dd6130 --- /dev/null +++ b/defaultcfg/config/objects/Factory.cpp @@ -0,0 +1,54 @@ +#include "Factory.h" +#include "../tmtc/apid.h" +#include "../tmtc/pusIds.h" +#include "../objects/systemObjectList.h" +#include "../devices/logicalAddresses.h" +#include "../devices/powerSwitcherList.h" + +#include +#include +#include +#include +#include +#include + +#include + +/** + * This class should be used to create all system objects required for + * the on-board software, using the object ID list from the configuration + * folder. + * + * The objects are registered in the internal object manager automatically. + * This is used later to add objects to tasks. + * + * This file also sets static framework IDs. + * + * Framework objects are created first. + * @ingroup init + */ +void Factory::produce(void) { + setStaticFrameworkObjectIds(); + new EventManager(objects::EVENT_MANAGER); + new HealthTable(objects::HEALTH_TABLE); + //new InternalErrorReporter(objects::INTERNAL_ERROR_REPORTER); +} + +void Factory::setStaticFrameworkObjectIds() { + PusServiceBase::packetSource = objects::PUS_PACKET_DISTRIBUTOR; + PusServiceBase::packetDestination = objects::TM_FUNNEL; + + CommandingServiceBase::defaultPacketSource = objects::PUS_PACKET_DISTRIBUTOR; + CommandingServiceBase::defaultPacketDestination = objects::TM_FUNNEL; + + VerificationReporter::messageReceiver = objects::PUS_SERVICE_1_VERIFICATION; + + DeviceHandlerBase::powerSwitcherId = objects::NO_OBJECT; + DeviceHandlerBase::rawDataReceiverId = objects::PUS_SERVICE_2_DEVICE_ACCESS; + + DeviceHandlerFailureIsolation::powerConfirmationId = objects::NO_OBJECT; + + TmPacketStored::timeStamperId = objects::PUS_TIME; + //TmFunnel::downlinkDestination = objects::NO_OBJECT; +} + diff --git a/defaultcfg/config/objects/Factory.h b/defaultcfg/config/objects/Factory.h new file mode 100644 index 00000000..fe55deff --- /dev/null +++ b/defaultcfg/config/objects/Factory.h @@ -0,0 +1,17 @@ +#ifndef FACTORY_H_ +#define FACTORY_H_ + +#include +#include + +namespace Factory { + /** + * @brief Creates all SystemObject elements which are persistent + * during execution. + */ + void produce(); + void setStaticFrameworkObjectIds(); +} + + +#endif /* FACTORY_H_ */ diff --git a/defaultcfg/config/objects/systemObjectList.h b/defaultcfg/config/objects/systemObjectList.h new file mode 100644 index 00000000..f4292f6d --- /dev/null +++ b/defaultcfg/config/objects/systemObjectList.h @@ -0,0 +1,16 @@ +#ifndef CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_ +#define CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_ + +#include +#include + +// The objects will be instantiated in the ID order +namespace objects { + enum sourceObjects: uint32_t { + /* All addresses between start and end are reserved for the FSFW */ + FSFW_CONFIG_RESERVED_START = PUS_SERVICE_1_VERIFICATION, + FSFW_CONFIG_RESERVED_END = TM_STORE + }; +} + +#endif /* BSP_CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_ */ diff --git a/defaultcfg/config/pollingsequence/PollingSequenceFactory.cpp b/defaultcfg/config/pollingsequence/PollingSequenceFactory.cpp new file mode 100644 index 00000000..f836a746 --- /dev/null +++ b/defaultcfg/config/pollingsequence/PollingSequenceFactory.cpp @@ -0,0 +1,23 @@ +#include "PollingSequenceFactory.h" + +#include +#include +#include + +ReturnValue_t pst::pollingSequenceInitDefault( + FixedTimeslotTaskIF *thisSequence) { + /* Length of a communication cycle */ + uint32_t length = thisSequence->getPeriodMs(); + + /* Add polling sequence table here */ + + if (thisSequence->checkSequence() == HasReturnvaluesIF::RETURN_OK) { + return HasReturnvaluesIF::RETURN_OK; + } + else { + sif::error << "pst::pollingSequenceInitDefault: Sequence invalid!" + << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } +} + diff --git a/defaultcfg/config/pollingsequence/PollingSequenceFactory.h b/defaultcfg/config/pollingsequence/PollingSequenceFactory.h new file mode 100644 index 00000000..c5d41b7d --- /dev/null +++ b/defaultcfg/config/pollingsequence/PollingSequenceFactory.h @@ -0,0 +1,32 @@ +#ifndef POLLINGSEQUENCEFACTORY_H_ +#define POLLINGSEQUENCEFACTORY_H_ + +#include + +class FixedTimeslotTaskIF; + +/** + * All device handlers are scheduled by adding them into Polling Sequence Tables (PST) + * to satisfy stricter timing requirements of device communication, + * A device handler has four different communication steps: + * 1. DeviceHandlerIF::SEND_WRITE -> Send write via interface + * 2. DeviceHandlerIF::GET_WRITE -> Get confirmation for write + * 3. DeviceHandlerIF::SEND_READ -> Send read request + * 4. DeviceHandlerIF::GET_READ -> Read from interface + * The PST specifies precisely when the respective ComIF functions are called + * during the communication cycle time. + * The task is created using the FixedTimeslotTaskIF, + * which utilises the underlying Operating System Abstraction Layer (OSAL) + * + * @param thisSequence FixedTimeslotTaskIF * object is passed inside the Factory class when creating the PST + * @return + */ +namespace pst { + +/* Default PST */ +ReturnValue_t pollingSequenceInitDefault(FixedTimeslotTaskIF *thisSequence); + + +} + +#endif /* POLLINGSEQUENCEINIT_H_ */ diff --git a/defaultcfg/config/returnvalues/classIds.h b/defaultcfg/config/returnvalues/classIds.h new file mode 100644 index 00000000..606cc60b --- /dev/null +++ b/defaultcfg/config/returnvalues/classIds.h @@ -0,0 +1,16 @@ +#ifndef CONFIG_RETURNVALUES_CLASSIDS_H_ +#define CONFIG_RETURNVALUES_CLASSIDS_H_ + +#include + +/** + * @brief CLASS_ID defintions which are required for custom returnvalues. + */ +namespace CLASS_ID { +enum { + MISSION_CLASS_ID_START = FW_CLASS_ID_COUNT, +}; +} + + +#endif /* CONFIG_RETURNVALUES_CLASSIDS_H_ */ diff --git a/defaultcfg/config/tmtc/apid.h b/defaultcfg/config/tmtc/apid.h new file mode 100644 index 00000000..c0231bca --- /dev/null +++ b/defaultcfg/config/tmtc/apid.h @@ -0,0 +1,18 @@ +#ifndef CONFIG_TMTC_APID_H_ +#define CONFIG_TMTC_APID_H_ + +#include + +/** + * Application Process Definition: entity, uniquely identified by an + * application process ID (APID), capable of generating telemetry source + * packets and receiving telecommand packets. + * + * Chose APID(s) for mission and define it here. + */ +namespace apid { + static const uint16_t DEFAULT_APID = 0x00; +} + + +#endif /* CONFIG_TMTC_APID_H_ */ diff --git a/defaultcfg/config/tmtc/pusIds.h b/defaultcfg/config/tmtc/pusIds.h new file mode 100644 index 00000000..cc0db9f0 --- /dev/null +++ b/defaultcfg/config/tmtc/pusIds.h @@ -0,0 +1,23 @@ +#ifndef CONFIG_TMTC_PUSIDS_HPP_ +#define CONFIG_TMTC_PUSIDS_HPP_ + +namespace pus { +enum Ids: uint8_t { + PUS_SERVICE_1 = 1, + PUS_SERVICE_2 = 2, + PUS_SERVICE_3 = 3, + PUS_SERVICE_5 = 5, + PUS_SERVICE_6 = 6, + PUS_SERVICE_8 = 8, + PUS_SERVICE_9 = 9, + PUS_SERVICE_11 = 11, + PUS_SERVICE_17 = 17, + PUS_SERVICE_19 = 19, + PUS_SERVICE_20 = 20, + PUS_SERVICE_23 = 23, + PUS_SERVICE_200 = 200, + PUS_SERVICE_201 = 201, +}; +}; + +#endif /* CONFIG_TMTC_PUSIDS_HPP_ */ diff --git a/devicehandlers/DeviceHandlerBase.cpp b/devicehandlers/DeviceHandlerBase.cpp index 017ea8d2..710e8a83 100644 --- a/devicehandlers/DeviceHandlerBase.cpp +++ b/devicehandlers/DeviceHandlerBase.cpp @@ -1224,7 +1224,7 @@ void DeviceHandlerBase::buildInternalCommand(void) { if (result == BUSY) { //so we can track misconfigurations sif::debug << std::hex << getObjectId() - << ": DHB::buildInternalCommand: Busy" << std::endl; + << ": DHB::buildInternalCommand: Busy" << std::dec << std::endl; result = NOTHING_TO_SEND; //no need to report this } } diff --git a/events/Event.h b/events/Event.h index e22c9db1..f8410f32 100644 --- a/events/Event.h +++ b/events/Event.h @@ -4,7 +4,7 @@ #include #include "fwSubsystemIdRanges.h" //could be move to more suitable location -#include +#include typedef uint16_t EventId_t; typedef uint8_t EventSeverity_t; diff --git a/events/EventManager.cpp b/events/EventManager.cpp index e71951e3..f60a8a66 100644 --- a/events/EventManager.cpp +++ b/events/EventManager.cpp @@ -1,5 +1,7 @@ #include "EventManager.h" #include "EventMessage.h" +#include + #include "../serviceinterface/ServiceInterfaceStream.h" #include "../ipc/QueueFactory.h" #include "../ipc/MutexFactory.h" @@ -12,8 +14,10 @@ const uint16_t EventManager::POOL_SIZES[N_POOLS] = { // objects registering for certain events. // Each listener requires 1 or 2 EventIdMatcher and 1 or 2 ReportRangeMatcher. // So a good guess is 75 to a max of 100 pools required for each, which fits well. -// SHOULDDO: Shouldn't this be in the config folder and passed via ctor? -const uint16_t EventManager::N_ELEMENTS[N_POOLS] = { 240, 120, 120 }; +const uint16_t EventManager::N_ELEMENTS[N_POOLS] = { + fsfwconfig::FSFW_EVENTMGMR_MATCHTREE_NODES , + fsfwconfig::FSFW_EVENTMGMT_EVENTIDMATCHERS, + fsfwconfig::FSFW_EVENTMGMR_RANGEMATCHERS }; EventManager::EventManager(object_id_t setObjectId) : SystemObject(setObjectId), diff --git a/health/HasHealthIF.h b/health/HasHealthIF.h index ac404300..86863ea8 100644 --- a/health/HasHealthIF.h +++ b/health/HasHealthIF.h @@ -1,5 +1,5 @@ -#ifndef HASHEALTHIF_H_ -#define HASHEALTHIF_H_ +#ifndef FSFW_HEALTH_HASHEALTHIF_H_ +#define FSFW_HEALTH_HASHEALTHIF_H_ #include "../events/Event.h" #include "../returnvalues/HasReturnvaluesIF.h" @@ -8,9 +8,13 @@ class HasHealthIF { public: - typedef enum { - HEALTHY = 1, FAULTY = 0, EXTERNAL_CONTROL = 2, NEEDS_RECOVERY = 3, PERMANENT_FAULTY = 4 - } HealthState; + enum HealthState: uint8_t { + HEALTHY = 1, + FAULTY = 0, + EXTERNAL_CONTROL = 2, + NEEDS_RECOVERY = 3, + PERMANENT_FAULTY = 4 + }; static const uint8_t INTERFACE_ID = CLASS_ID::HAS_HEALTH_IF; static const ReturnValue_t OBJECT_NOT_HEALTHY = MAKE_RETURN_CODE(1); @@ -31,20 +35,17 @@ public: virtual MessageQueueId_t getCommandQueue() const = 0; /** - * set the Health State - * + * @brief 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 + * @brief Get Health State + * @return Health State of the object */ virtual HasHealthIF::HealthState getHealth() = 0; }; -#endif /* HASHEALTHIF_H_ */ +#endif /* FSFW_HEALTH_HASHEALTHIF_H_ */ diff --git a/health/HealthHelper.h b/health/HealthHelper.h index d1f1945c..08889fba 100644 --- a/health/HealthHelper.h +++ b/health/HealthHelper.h @@ -12,13 +12,15 @@ #include "../returnvalues/HasReturnvaluesIF.h" /** - * Helper class for Objects that implement HasHealthIF + * @brief Helper class for Objects that implement HasHealthIF + * @details + * 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. * - * 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 + * 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 @@ -27,10 +29,9 @@ class HealthHelper { public: /** - * ctor - * * @param owner - * @param objectId the object Id to use when communication with the HealthTable + * @param objectId The object Id to use when communication with + * the HealthTable */ HealthHelper(HasHealthIF* owner, object_id_t objectId); @@ -56,8 +57,9 @@ public: * * @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) + * -@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); @@ -78,16 +80,19 @@ public: HasHealthIF::HealthState getHealth(); /** - * @param parentQueue the Queue id of the parent object. Set to 0 if no parent present + * @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 + * @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 + * -@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 ); @@ -110,11 +115,15 @@ private: 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 + * 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 informParent(HasHealthIF::HealthState health, + HasHealthIF::HealthState oldHealth); void handleSetHealthCommand(CommandMessage *message); }; diff --git a/health/HealthMessage.cpp b/health/HealthMessage.cpp index 1bb29526..52479c26 100644 --- a/health/HealthMessage.cpp +++ b/health/HealthMessage.cpp @@ -7,11 +7,13 @@ void HealthMessage::setHealthMessage(CommandMessage* message, Command_t command, message->setParameter2(oldHealth); } -void HealthMessage::setHealthMessage(CommandMessage* message, Command_t command) { +void HealthMessage::setHealthMessage(CommandMessage* message, + Command_t command) { message->setCommand(command); } -HasHealthIF::HealthState HealthMessage::getHealth(const CommandMessage* message) { +HasHealthIF::HealthState HealthMessage::getHealth( + const CommandMessage* message) { return (HasHealthIF::HealthState) message->getParameter(); } diff --git a/health/HealthMessage.h b/health/HealthMessage.h index db2a7719..fb979c66 100644 --- a/health/HealthMessage.h +++ b/health/HealthMessage.h @@ -1,5 +1,5 @@ -#ifndef HEALTHMESSAGE_H_ -#define HEALTHMESSAGE_H_ +#ifndef FSFW_HEALTH_HEALTHMESSAGE_H_ +#define FSFW_HEALTH_HEALTHMESSAGE_H_ #include "HasHealthIF.h" #include "../ipc/CommandMessage.h" @@ -7,14 +7,20 @@ 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_SET = MAKE_COMMAND_ID(1); + // No reply expected, health will be announced as event! + static const Command_t HEALTH_ANNOUNCE = MAKE_COMMAND_ID(2); + // Same as before, but all objects in health table will + // announce their health as events. + static const Command_t HEALTH_ANNOUNCE_ALL = MAKE_COMMAND_ID(3); + 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); - + HasHealthIF::HealthState health, + HasHealthIF::HealthState oldHealth = HasHealthIF::FAULTY); static void setHealthMessage(CommandMessage *message, Command_t command); static HasHealthIF::HealthState getHealth(const CommandMessage *message); @@ -27,4 +33,4 @@ private: HealthMessage(); }; -#endif /* HEALTHMESSAGE_H_ */ +#endif /* FSFW_HEALTH_HEALTHMESSAGE_H_ */ diff --git a/health/HealthTable.cpp b/health/HealthTable.cpp index 4d2564a3..2b8b6712 100644 --- a/health/HealthTable.cpp +++ b/health/HealthTable.cpp @@ -1,6 +1,7 @@ #include "HealthTable.h" -#include "../serialize/SerializeAdapter.h" +#include "../ipc/MutexHelper.h" #include "../ipc/MutexFactory.h" +#include "../serialize/SerializeAdapter.h" HealthTable::HealthTable(object_id_t objectid) : SystemObject(objectid) { @@ -9,6 +10,12 @@ HealthTable::HealthTable(object_id_t objectid) : mapIterator = healthMap.begin(); } +void HealthTable::setMutexTimeout(MutexIF::TimeoutType timeoutType, + uint32_t timeoutMs) { + this->timeoutType = timeoutType; + this->mutexTimeoutMs = timeoutMs; +} + HealthTable::~HealthTable() { MutexFactory::instance()->deleteMutex(mutex); } @@ -18,74 +25,63 @@ ReturnValue_t HealthTable::registerObject(object_id_t object, if (healthMap.count(object) != 0) { return HasReturnvaluesIF::RETURN_FAILED; } - healthMap.insert( - std::pair(object, - initilialState)); + healthMap.emplace(object, initilialState); return HasReturnvaluesIF::RETURN_OK; } void HealthTable::setHealth(object_id_t object, HasHealthIF::HealthState newState) { - mutex->lockMutex(MutexIF::BLOCKING); + MutexHelper(mutex, timeoutType, mutexTimeoutMs); 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); + MutexHelper(mutex, timeoutType, mutexTimeoutMs); 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); + MutexHelper(mutex, timeoutType, mutexTimeoutMs); HealthMap::iterator iter = healthMap.find(object); if (iter != healthMap.end()) { - exits = true; + return true; } - mutex->unlockMutex(); - return exits; + return false; +} + +size_t HealthTable::getPrintSize() { + MutexHelper(mutex, timeoutType, mutexTimeoutMs); + uint32_t size = healthMap.size() * sizeof(object_id_t) + + sizeof(HasHealthIF::HealthState) + sizeof(uint16_t); + return size; } void HealthTable::printAll(uint8_t* pointer, size_t maxSize) { - mutex->lockMutex(MutexIF::BLOCKING); + MutexHelper(mutex, timeoutType, mutexTimeoutMs); size_t size = 0; uint16_t count = healthMap.size(); - ReturnValue_t result = SerializeAdapter::serialize(&count, + 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, + for (const auto& health: healthMap) { + SerializeAdapter::serialize(&health.first, &pointer, &size, maxSize, SerializeIF::Endianness::BIG); - uint8_t health = iter->second; - result = SerializeAdapter::serialize(&health, &pointer, &size, + uint8_t healthValue = health.second; + SerializeAdapter::serialize(&healthValue, &pointer, &size, maxSize, SerializeIF::Endianness::BIG); } - mutex->unlockMutex(); } -ReturnValue_t HealthTable::iterate( - std::pair *value, bool reset) { +ReturnValue_t HealthTable::iterate(HealthEntry *value, bool reset) { ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; - mutex->lockMutex(MutexIF::BLOCKING); + MutexHelper(mutex, timeoutType, mutexTimeoutMs); if (reset) { mapIterator = healthMap.begin(); } @@ -94,7 +90,5 @@ ReturnValue_t HealthTable::iterate( } *value = *mapIterator; mapIterator++; - mutex->unlockMutex(); - return result; } diff --git a/health/HealthTable.h b/health/HealthTable.h index 6f5dd18d..cea34f68 100644 --- a/health/HealthTable.h +++ b/health/HealthTable.h @@ -1,35 +1,47 @@ -#ifndef HEALTHTABLE_H_ -#define HEALTHTABLE_H_ +#ifndef FSFW_HEALTH_HEALTHTABLE_H_ +#define FSFW_HEALTH_HEALTHTABLE_H_ #include "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); + void setMutexTimeout(MutexIF::TimeoutType timeoutType, uint32_t timeoutMs); - virtual bool hasHealth(object_id_t object); - virtual void setHealth(object_id_t object, HasHealthIF::HealthState newState); - virtual HasHealthIF::HealthState getHealth(object_id_t); + /** HealthTableIF overrides */ + virtual ReturnValue_t registerObject(object_id_t object, + HasHealthIF::HealthState initilialState = + HasHealthIF::HEALTHY) override; + virtual size_t getPrintSize() override; + virtual void printAll(uint8_t *pointer, size_t maxSize) override; - virtual uint32_t getPrintSize(); - virtual void printAll(uint8_t *pointer, size_t maxSize); + /** ManagesHealthIF overrides */ + virtual bool hasHealth(object_id_t object) override; + virtual void setHealth(object_id_t object, + HasHealthIF::HealthState newState) override; + virtual HasHealthIF::HealthState getHealth(object_id_t) override; protected: + using HealthMap = std::map; + using HealthEntry = std::pair; + MutexIF* mutex; + MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING; + uint32_t mutexTimeoutMs = 20; + HealthMap healthMap; HealthMap::iterator mapIterator; - virtual ReturnValue_t iterate(std::pair *value, bool reset = false); + virtual ReturnValue_t iterate( + HealthEntry* value, + bool reset = false) override; }; -#endif /* HEALTHTABLE_H_ */ +#endif /* FSFW_HEALTH_HEALTHTABLE_H_ */ diff --git a/health/HealthTableIF.h b/health/HealthTableIF.h index 404c03e4..d61e6761 100644 --- a/health/HealthTableIF.h +++ b/health/HealthTableIF.h @@ -1,26 +1,24 @@ -#ifndef HEALTHTABLEIF_H_ -#define HEALTHTABLEIF_H_ +#ifndef FSFW_HEALTH_HEALTHTABLEIF_H_ +#define FSFW_HEALTH_HEALTHTABLEIF_H_ #include "ManagesHealthIF.h" #include "../objectmanager/ObjectManagerIF.h" #include "../returnvalues/HasReturnvaluesIF.h" -#include - class HealthTableIF: public ManagesHealthIF { - friend class HealthCommandingService; public: - virtual ~HealthTableIF() { - } + virtual ~HealthTableIF() {} virtual ReturnValue_t registerObject(object_id_t object, HasHealthIF::HealthState initilialState = HasHealthIF::HEALTHY) = 0; - virtual uint32_t getPrintSize() = 0; + virtual size_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; + virtual ReturnValue_t iterate( + std::pair *value, + bool reset = false) = 0; }; -#endif /* HEALTHTABLEIF_H_ */ +#endif /* FRAMEWORK_HEALTH_HEALTHTABLEIF_H_ */ diff --git a/health/ManagesHealthIF.h b/health/ManagesHealthIF.h index 42d4c4f0..2edfceca 100644 --- a/health/ManagesHealthIF.h +++ b/health/ManagesHealthIF.h @@ -1,8 +1,9 @@ -#ifndef FRAMEWORK_HEALTH_MANAGESHEALTHIF_H_ -#define FRAMEWORK_HEALTH_MANAGESHEALTHIF_H_ +#ifndef FSFW_HEALTH_MANAGESHEALTHIF_H_ +#define FSFW_HEALTH_MANAGESHEALTHIF_H_ #include "HasHealthIF.h" #include "../objectmanager/ObjectManagerIF.h" + class ManagesHealthIF { public: virtual ~ManagesHealthIF() { @@ -49,4 +50,4 @@ public: } }; -#endif /* FRAMEWORK_HEALTH_MANAGESHEALTHIF_H_ */ +#endif /* FSFW_HEALTH_MANAGESHEALTHIF_H_ */ diff --git a/osal/host/QueueFactory.cpp b/osal/host/QueueFactory.cpp index da3fea55..1a679c96 100644 --- a/osal/host/QueueFactory.cpp +++ b/osal/host/QueueFactory.cpp @@ -1,6 +1,11 @@ + +#include "MessageQueue.h" + +#include "../../ipc/MessageQueueSenderIF.h" +#include "../../ipc/MessageQueueMessageIF.h" #include "../../ipc/QueueFactory.h" -#include "../../osal/host/MessageQueue.h" #include "../../serviceinterface/ServiceInterfaceStream.h" + #include QueueFactory* QueueFactory::factoryInstance = nullptr; diff --git a/returnvalues/HasReturnvaluesIF.h b/returnvalues/HasReturnvaluesIF.h index 5fef91dd..4a3835b6 100644 --- a/returnvalues/HasReturnvaluesIF.h +++ b/returnvalues/HasReturnvaluesIF.h @@ -1,8 +1,8 @@ -#ifndef FRAMEWORK_RETURNVALUES_HASRETURNVALUESIF_H_ -#define FRAMEWORK_RETURNVALUES_HASRETURNVALUESIF_H_ +#ifndef FSFW_RETURNVALUES_HASRETURNVALUESIF_H_ +#define FSFW_RETURNVALUES_HASRETURNVALUESIF_H_ #include "FwClassIds.h" -#include +#include #include #define MAKE_RETURN_CODE( number ) ((INTERFACE_ID << 8) + (number)) @@ -15,9 +15,17 @@ public: static const ReturnValue_t RETURN_FAILED = 1; virtual ~HasReturnvaluesIF() {} - static ReturnValue_t makeReturnCode(uint8_t interfaceId, uint8_t number) { - return (interfaceId << 8) + number; + /** + * 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 (static_cast(interfaceId) << 8) + number; } }; -#endif /* FRAMEWORK_RETURNVALUES_HASRETURNVALUESIF_H_ */ +#endif /* FSFW_RETURNVALUES_HASRETURNVALUESIF_H_ */ diff --git a/tcdistribution/CCSDSDistributor.cpp b/tcdistribution/CCSDSDistributor.cpp index 1ebb3185..ddd63308 100644 --- a/tcdistribution/CCSDSDistributor.cpp +++ b/tcdistribution/CCSDSDistributor.cpp @@ -1,31 +1,39 @@ -#include "../serviceinterface/ServiceInterfaceStream.h" #include "CCSDSDistributor.h" + +#include "../serviceinterface/ServiceInterfaceStream.h" #include "../tmtcpacket/SpacePacketBase.h" -CCSDSDistributor::CCSDSDistributor( uint16_t setDefaultApid, object_id_t setObjectId ) : - TcDistributor( setObjectId ), default_apid( setDefaultApid ), tcStore(NULL) { +CCSDSDistributor::CCSDSDistributor(uint16_t setDefaultApid, + object_id_t setObjectId): + TcDistributor(setObjectId), defaultApid( setDefaultApid ) { } -CCSDSDistributor::~CCSDSDistributor() { +CCSDSDistributor::~CCSDSDistributor() {} -} - -iterator_t CCSDSDistributor::selectDestination() { -// debug << "CCSDSDistributor::selectDestination received: " << this->currentMessage.getStorageId().pool_index << ", " << this->currentMessage.getStorageId().packet_index << std::endl; - const uint8_t* p_packet = NULL; +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; - //TODO check returncode? - this->tcStore->getData( this->currentMessage.getStorageId(), &p_packet, &size ); - SpacePacketBase current_packet( p_packet ); -// info << "CCSDSDistributor::selectDestination has packet with APID " << std::hex << current_packet.getAPID() << std::dec << std::endl; - iterator_t position = this->queueMap.find( current_packet.getAPID() ); + 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->default_apid ); + //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() { @@ -35,9 +43,9 @@ MessageQueueId_t CCSDSDistributor::getRequestQueue() { 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 ) { + auto insertPair = this->queueMap.emplace(application->getIdentifier(), + application->getRequestQueue()); + if(not insertPair.second) { returnValue = RETURN_FAILED; } return returnValue; @@ -46,9 +54,8 @@ ReturnValue_t CCSDSDistributor::registerApplication( 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 ) { + auto insertPair = this->queueMap.emplace(apid, id); + if(not insertPair.second) { returnValue = RETURN_FAILED; } return returnValue; @@ -62,7 +69,11 @@ uint16_t CCSDSDistributor::getIdentifier() { ReturnValue_t CCSDSDistributor::initialize() { ReturnValue_t status = this->TcDistributor::initialize(); this->tcStore = objectManager->get( objects::TC_STORE ); - if (this->tcStore == NULL) status = RETURN_FAILED; + if (this->tcStore == nullptr) { + sif::error << "CCSDSDistributor::initialize: Could not initialize" + " TC store!" << std::endl; + status = RETURN_FAILED; + } return status; } diff --git a/tcdistribution/CCSDSDistributor.h b/tcdistribution/CCSDSDistributor.h index bff72092..e8d54c9c 100644 --- a/tcdistribution/CCSDSDistributor.h +++ b/tcdistribution/CCSDSDistributor.h @@ -1,58 +1,71 @@ -#ifndef CCSDSDISTRIBUTOR_H_ -#define CCSDSDISTRIBUTOR_H_ +#ifndef FRAMEWORK_TCDISTRIBUTION_CCSDSDISTRIBUTOR_H_ +#define FRAMEWORK_TCDISTRIBUTION_CCSDSDISTRIBUTOR_H_ #include "../objectmanager/ObjectManagerIF.h" #include "../storagemanager/StorageManagerIF.h" -#include "CCSDSDistributorIF.h" -#include "TcDistributor.h" +#include "../tcdistribution/CCSDSDistributorIF.h" +#include "../tcdistribution/TcDistributor.h" #include "../tmtcservices/AcceptsTelecommandsIF.h" + /** - * An instantiation of the CCSDSDistributorIF. - * It receives Space Packets, and selects a destination depending on the APID of the telecommands. + * @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 + * @ingroup tc_distribution */ -class CCSDSDistributor : public TcDistributor, public CCSDSDistributorIF, public AcceptsTelecommandsIF { -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 default_apid, where a Acceptance Failure - * message should be generated. - * @return Iterator to map entry of found APID or iterator to default APID. - */ - iterator_t selectDestination(); - /** - * The default APID, where packets with unknown APID are sent to. - */ - uint16_t default_apid; - /** - * A reference to the TC storage must be maintained, as this class handles pure Space Packets and there - * exists no SpacePacketStored class. - */ - StorageManagerIF* tcStore; - /** - * The callback here handles the generation of acceptance success/failure messages. - */ - ReturnValue_t callbackAfterSending( ReturnValue_t queueStatus ); +class CCSDSDistributor : public TcDistributor, + public CCSDSDistributorIF, + public AcceptsTelecommandsIF { public: /** - * The constructor sets the default APID and calls the TcDistributor ctor with a certain object id. - * \c tcStore is set in the \c initialize method. - * @param set_default_apid The default APID, where packets with unknown destination are sent to. + * @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 ); + CCSDSDistributor(uint16_t setDefaultApid, object_id_t setObjectId); /** * The destructor is empty. */ - ~CCSDSDistributor(); - MessageQueueId_t getRequestQueue(); - ReturnValue_t registerApplication( uint16_t apid, MessageQueueId_t id ); - ReturnValue_t registerApplication( AcceptsTelecommandsIF* application ); - uint16_t getIdentifier(); - ReturnValue_t initialize(); + 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() override; + 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 callback here handles the generation of acceptance + * success/failure messages. + */ + ReturnValue_t callbackAfterSending( ReturnValue_t queueStatus ) 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; + }; - - -#endif /* CCSDSDISTRIBUTOR_H_ */ +#endif /* FRAMEWORK_TCDISTRIBUTION_CCSDSDISTRIBUTOR_H_ */ diff --git a/tcdistribution/CCSDSDistributorIF.h b/tcdistribution/CCSDSDistributorIF.h index be3c2811..6334a35a 100644 --- a/tcdistribution/CCSDSDistributorIF.h +++ b/tcdistribution/CCSDSDistributorIF.h @@ -1,34 +1,38 @@ -#ifndef CCSDSDISTRIBUTORIF_H_ -#define CCSDSDISTRIBUTORIF_H_ +#ifndef FSFW_TCDISTRIBUTION_CCSDSDISTRIBUTORIF_H_ +#define FSFW_TCDISTRIBUTION_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 + * 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. + * 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. + * @return - @c RETURN_OK on success, + * - @c RETURN_FAILED on failure. */ - virtual ReturnValue_t registerApplication( AcceptsTelecommandsIF* application ) = 0; + 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. + * @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; + virtual ReturnValue_t registerApplication( uint16_t apid, + MessageQueueId_t id) = 0; /** * The empty virtual destructor. */ @@ -37,4 +41,4 @@ public: }; -#endif /* CCSDSDISTRIBUTORIF_H_ */ +#endif /* FSFW_TCDISTRIBUTION_CCSDSDISTRIBUTORIF_H_ */ diff --git a/tcdistribution/PUSDistributor.cpp b/tcdistribution/PUSDistributor.cpp index f77eb99d..d964202f 100644 --- a/tcdistribution/PUSDistributor.cpp +++ b/tcdistribution/PUSDistributor.cpp @@ -1,61 +1,71 @@ -#include "../serviceinterface/ServiceInterfaceStream.h" #include "CCSDSDistributorIF.h" #include "PUSDistributor.h" + +#include "../serviceinterface/ServiceInterfaceStream.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(uint16_t setApid, object_id_t setObjectId, + object_id_t setPacketSource) : + TcDistributor(setObjectId), checker(setApid), verifyChannel(), + tcStatus(RETURN_FAILED), packetSource(setPacketSource) {} + +PUSDistributor::~PUSDistributor() {} + +PUSDistributor::TcMqMapIter PUSDistributor::selectDestination() { + // sif:: debug << "PUSDistributor::handlePacket received: " + // << this->current_packet_id.store_index << ", " + // << this->current_packet_id.packet_index << std::endl; + TcMqMapIter queueMapIt = this->queueMap.end(); + if(this->currentPacket == nullptr) { + return queueMapIt; + } + this->currentPacket->setStoreAddress(this->currentMessage.getStorageId()); + if (currentPacket->getWholeData() != nullptr) { + tcStatus = checker.checkPacket(currentPacket); +#ifdef DEBUG + if(tcStatus != HasReturnvaluesIF::RETURN_OK) { + sif::debug << "PUSDistributor::handlePacket: Packet format " + << "invalid, code "<< static_cast(tcStatus) + << std::endl; + } +#endif + 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; +#ifdef DEBUG + sif::debug << "PUSDistributor::handlePacket: Destination not found, " + << "code "<< static_cast(tcStatus) << std::endl; +#endif + } + + if (tcStatus != RETURN_OK) { + return this->queueMap.end(); + } + else { + return queueMapIt; + } } -PUSDistributor::~PUSDistributor() { - -} - -iterator_t PUSDistributor::selectDestination() { -// debug << "PUSDistributor::handlePacket received: " << this->current_packet_id.store_index << ", " << this->current_packet_id.packet_index << std::endl; - iterator_t queueMapIt = this->queueMap.end(); - this->currentPacket.setStoreAddress(this->currentMessage.getStorageId()); - if (currentPacket.getWholeData() != NULL) { - tcStatus = checker.checkPacket(¤tPacket); -// info << "PUSDistributor::handlePacket: packetCheck returned with " << (int)tc_status << 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 " << (int) tcStatus - << 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) { - ReturnValue_t returnValue = RETURN_OK; - bool errorCode = true; uint16_t serviceId = service->getIdentifier(); + // sif::info << "Service ID: " << (int)serviceId << std::endl; MessageQueueId_t queue = service->getRequestQueue(); - errorCode = this->queueMap.insert( - std::pair(serviceId, queue)).second; - if (errorCode == false) { - //TODO Return Code - returnValue = MessageQueueIF::NO_QUEUE; + auto returnPair = queueMap.emplace(serviceId, queue); + if (not returnPair.second) { + sif::error << "PUSDistributor::registerService: Service ID already" + " exists in map." << std::endl; + return SERVICE_ID_ALREADY_EXISTS; } - return returnValue; + return HasReturnvaluesIF::RETURN_OK; } MessageQueueId_t PUSDistributor::getRequestQueue() { @@ -68,13 +78,14 @@ ReturnValue_t PUSDistributor::callbackAfterSending(ReturnValue_t 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(); + currentPacket, 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); + currentPacket); return RETURN_OK; } } @@ -84,11 +95,19 @@ uint16_t PUSDistributor::getIdentifier() { } ReturnValue_t PUSDistributor::initialize() { + currentPacket = new TcPacketStored(); + if(currentPacket == nullptr) { + // Should not happen, memory allocation failed! + return ObjectManagerIF::CHILD_INIT_FAILED; + } + CCSDSDistributorIF* ccsdsDistributor = objectManager->get(packetSource); - if (ccsdsDistributor == NULL) { - return RETURN_FAILED; - } else { - return ccsdsDistributor->registerApplication(this); + if (ccsdsDistributor == nullptr) { + sif::error << "PUSDistributor::initialize: Packet source invalid." + << " Make sure it exists and implements CCSDSDistributorIF!" + << std::endl; + return RETURN_FAILED; } + return ccsdsDistributor->registerApplication(this); } diff --git a/tcdistribution/PUSDistributor.h b/tcdistribution/PUSDistributor.h index e9d4be8c..be3804ef 100644 --- a/tcdistribution/PUSDistributor.h +++ b/tcdistribution/PUSDistributor.h @@ -1,67 +1,79 @@ -#ifndef PUSDISTRIBUTOR_H_ -#define PUSDISTRIBUTOR_H_ +#ifndef FSFW_TCDISTRIBUTION_PUSDISTRIBUTOR_H_ +#define FSFW_TCDISTRIBUTION_PUSDISTRIBUTOR_H_ -#include "../returnvalues/HasReturnvaluesIF.h" #include "PUSDistributorIF.h" #include "TcDistributor.h" #include "TcPacketCheck.h" + +#include "../returnvalues/HasReturnvaluesIF.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 + * 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. + * 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. + * @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); + PUSDistributor(uint16_t setApid, object_id_t setObjectId, + object_id_t setPacketSource); /** * The destructor is empty. */ virtual ~PUSDistributor(); - ReturnValue_t registerService(AcceptsTelecommandsIF* service); - MessageQueueId_t getRequestQueue(); - uint16_t getIdentifier(); - ReturnValue_t initialize(); + 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. + * With this class, verification messages are sent to the + * TC Verification service. */ VerificationReporter verifyChannel; /** * The currently handled packet is stored here. */ - TcPacketStored currentPacket; + TcPacketStored* currentPacket = nullptr; /** - * With this variable, the current check status is stored to generate acceptance messages later. + * 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(). + * 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(). */ - iterator_t selectDestination(); + TcMqMapIter selectDestination() override; /** - * The callback here handles the generation of acceptance success/failure messages. + * The callback here handles the generation of acceptance + * success/failure messages. */ - ReturnValue_t callbackAfterSending(ReturnValue_t queueStatus); + ReturnValue_t callbackAfterSending(ReturnValue_t queueStatus) override; }; -#endif /* PUSDISTRIBUTOR_H_ */ +#endif /* FSFW_TCDISTRIBUTION_PUSDISTRIBUTOR_H_ */ diff --git a/tcdistribution/PUSDistributorIF.h b/tcdistribution/PUSDistributorIF.h index 5e27b35c..0125c08f 100644 --- a/tcdistribution/PUSDistributorIF.h +++ b/tcdistribution/PUSDistributorIF.h @@ -1,11 +1,12 @@ -#ifndef PUSDISTRIBUTORIF_H_ -#define PUSDISTRIBUTORIF_H_ +#ifndef FSFW_TCDISTRIBUTION_PUSDISTRIBUTORIF_H_ +#define FSFW_TCDISTRIBUTION_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 + * @ingroup tc_distribution */ class PUSDistributorIF { public: @@ -17,10 +18,10 @@ public: /** * 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. + * @return - @c RETURN_OK on success, + * - @c RETURN_FAILED on failure. */ virtual ReturnValue_t registerService( AcceptsTelecommandsIF* service ) = 0; }; -#endif /* PUSDISTRIBUTORIF_H_ */ +#endif /* FSFW_TCDISTRIBUTION_PUSDISTRIBUTORIF_H_ */ diff --git a/tcdistribution/TcDistributor.cpp b/tcdistribution/TcDistributor.cpp index 49a996d9..06e1817f 100644 --- a/tcdistribution/TcDistributor.cpp +++ b/tcdistribution/TcDistributor.cpp @@ -1,12 +1,13 @@ -#include "../serviceinterface/ServiceInterfaceStream.h" -#include "../serviceinterface/ServiceInterfaceStream.h" #include "TcDistributor.h" + +#include "../serviceinterface/ServiceInterfaceStream.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(object_id_t objectId) : + SystemObject(objectId) { + tcQueue = QueueFactory::instance()-> + createMessageQueue(DISTRIBUTER_MAX_PACKETS); } TcDistributor::~TcDistributor() { @@ -15,7 +16,6 @@ TcDistributor::~TcDistributor() { ReturnValue_t TcDistributor::performOperation(uint8_t opCode) { ReturnValue_t status = RETURN_OK; -// debug << "TcDistributor: performing Operation." << std::endl; for (status = tcQueue->receiveMessage(¤tMessage); status == RETURN_OK; status = tcQueue->receiveMessage(¤tMessage)) { status = handlePacket(); @@ -29,7 +29,7 @@ ReturnValue_t TcDistributor::performOperation(uint8_t opCode) { ReturnValue_t TcDistributor::handlePacket() { - iterator_t queueMapIt = this->selectDestination(); + TcMqMapIter queueMapIt = this->selectDestination(); ReturnValue_t returnValue = RETURN_FAILED; if (queueMapIt != this->queueMap.end()) { returnValue = this->tcQueue->sendMessage(queueMapIt->second, @@ -39,14 +39,14 @@ ReturnValue_t TcDistributor::handlePacket() { } void TcDistributor::print() { - sif::debug << "Distributor content is: " << std::endl << "ID\t| message queue id" - << std::endl; - for (iterator_t 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 << "Distributor content is: " << std::endl + << "ID\t| Message Queue ID" << std::endl; + sif::debug << std::setfill('0') << std::setw(8) << std::hex; + for (const auto& queueMapIter: queueMap) { + sif::debug << queueMapIter.first << "\t| 0x" << queueMapIter.second + << std::endl; } - sif::debug << std::dec; + sif::debug << std::setfill(' ') << std::dec; } diff --git a/tcdistribution/TcDistributor.h b/tcdistribution/TcDistributor.h index fed1cb3e..5d0ca45d 100644 --- a/tcdistribution/TcDistributor.h +++ b/tcdistribution/TcDistributor.h @@ -1,5 +1,6 @@ -#ifndef TCDISTRIBUTOR_H_ -#define TCDISTRIBUTOR_H_ +#ifndef FSFW_TMTCSERVICES_TCDISTRIBUTOR_H_ +#define FSFW_TMTCSERVICES_TCDISTRIBUTOR_H_ + #include "../objectmanager/ObjectManagerIF.h" #include "../objectmanager/SystemObject.h" #include "../returnvalues/HasReturnvaluesIF.h" @@ -9,16 +10,12 @@ #include "../ipc/MessageQueueIF.h" #include - /** - * \defgroup tc_distribution Telecommand Distribution - * All classes associated with Routing and Distribution of Telecommands belong to this group. + * @defgroup tc_distribution Telecommand Distribution + * All classes associated with Routing and Distribution of Telecommands + * belong to this group. */ -/** - * This typedef simplifies writing down the \c map iterator. - */ -typedef std::map::iterator iterator_t; /** * This is the base class to implement distributors for Space Packets. @@ -28,62 +25,19 @@ typedef std::map::iterator iterator_t; * 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 + * @ingroup tc_distribution */ -class TcDistributor : public SystemObject, public ExecutableObjectIF, public HasReturnvaluesIF { -private: - /** - * This constant sets the maximum number of packets distributed per call. - */ - static const uint8_t DISTRIBUTER_MAX_PACKETS = 128; -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. - */ - std::map 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 iterator_t 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 ); +class TcDistributor : public SystemObject, + public ExecutableObjectIF, + public HasReturnvaluesIF { public: - 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 ); + using TcMessageQueueMap = std::map; + using TcMqMapIter = std::map::iterator; + + static constexpr uint8_t INTERFACE_ID = CLASS_ID::PACKET_DISTRIBUTION; + static constexpr ReturnValue_t PACKET_LOST = MAKE_RETURN_CODE( 1 ); + static constexpr ReturnValue_t DESTINATION_NOT_FOUND = MAKE_RETURN_CODE( 2 ); + static constexpr ReturnValue_t SERVICE_ID_ALREADY_EXISTS = MAKE_RETURN_CODE(3); /** * Within the default constructor, the SystemObject id is set and the * message queue is initialized. @@ -91,7 +45,7 @@ public: * @param set_object_id This id is assigned to the distributor * implementation. */ - TcDistributor( object_id_t set_object_id ); + TcDistributor(object_id_t objectId); /** * The destructor is empty, the message queues are not in the vicinity of * this class. @@ -110,7 +64,59 @@ public: * queueMap. */ void print(); + +protected: + /** + * This is the receiving queue for incoming Telecommands. + * The child classes must make its queue id public. + */ + MessageQueueIF* tcQueue = nullptr; + /** + * 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 constexpr uint8_t DISTRIBUTER_MAX_PACKETS = 128; }; -#endif /* TCDISTRIBUTOR_H_ */ +#endif /* FSFW_TMTCSERVICES_TCDISTRIBUTOR_H_ */ diff --git a/tcdistribution/TcPacketCheck.cpp b/tcdistribution/TcPacketCheck.cpp index b5881083..38ed04aa 100644 --- a/tcdistribution/TcPacketCheck.cpp +++ b/tcdistribution/TcPacketCheck.cpp @@ -1,31 +1,33 @@ +#include "TcPacketCheck.h" + #include "../globalfunctions/CRC.h" #include "../serviceinterface/ServiceInterfaceStream.h" #include "../storagemanager/StorageManagerIF.h" -#include "TcPacketCheck.h" #include "../tmtcservices/VerificationCodes.h" -TcPacketCheck::TcPacketCheck( uint16_t set_apid ) : apid(set_apid) { +TcPacketCheck::TcPacketCheck( uint16_t setApid ) : apid(setApid) { } -ReturnValue_t TcPacketCheck::checkPacket( TcPacketStored* current_packet ) { - uint16_t calculated_crc = CRC::crc16ccitt( current_packet->getWholeData(), current_packet->getFullSize() ); +ReturnValue_t TcPacketCheck::checkPacket( TcPacketStored* currentPacket ) { + uint16_t calculated_crc = CRC::crc16ccitt( currentPacket->getWholeData(), + currentPacket->getFullSize() ); if ( calculated_crc != 0 ) { return INCORRECT_CHECKSUM; } - bool condition = !(current_packet->hasSecondaryHeader()) || - current_packet->getPacketVersionNumber() != CCSDS_VERSION_NUMBER || - !(current_packet->isTelecommand()); + bool condition = (not currentPacket->hasSecondaryHeader()) or + (currentPacket->getPacketVersionNumber() != CCSDS_VERSION_NUMBER) or + (not currentPacket->isTelecommand()); if ( condition ) { return INCORRECT_PRIMARY_HEADER; } - if ( current_packet->getAPID() != this->apid ) + if ( currentPacket->getAPID() != this->apid ) return ILLEGAL_APID; - if ( !current_packet->isSizeCorrect() ) { + if ( not currentPacket->isSizeCorrect() ) { return INCOMPLETE_PACKET; } - condition = (current_packet->getSecondaryHeaderFlag() != CCSDS_SECONDARY_HEADER_FLAG) || - (current_packet->getPusVersionNumber() != PUS_VERSION_NUMBER); + condition = (currentPacket->getSecondaryHeaderFlag() != CCSDS_SECONDARY_HEADER_FLAG) || + (currentPacket->getPusVersionNumber() != PUS_VERSION_NUMBER); if ( condition ) { return INCORRECT_SECONDARY_HEADER; } diff --git a/tcdistribution/TcPacketCheck.h b/tcdistribution/TcPacketCheck.h index 4ba269f5..703bb1bb 100644 --- a/tcdistribution/TcPacketCheck.h +++ b/tcdistribution/TcPacketCheck.h @@ -1,28 +1,29 @@ -#ifndef TCPACKETCHECK_H_ -#define TCPACKETCHECK_H_ +#ifndef FSFW_TCDISTRIBUTION_TCPACKETCHECK_H_ +#define FSFW_TCDISTRIBUTION_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 + * @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; + static constexpr 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; + static constexpr 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; + static constexpr uint8_t PUS_VERSION_NUMBER = 1; /** * The packet id each correct packet should have. * It is composed of the APID and some static fields. @@ -41,19 +42,19 @@ public: * The constructor only sets the APID attribute. * @param set_apid The APID to set. */ - TcPacketCheck( uint16_t set_apid ); + TcPacketCheck( uint16_t setApid ); /** * 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. + * @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 ); + ReturnValue_t checkPacket( TcPacketStored* currentPacket ); uint16_t getApid() const; }; -#endif /* TCPACKETCHECK_H_ */ +#endif /* FSFW_TCDISTRIBUTION_TCPACKETCHECK_H_ */ diff --git a/timemanager/CCSDSTime.cpp b/timemanager/CCSDSTime.cpp index f99f8fbb..f137e030 100644 --- a/timemanager/CCSDSTime.cpp +++ b/timemanager/CCSDSTime.cpp @@ -1,8 +1,9 @@ -#include "../timemanager/CCSDSTime.h" +#include "CCSDSTime.h" + #include #include #include - +#include CCSDSTime::CCSDSTime() { } @@ -158,15 +159,16 @@ ReturnValue_t CCSDSTime::convertFromASCII(Clock::TimeOfDay_t* to, const uint8_t* } // 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 +#if FSFW_NO_C99_IO == 1 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); + 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; @@ -179,12 +181,13 @@ ReturnValue_t CCSDSTime::convertFromASCII(Clock::TimeOfDay_t* to, const uint8_t* } // try Code B (yyyy-ddd) - count = sscanf((char *) from, "%4" SCNu16 "-%3" SCNu16 "T%2" SCNu16 ":%2" SCNu16 ":%fZ", &year, &day, - &hour, &minute, &second); + 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)); + reinterpret_cast(&month), + reinterpret_cast(&tempDay)); if (result != RETURN_OK) { return RETURN_FAILED; } diff --git a/timemanager/TimeStamperIF.h b/timemanager/TimeStamperIF.h index bdc5e7e3..96011088 100644 --- a/timemanager/TimeStamperIF.h +++ b/timemanager/TimeStamperIF.h @@ -14,8 +14,12 @@ 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; + //! This is a mission-specific constant and determines the total + //! size reserved for timestamps. + //! TODO: Default define in FSFWConfig ? + static const uint8_t MISSION_TIMESTAMP_SIZE = 8; + virtual ReturnValue_t addTimeStamp(uint8_t* buffer, + const uint8_t maxSize) = 0; virtual ~TimeStamperIF() {} }; diff --git a/tmtcpacket/SpacePacketBase.cpp b/tmtcpacket/SpacePacketBase.cpp index a37e024b..e13af8d0 100644 --- a/tmtcpacket/SpacePacketBase.cpp +++ b/tmtcpacket/SpacePacketBase.cpp @@ -1,6 +1,6 @@ -#include "../serviceinterface/ServiceInterfaceStream.h" #include "SpacePacketBase.h" -#include +#include "../serviceinterface/ServiceInterfaceStream.h" +#include SpacePacketBase::SpacePacketBase( const uint8_t* set_address ) { this->data = (SpacePacketPointer*) set_address; @@ -14,7 +14,8 @@ 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) { +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. @@ -81,7 +82,7 @@ void SpacePacketBase::setPacketDataLength( uint16_t new_length) { this->data->header.packet_length_l = ( new_length & 0x00FF ); } -uint32_t SpacePacketBase::getFullSize() { +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; } diff --git a/tmtcpacket/SpacePacketBase.h b/tmtcpacket/SpacePacketBase.h index ef3ad79d..19cbd074 100644 --- a/tmtcpacket/SpacePacketBase.h +++ b/tmtcpacket/SpacePacketBase.h @@ -1,10 +1,11 @@ -#ifndef SPACEPACKETBASE_H_ -#define SPACEPACKETBASE_H_ +#ifndef FSFW_TMTCPACKET_SPACEPACKETBASE_H_ +#define FSFW_TMTCPACKET_SPACEPACKETBASE_H_ #include "ccsds_header.h" +#include /** - * \defgroup tmtcpackets Space Packets + * @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 @@ -81,7 +82,8 @@ public: */ bool isTelecommand( void ); - void initSpacePacketHeader(bool isTelecommand, bool hasSecondaryHeader, uint16_t apid, uint16_t sequenceCount = 0); + 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. @@ -167,10 +169,10 @@ public: * This method returns the full raw packet size. * @return The full size of the packet in bytes. */ - uint32_t getFullSize(); + size_t getFullSize(); uint32_t getApidAndSequenceCount() const; }; -#endif /* SPACEPACKETBASE_H_ */ +#endif /* FSFW_TMTCPACKET_SPACEPACKETBASE_H_ */ diff --git a/tmtcpacket/pus/PacketTimestampInterpreterIF.h b/tmtcpacket/pus/PacketTimestampInterpreterIF.h index dd0c0328..40e7a2ea 100644 --- a/tmtcpacket/pus/PacketTimestampInterpreterIF.h +++ b/tmtcpacket/pus/PacketTimestampInterpreterIF.h @@ -7,7 +7,8 @@ class TmPacketMinimal; class PacketTimestampInterpreterIF { public: virtual ~PacketTimestampInterpreterIF() {} - virtual ReturnValue_t getPacketTime(TmPacketMinimal* packet, timeval* timestamp) const = 0; + 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; }; diff --git a/tmtcpacket/pus/TcPacketBase.cpp b/tmtcpacket/pus/TcPacketBase.cpp index 3815eb20..eaa8416a 100644 --- a/tmtcpacket/pus/TcPacketBase.cpp +++ b/tmtcpacket/pus/TcPacketBase.cpp @@ -1,11 +1,14 @@ -#include "../../globalfunctions/CRC.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" #include "TcPacketBase.h" -#include -TcPacketBase::TcPacketBase(const uint8_t* set_data) : - SpacePacketBase(set_data) { - tcData = (TcPacketPointer*) set_data; +#include "../../globalfunctions/CRC.h" +#include "../../globalfunctions/arrayprinter.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" + +#include + +TcPacketBase::TcPacketBase(const uint8_t* setData) : + SpacePacketBase(setData) { + tcData = reinterpret_cast(const_cast(setData)); } TcPacketBase::~TcPacketBase() { @@ -13,28 +16,28 @@ TcPacketBase::~TcPacketBase() { } uint8_t TcPacketBase::getService() { - return tcData->data_field.service_type; + return tcData->dataField.service_type; } uint8_t TcPacketBase::getSubService() { - return tcData->data_field.service_subtype; + return tcData->dataField.service_subtype; } uint8_t TcPacketBase::getAcknowledgeFlags() { - return tcData->data_field.version_type_ack & 0b00001111; + return tcData->dataField.version_type_ack & 0b00001111; } const uint8_t* TcPacketBase::getApplicationData() const { - return &tcData->data; + return &tcData->appData; } uint16_t TcPacketBase::getApplicationDataSize() { - return getPacketDataLength() - sizeof(tcData->data_field) - CRC_SIZE + 1; + return getPacketDataLength() - sizeof(tcData->dataField) - CRC_SIZE + 1; } uint16_t TcPacketBase::getErrorControl() { uint16_t size = getApplicationDataSize() + CRC_SIZE; - uint8_t* p_to_buffer = &tcData->data; + uint8_t* p_to_buffer = &tcData->appData; return (p_to_buffer[size - 2] << 8) + p_to_buffer[size - 1]; } @@ -42,41 +45,42 @@ void TcPacketBase::setErrorControl() { uint32_t full_size = getFullSize(); uint16_t crc = CRC::crc16ccitt(getWholeData(), full_size - CRC_SIZE); uint32_t size = getApplicationDataSize(); - (&tcData->data)[size] = (crc & 0XFF00) >> 8; // CRCH - (&tcData->data)[size + 1] = (crc) & 0X00FF; // CRCL + (&tcData->appData)[size] = (crc & 0XFF00) >> 8; // CRCH + (&tcData->appData)[size + 1] = (crc) & 0X00FF; // CRCL } -void TcPacketBase::setData(const uint8_t* p_Data) { - SpacePacketBase::setData(p_Data); - tcData = (TcPacketPointer*) p_Data; +void TcPacketBase::setData(const uint8_t* pData) { + SpacePacketBase::setData(pData); + tcData = (TcPacketPointer*) pData; } uint8_t TcPacketBase::getSecondaryHeaderFlag() { - return (tcData->data_field.version_type_ack & 0b10000000) >> 7; + return (tcData->dataField.version_type_ack & 0b10000000) >> 7; } uint8_t TcPacketBase::getPusVersionNumber() { - return (tcData->data_field.version_type_ack & 0b01110000) >> 4; + 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; + sif::debug << "TcPacketBase::print: " << std::endl; + arrayprinter::print(getWholeData(), getFullSize()); } void TcPacketBase::initializeTcPacket(uint16_t apid, uint16_t sequenceCount, - uint8_t ack, uint8_t service, uint8_t subservice) { + uint8_t ack, uint8_t service, uint8_t subservice) { initSpacePacketHeader(true, true, apid, sequenceCount); - memset(&tcData->data_field, 0, sizeof(tcData->data_field)); - setPacketDataLength(sizeof(tcData->data_field) + CRC_SIZE); + std::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->data_field.version_type_ack = 0b00010000; - tcData->data_field.version_type_ack |= (ack & 0x0F); - tcData->data_field.service_type = service; - tcData->data_field.service_subtype = subservice; + //Set CCSDS_secondary_header_flag to 0 and version number to 001 + 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 dd63d2be..582a2214 100644 --- a/tmtcpacket/pus/TcPacketBase.h +++ b/tmtcpacket/pus/TcPacketBase.h @@ -1,7 +1,9 @@ -#ifndef TCPACKETBASE_H_ -#define TCPACKETBASE_H_ +#ifndef TMTCPACKET_PUS_TCPACKETBASE_H_ +#define TMTCPACKET_PUS_TCPACKETBASE_H_ #include "../../tmtcpacket/SpacePacketBase.h" +#include + /** * This struct defines a byte-wise structured PUS TC Data Field Header. @@ -23,14 +25,14 @@ struct PUSTcDataFieldHeader { */ struct TcPacketPointer { CCSDSPrimaryHeader primary; - PUSTcDataFieldHeader data_field; - uint8_t data; + 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 + * 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 @@ -39,67 +41,38 @@ struct TcPacketPointer { * @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; + static const uint16_t TC_PACKET_MIN_SIZE = (sizeof(CCSDSPrimaryHeader) + + sizeof(PUSTcDataFieldHeader) + 2); + + enum AckField { + //! No acknowledgements are expected. + ACK_NONE = 0b0000, + //! Acknowledgements on acceptance are expected. + ACK_ACCEPTANCE = 0b0001, + //! Acknowledgements on start are expected. + ACK_START = 0b0010, + //! Acknowledgements on step are expected. + ACK_STEP = 0b0100, + //! Acknowledfgement on completion are expected. + ACK_COMPLETION = 0b1000 + }; + + static constexpr uint8_t ACK_ALL = ACK_ACCEPTANCE | ACK_START | ACK_STEP | + ACK_COMPLETION; + /** * 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. + * @param setData The position where the packet data lies. */ - TcPacketBase( const uint8_t* set_data ); + TcPacketBase( const uint8_t* setData ); /** * 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 @@ -166,22 +139,49 @@ public: * current content of the packet. */ void setErrorControl(); - /** - * 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* p_data ); + /** * 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); + +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; + + /** + * 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); + + /** + * 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 ); }; -#endif /* TCPACKETBASE_H_ */ +#endif /* TMTCPACKET_PUS_TCPACKETBASE_H_ */ diff --git a/tmtcpacket/pus/TcPacketStored.cpp b/tmtcpacket/pus/TcPacketStored.cpp index 216f89c9..fffc86ae 100644 --- a/tmtcpacket/pus/TcPacketStored.cpp +++ b/tmtcpacket/pus/TcPacketStored.cpp @@ -1,37 +1,50 @@ +#include "TcPacketStored.h" #include "../../objectmanager/ObjectManagerIF.h" #include "../../serviceinterface/ServiceInterfaceStream.h" -#include "TcPacketStored.h" -#include + +#include + +StorageManagerIF* TcPacketStored::store = nullptr; TcPacketStored::TcPacketStored(store_address_t setAddress) : - TcPacketBase(NULL), storeAddress(setAddress) { - this->setStoreAddress(this->storeAddress); + TcPacketBase(nullptr), storeAddress(setAddress) { + setStoreAddress(storeAddress); } -TcPacketStored::TcPacketStored(uint16_t apid, uint8_t ack, uint8_t service, - uint8_t subservice, uint8_t sequence_count, const uint8_t* data, - uint32_t size) : - TcPacketBase(NULL) { +TcPacketStored::TcPacketStored(uint16_t apid, uint8_t service, + uint8_t subservice, uint8_t sequenceCount, const uint8_t* data, + size_t size, uint8_t ack) : + TcPacketBase(nullptr) { this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; - if (!this->checkAndSetStore()) { + if (not this->checkAndSetStore()) { return; } - uint8_t* p_data = NULL; + uint8_t* pData = nullptr; ReturnValue_t returnValue = this->store->getFreeElement(&this->storeAddress, - (TC_PACKET_MIN_SIZE + size), &p_data); + (TC_PACKET_MIN_SIZE + size), &pData); 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->data, data, size); + this->setData(pData); + initializeTcPacket(apid, sequenceCount, ack, service, subservice); + memcpy(&tcData->appData, data, size); this->setPacketDataLength( size + sizeof(PUSTcDataFieldHeader) + CRC_SIZE - 1); this->setErrorControl(); } -TcPacketStored::TcPacketStored() : - TcPacketBase(NULL) { +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(nullptr) { this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; this->checkAndSetStore(); @@ -40,14 +53,14 @@ TcPacketStored::TcPacketStored() : ReturnValue_t TcPacketStored::deletePacket() { ReturnValue_t result = this->store->deleteData(this->storeAddress); this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; - this->setData( NULL); + this->setData(nullptr); return result; } bool TcPacketStored::checkAndSetStore() { - if (this->store == NULL) { + if (this->store == nullptr) { this->store = objectManager->get(objects::TC_STORE); - if (this->store == NULL) { + if (this->store == nullptr) { sif::error << "TcPacketStored::TcPacketStored: TC Store not found!" << std::endl; return false; @@ -58,17 +71,17 @@ bool TcPacketStored::checkAndSetStore() { void TcPacketStored::setStoreAddress(store_address_t setAddress) { this->storeAddress = setAddress; - const uint8_t* temp_data = NULL; + const uint8_t* tempData = nullptr; size_t temp_size; ReturnValue_t status = StorageManagerIF::RETURN_FAILED; if (this->checkAndSetStore()) { - status = this->store->getData(this->storeAddress, &temp_data, + status = this->store->getData(this->storeAddress, &tempData, &temp_size); } if (status == StorageManagerIF::RETURN_OK) { - this->setData(temp_data); + this->setData(tempData); } else { - this->setData(NULL); + this->setData(nullptr); this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; } } @@ -78,7 +91,7 @@ store_address_t TcPacketStored::getStoreAddress() { } bool TcPacketStored::isSizeCorrect() { - const uint8_t* temp_data = NULL; + const uint8_t* temp_data = nullptr; size_t temp_size; ReturnValue_t status = this->store->getData(this->storeAddress, &temp_data, &temp_size); @@ -90,8 +103,6 @@ bool TcPacketStored::isSizeCorrect() { return false; } -StorageManagerIF* TcPacketStored::store = NULL; - TcPacketStored::TcPacketStored(const uint8_t* data, uint32_t size) : TcPacketBase(data) { if (getFullSize() != size) { @@ -100,7 +111,7 @@ TcPacketStored::TcPacketStored(const uint8_t* data, uint32_t size) : if (this->checkAndSetStore()) { ReturnValue_t status = store->addData(&storeAddress, data, size); if (status != HasReturnvaluesIF::RETURN_OK) { - this->setData(NULL); + this->setData(nullptr); } } } diff --git a/tmtcpacket/pus/TcPacketStored.h b/tmtcpacket/pus/TcPacketStored.h index 2d86f89b..1666107b 100644 --- a/tmtcpacket/pus/TcPacketStored.h +++ b/tmtcpacket/pus/TcPacketStored.h @@ -1,8 +1,8 @@ -#ifndef TCPACKETSTORED_H_ -#define TCPACKETSTORED_H_ +#ifndef TMTCPACKET_PUS_TCPACKETSTORED_H_ +#define TMTCPACKET_PUS_TCPACKETSTORED_H_ -#include "../../storagemanager/StorageManagerIF.h" #include "TcPacketBase.h" +#include "../../storagemanager/StorageManagerIF.h" /** * This class generates a ECSS PUS Telecommand packet within a given @@ -15,26 +15,6 @@ * @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. @@ -53,18 +33,20 @@ public: * 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. + * 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. + * 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. + * @param ack Set's the packet's Ack field, which specifies + * number of verification packets returned + * for this command. */ - TcPacketStored( uint16_t apid, uint8_t ack, uint8_t service, uint8_t subservice, uint8_t sequence_count = 0, const uint8_t* data = NULL, uint32_t size = 0 ); + TcPacketStored(uint16_t apid, uint8_t service, uint8_t subservice, + 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. @@ -72,10 +54,19 @@ public: * @param Size size of the packet. */ TcPacketStored( const uint8_t* data, uint32_t size); + + /** + * Getter function for the raw data. + * @param dataPtr [out] Pointer to the data pointer to set + * @param dataSize [out] Address of size to set. + * @return -@c RETURN_OK if data was retrieved successfully. + */ + 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. + * @return The current store address. The (raw) value is + * @c StorageManagerIF::INVALID_ADDRESS if the packet is not linked. */ store_address_t getStoreAddress(); /** @@ -99,7 +90,28 @@ public: * store or size is incorrect. */ bool isSizeCorrect(); + +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(); }; -#endif /* TCPACKETSTORED_H_ */ +#endif /* TMTCPACKET_PUS_TCPACKETSTORED_H_ */ diff --git a/tmtcpacket/pus/TmPacketBase.cpp b/tmtcpacket/pus/TmPacketBase.cpp index 3c1a8ca4..f3bc3f00 100644 --- a/tmtcpacket/pus/TmPacketBase.cpp +++ b/tmtcpacket/pus/TmPacketBase.cpp @@ -1,13 +1,19 @@ +#include "TmPacketBase.h" + #include "../../globalfunctions/CRC.h" +#include "../../globalfunctions/arrayprinter.h" #include "../../objectmanager/ObjectManagerIF.h" #include "../../serviceinterface/ServiceInterfaceStream.h" -#include "TmPacketBase.h" #include "../../timemanager/CCSDSTime.h" -#include -TmPacketBase::TmPacketBase(uint8_t* set_data) : - SpacePacketBase(set_data) { - tm_data = (TmPacketPointer*) set_data; +#include + +TimeStamperIF* TmPacketBase::timeStamper = nullptr; +object_id_t TmPacketBase::timeStamperId = 0; + +TmPacketBase::TmPacketBase(uint8_t* setData) : + SpacePacketBase(setData) { + tmData = reinterpret_cast(setData); } TmPacketBase::~TmPacketBase() { @@ -15,25 +21,25 @@ TmPacketBase::~TmPacketBase() { } uint8_t TmPacketBase::getService() { - return tm_data->data_field.service_type; + return tmData->data_field.service_type; } uint8_t TmPacketBase::getSubService() { - return tm_data->data_field.service_subtype; + return tmData->data_field.service_subtype; } uint8_t* TmPacketBase::getSourceData() { - return &tm_data->data; + return &tmData->data; } uint16_t TmPacketBase::getSourceDataSize() { - return getPacketDataLength() - sizeof(tm_data->data_field) + return getPacketDataLength() - sizeof(tmData->data_field) - CRC_SIZE + 1; } uint16_t TmPacketBase::getErrorControl() { uint32_t size = getSourceDataSize() + CRC_SIZE; - uint8_t* p_to_buffer = &tm_data->data; + uint8_t* p_to_buffer = &tmData->data; return (p_to_buffer[size - 2] << 8) + p_to_buffer[size - 1]; } @@ -47,16 +53,12 @@ void TmPacketBase::setErrorControl() { void TmPacketBase::setData(const uint8_t* p_Data) { SpacePacketBase::setData(p_Data); - tm_data = (TmPacketPointer*) p_Data; + tmData = (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;*/ + sif::debug << "TmPacketBase::print: " << std::endl; + arrayprinter::print(getWholeData(), getFullSize()); } bool TmPacketBase::checkAndSetStamper() { @@ -73,32 +75,36 @@ bool TmPacketBase::checkAndSetStamper() { 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)); + return CCSDSTime::convertFromCcsds(timestamp, tmData->data_field.time, + &tempSize, sizeof(tmData->data_field.time)); } uint8_t* TmPacketBase::getPacketTimeRaw() const{ - return tm_data->data_field.time; + return tmData->data_field.time; } -void TmPacketBase::initializeTmPacket(uint16_t apid, uint8_t service, uint8_t subservice, uint8_t packetSubcounter) { +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 + memset(&tmData->data_field, 0, sizeof(tmData->data_field)); + // 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; + // The other 4 bits of the first byte are the spacecraft time reference + // status. To change to PUS-C, set 0b00100000. + // Set CCSDS_secondary header flag to 0, version number to 001 and ack + // to 0000 + tmData->data_field.version_type_ack = 0b00010000; + tmData->data_field.service_type = service; + tmData->data_field.service_subtype = subservice; + tmData->data_field.subcounter = packetSubcounter; //Timestamp packet if (checkAndSetStamper()) { - timeStamper->addTimeStamp(tm_data->data_field.time, sizeof(tm_data->data_field.time)); + timeStamper->addTimeStamp(tmData->data_field.time, + sizeof(tmData->data_field.time)); } } @@ -106,9 +112,6 @@ 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); +size_t TmPacketBase::getTimestampSize() const { + return sizeof(tmData->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 85ae4dac..6efc0165 100644 --- a/tmtcpacket/pus/TmPacketBase.h +++ b/tmtcpacket/pus/TmPacketBase.h @@ -1,8 +1,8 @@ -#ifndef TMPACKETBASE_H_ -#define TMPACKETBASE_H_ +#ifndef TMTCPACKET_PUS_TMPACKETBASE_H_ +#define TMTCPACKET_PUS_TMPACKETBASE_H_ +#include "../SpacePacketBase.h" #include "../../timemanager/TimeStamperIF.h" -#include "../../tmtcpacket/SpacePacketBase.h" #include "../../timemanager/Clock.h" #include "../../objectmanager/SystemObjectIF.h" @@ -14,7 +14,7 @@ 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]. + * for a time tag. * @ingroup tmtcpackets */ struct PUSTmDataFieldHeader { @@ -40,7 +40,7 @@ struct TmPacketPointer { /** * This class is the basic data handler for any ECSS PUS Telemetry packet. * - * In addition to \SpacePacketBase, the class provides methods to handle + * 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 @@ -54,29 +54,27 @@ 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. + static const uint32_t TM_PACKET_MIN_SIZE = (sizeof(CCSDSPrimaryHeader) + + sizeof(PUSTmDataFieldHeader) + 2); + //! Maximum size of a TM Packet in this mission. + //! TODO: Make this dependant on a config variable. + static const uint32_t MISSION_TM_PACKET_MAX_SIZE = 2048; + //! First byte of secondary header for PUS-A packets. + //! TODO: Maybe also support PUS-C via config? + static const uint8_t VERSION_NUMBER_BYTE_PUS_A = 0b00010000; + /** * 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 ); + TmPacketBase( uint8_t* setData ); /** * 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. @@ -106,11 +104,14 @@ public: */ 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); + /** + * With this method, the Error Control Field is updated to match the + * current content of the packet. This method is not protected because + * a recalculation by the user might be necessary when manipulating fields + * like the sequence count. + */ + void setErrorControl(); + /** * This getter returns the Error Control Field of the packet. * @@ -120,28 +121,15 @@ public: * @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(); - /** - * 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. + * 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; @@ -151,7 +139,7 @@ public: */ uint8_t* getPacketTimeRaw() const; - uint32_t getTimestampSize() const; + size_t getTimestampSize() const; protected: /** @@ -160,20 +148,49 @@ protected: * * To be hardware-safe, all elements are of byte size. */ - TmPacketPointer* tm_data; + TmPacketPointer* tmData; /** * The timeStamper is responsible for adding a timestamp to the packet. * It is initialized lazy. */ static TimeStamperIF* timeStamper; + //! The ID to use when looking for a time stamper. + static object_id_t timeStamperId; - 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(); + /** + * 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); + + /** + * 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* pData ); + + /** + * 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); + + /** + * 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_ */ +#endif /* TMTCPACKET_PUS_TMPACKETBASE_H_ */ diff --git a/tmtcpacket/pus/TmPacketStored.cpp b/tmtcpacket/pus/TmPacketStored.cpp index 4e4c9434..0fb789aa 100644 --- a/tmtcpacket/pus/TmPacketStored.cpp +++ b/tmtcpacket/pus/TmPacketStored.cpp @@ -1,11 +1,16 @@ +#include "TmPacketStored.h" + #include "../../objectmanager/ObjectManagerIF.h" #include "../../serviceinterface/ServiceInterfaceStream.h" -#include "TmPacketStored.h" #include "../../tmtcservices/TmTcMessage.h" -#include + +#include + +StorageManagerIF *TmPacketStored::store = nullptr; +InternalErrorReporterIF *TmPacketStored::internalErrorReporter = nullptr; TmPacketStored::TmPacketStored(store_address_t setAddress) : - TmPacketBase(NULL), storeAddress(setAddress) { + TmPacketBase(nullptr), storeAddress(setAddress) { setStoreAddress(storeAddress); } @@ -14,10 +19,10 @@ TmPacketStored::TmPacketStored(uint16_t apid, uint8_t service, uint32_t size, const uint8_t *headerData, uint32_t headerSize) : TmPacketBase(NULL) { storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; - if (!checkAndSetStore()) { + if (not checkAndSetStore()) { return; } - uint8_t *pData = NULL; + uint8_t *pData = nullptr; ReturnValue_t returnValue = store->getFreeElement(&storeAddress, (TmPacketBase::TM_PACKET_MIN_SIZE + size + headerSize), &pData); @@ -38,7 +43,7 @@ TmPacketStored::TmPacketStored(uint16_t apid, uint8_t service, SerializeIF *header) : TmPacketBase(NULL) { storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; - if (!checkAndSetStore()) { + if (not checkAndSetStore()) { return; } size_t sourceDataSize = 0; @@ -77,29 +82,29 @@ store_address_t TmPacketStored::getStoreAddress() { void TmPacketStored::deletePacket() { store->deleteData(storeAddress); storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; - setData(NULL); + setData(nullptr); } void TmPacketStored::setStoreAddress(store_address_t setAddress) { storeAddress = setAddress; - const uint8_t* temp_data = NULL; - size_t temp_size; - if (!checkAndSetStore()) { + const uint8_t* tempData = nullptr; + size_t tempSize; + if (not checkAndSetStore()) { return; } - ReturnValue_t status = store->getData(storeAddress, &temp_data, &temp_size); + ReturnValue_t status = store->getData(storeAddress, &tempData, &tempSize); if (status == StorageManagerIF::RETURN_OK) { - setData(temp_data); + setData(tempData); } else { - setData(NULL); + setData(nullptr); storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; } } bool TmPacketStored::checkAndSetStore() { - if (store == NULL) { + if (store == nullptr) { store = objectManager->get(objects::TM_STORE); - if (store == NULL) { + if (store == nullptr) { sif::error << "TmPacketStored::TmPacketStored: TM Store not found!" << std::endl; return false; @@ -108,12 +113,9 @@ bool TmPacketStored::checkAndSetStore() { 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) { + if (getWholeData() == nullptr) { //SHOULDDO: More decent code. return HasReturnvaluesIF::RETURN_FAILED; } @@ -133,11 +135,11 @@ ReturnValue_t TmPacketStored::sendPacket(MessageQueueId_t destination, } void TmPacketStored::checkAndReportLostTm() { - if (internalErrorReporter == NULL) { + if (internalErrorReporter == nullptr) { internalErrorReporter = objectManager->get( objects::INTERNAL_ERROR_REPORTER); } - if (internalErrorReporter != NULL) { + if (internalErrorReporter != nullptr) { internalErrorReporter->lostTm(); } } diff --git a/tmtcpacket/pus/TmPacketStored.h b/tmtcpacket/pus/TmPacketStored.h index 8962d343..6ddbf131 100644 --- a/tmtcpacket/pus/TmPacketStored.h +++ b/tmtcpacket/pus/TmPacketStored.h @@ -1,9 +1,10 @@ -#ifndef TMPACKETSTORED_H_ -#define TMPACKETSTORED_H_ +#ifndef TMTCPACKET_PUS_TMPACKETSTORED_H_ +#define TMTCPACKET_PUS_TMPACKETSTORED_H_ + +#include "TmPacketBase.h" #include "../../serialize/SerializeIF.h" #include "../../storagemanager/StorageManagerIF.h" -#include "TmPacketBase.h" #include "../../internalError/InternalErrorReporterIF.h" #include "../../ipc/MessageQueueSenderIF.h" @@ -18,31 +19,6 @@ * @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. @@ -52,28 +28,38 @@ public: /** * 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. + * 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 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 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); + TmPacketStored( uint16_t apid, uint8_t service, uint8_t subservice, + uint8_t packet_counter = 0, const uint8_t* data = nullptr, + uint32_t size = 0, const uint8_t* headerData = nullptr, + uint32_t headerSize = 0); /** - * Another ctor to directly pass structured content and header data to the packet to avoid additional buffers. + * 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); + TmPacketStored( uint16_t apid, uint8_t service, uint8_t subservice, + uint8_t packet_counter, SerializeIF* content, + SerializeIF* header = nullptr); /** * 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 + * @return The current store address. The (raw) value is + * @c StorageManagerIF::INVALID_ADDRESS if * the packet is not linked. */ store_address_t getStoreAddress(); @@ -89,8 +75,34 @@ public: */ void setStoreAddress( store_address_t setAddress ); - ReturnValue_t sendPacket( MessageQueueId_t destination, MessageQueueId_t sentFrom, bool doErrorReporting = true ); + ReturnValue_t sendPacket( MessageQueueId_t destination, + MessageQueueId_t sentFrom, bool doErrorReporting = true ); +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(); }; -#endif /* TMPACKETSTORED_H_ */ +#endif /* TMTCPACKET_PUS_TMPACKETSTORED_H_ */ diff --git a/unittest/README.md b/unittest/README.md new file mode 100644 index 00000000..8a787c07 --- /dev/null +++ b/unittest/README.md @@ -0,0 +1,59 @@ +## FSFW Testing +This repository contains testing and unit testing components. + +[Catch2](https://github.com/catchorg/Catch2) has been used as a framework, +and these unit tests can only be run on a linux host machine. +The makefile with default settings creates the unit test binary which can be +run in the terminal or in eclipse. + +### Instructions + +To run the fsfw unittests in the project, perform following steps: + +1. Copy the testcfg folder the project root (folder containing the FSFW). +2. There is a makefile inside the testcfg folder which can be used to have + a starting point to compile the unit tests. Copy that Makefile to the project + root +3. Create a folder named catch2 (can have other name which requires Makefile + adaption) and copy the Catch2 header files there (NOTE: CMake support + not enabled yet!) + +### Eclipse CDT settings + +The default eclipse terminal has issues displaying the colors used +when running the unit test binary by catch2. To fix this issue, +install the ANSI Escape In Console package from the eclipse marketplace. + +### GCOV integration + +GCOV has been integrated as a code coverage tool. +It can be enabled by adding `GCOV=1` to the build process as an additional argument. +Coverage data will be provided in form of .gcno and .gcda files. +These can be displayed in eclipse by looking +for a .gcno or .gcda file in the \_obj folder, double-clicking it +and picking the right source-binary. This will generate +information about which lines of a file have run, provided it is open in +eclipse. + +### LCOV integration + +The files generated by GCOV can also be processed by the tool LCOV. +On ubuntu, the tool can be installed with the following command: + +```sh +sudo apt-get install lcov +```` + +After that, the tool can be run by building the unit tests with `GCOV=1`, +running them at least one time and then executing the `lcov.sh` script. + +### Adding unit tests + +The catch unit tests are located in unittest/testfw. To add new unit tests, +add them to the UnitTestCatch.cpp file or add a new source file which +includes catch.hpp. + +For writing basics tests, the [assertion documentation](https://github.com/catchorg/Catch2/blob/master/docs/assertions.md#top) +or the existing examples are a good guideliens. +For more advanced tests, refer to the [catch2 documentation](https://github.com/catchorg/Catch2/blob/master/docs/Readme.md#top). + diff --git a/unittest/core/CatchDefinitions.cpp b/unittest/core/CatchDefinitions.cpp new file mode 100644 index 00000000..0b66558a --- /dev/null +++ b/unittest/core/CatchDefinitions.cpp @@ -0,0 +1,11 @@ +#include "CatchDefinitions.h" +#include + +StorageManagerIF* tglob::getIpcStoreHandle() { + if(objectManager != nullptr) { + return objectManager->get(objects::IPC_STORE); + } else { + sif::error << "Global object manager uninitialized" << std::endl; + return nullptr; + } +} diff --git a/unittest/core/CatchDefinitions.h b/unittest/core/CatchDefinitions.h new file mode 100644 index 00000000..366cda7e --- /dev/null +++ b/unittest/core/CatchDefinitions.h @@ -0,0 +1,21 @@ +#ifndef FSFW_UNITTEST_CORE_CATCHDEFINITIONS_H_ +#define FSFW_UNITTEST_CORE_CATCHDEFINITIONS_H_ + +#include +#include +#include + +namespace retval { +static constexpr int CATCH_OK = static_cast(HasReturnvaluesIF::RETURN_OK); +static constexpr int CATCH_FAILED = static_cast(HasReturnvaluesIF::RETURN_FAILED); +} + +namespace tconst { + static constexpr MessageQueueId_t testQueueId = 42; +} + +namespace tglob { + StorageManagerIF* getIpcStoreHandle(); +} + +#endif /* FSFW_UNITTEST_CORE_CATCHDEFINITIONS_H_ */ diff --git a/unittest/core/CatchRunner.cpp b/unittest/core/CatchRunner.cpp new file mode 100644 index 00000000..35c53cd4 --- /dev/null +++ b/unittest/core/CatchRunner.cpp @@ -0,0 +1,31 @@ +/** + * @file CatchSource.cpp + * @brief Source file to compile catch framework. + * @details All tests should be written in other files. + * For eclipse console output, install ANSI Escape in Console + * from the eclipse market place to get colored characters. + */ + +#ifndef NO_UNIT_TEST_FRAMEWORK + +#define CATCH_CONFIG_RUNNER +#include + +#if CUSTOM_UNITTEST_RUNNER == 0 + +extern int customSetup(); + +int main( int argc, char* argv[] ) { + customSetup(); + + // Catch internal function call + int result = Catch::Session().run( argc, argv ); + + // global clean-up + return result; +} + +#endif + + +#endif diff --git a/unittest/core/CatchSetup.cpp b/unittest/core/CatchSetup.cpp new file mode 100644 index 00000000..f8543fd2 --- /dev/null +++ b/unittest/core/CatchSetup.cpp @@ -0,0 +1,42 @@ +#include "CatchDefinitions.h" + +#include +#include + + +#ifdef GCOV +#include +#endif + +#include "../../objectmanager/ObjectManager.h" +#include "../../objectmanager/ObjectManagerIF.h" +#include "../../storagemanager/StorageManagerIF.h" +#include "../../datapool/DataPool.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" + + +/* Global instantiations normally done in main.cpp */ +/* Initialize Data Pool */ +//namespace glob { +DataPool dataPool(datapool::dataPoolInit); +//} + + +namespace sif { +/* Set up output streams */ +ServiceInterfaceStream debug("DEBUG"); +ServiceInterfaceStream info("INFO"); +ServiceInterfaceStream error("ERROR"); +ServiceInterfaceStream warning("WARNING"); +} + +/* Global object manager */ +ObjectManagerIF *objectManager; + +int customSetup() { + // global setup + objectManager = new ObjectManager(Factory::produce); + objectManager -> initialize(); + return 0; +} + diff --git a/unittest/core/core.mk b/unittest/core/core.mk new file mode 100644 index 00000000..3e5626d3 --- /dev/null +++ b/unittest/core/core.mk @@ -0,0 +1,3 @@ +CXXSRC += $(wildcard $(CURRENTPATH)/*.cpp) + +INCLUDES += $(CURRENTPATH) \ No newline at end of file diff --git a/unittest/core/printChar.cpp b/unittest/core/printChar.cpp new file mode 100644 index 00000000..755a13b2 --- /dev/null +++ b/unittest/core/printChar.cpp @@ -0,0 +1,10 @@ +#include +#include + +void printChar(const char* character, bool errStream) { + if(errStream) { + std::putc(*character, stderr); + return; + } + std::putc(*character, stdout); +} diff --git a/unittest/core/printChar.h b/unittest/core/printChar.h new file mode 100644 index 00000000..80e867f6 --- /dev/null +++ b/unittest/core/printChar.h @@ -0,0 +1,8 @@ +#ifndef FSFW_UNITTEST_CORE_PRINTCHAR_H_ +#define FSFW_UNITTEST_CORE_PRINTCHAR_H_ + + +extern "C" void printChar(const char*, bool errStream); + + +#endif /* FSFW_UNITTEST_CORE_PRINTCHAR_H_ */ diff --git a/unittest/internal/InternalUnitTester.cpp b/unittest/internal/InternalUnitTester.cpp new file mode 100644 index 00000000..503a71ec --- /dev/null +++ b/unittest/internal/InternalUnitTester.cpp @@ -0,0 +1,27 @@ +#include "InternalUnitTester.h" +#include "UnittDefinitions.h" + +#include "osal/IntTestMq.h" +#include "osal/IntTestSemaphore.h" +#include "osal/IntTestMutex.h" +#include "serialize/IntTestSerialization.h" + +#include + +InternalUnitTester::InternalUnitTester() {} + +InternalUnitTester::~InternalUnitTester() {} + +ReturnValue_t InternalUnitTester::performTests() { + sif::info << "Running internal unit tests.." << std::endl; + testserialize::test_serialization(); + testmq::testMq(); + testsemaph::testBinSemaph(); + testsemaph::testCountingSemaph(); + testmutex::testMutex(); + sif::info << "Internal unit tests finished." << std::endl; + return RETURN_OK; +} + + + diff --git a/unittest/internal/InternalUnitTester.h b/unittest/internal/InternalUnitTester.h new file mode 100644 index 00000000..b301b923 --- /dev/null +++ b/unittest/internal/InternalUnitTester.h @@ -0,0 +1,29 @@ +#ifndef FRAMEWORK_TEST_UNITTESTCLASS_H_ +#define FRAMEWORK_TEST_UNITTESTCLASS_H_ + +#include "UnittDefinitions.h" +#include + +/** + * @brief Can be used for internal testing, for example for hardware specific + * tests which can not be run on a host-machine. + * + * TODO: A lot of ways to improve this class. A way for tests to subscribe + * in this central class would be nice. Right now, this is the class + * which simply calls all other tests from other files manually. + * Maybe there is a better way.. + */ +class InternalUnitTester: public HasReturnvaluesIF { +public: + InternalUnitTester(); + virtual~ InternalUnitTester(); + + /** + * Some function which calls all other tests + * @return + */ + virtual ReturnValue_t performTests(); +}; + + +#endif /* FRAMEWORK_TEST_UNITTESTCLASS_H_ */ diff --git a/unittest/internal/UnittDefinitions.cpp b/unittest/internal/UnittDefinitions.cpp new file mode 100644 index 00000000..0bdbfcc7 --- /dev/null +++ b/unittest/internal/UnittDefinitions.cpp @@ -0,0 +1,7 @@ +#include + + ReturnValue_t unitt::put_error(std::string errorId) { + sif::error << "Unit Tester error: Failed at test ID " + << errorId << "\n" << std::flush; + return HasReturnvaluesIF::RETURN_FAILED; +} diff --git a/unittest/internal/UnittDefinitions.h b/unittest/internal/UnittDefinitions.h new file mode 100644 index 00000000..ea36fea4 --- /dev/null +++ b/unittest/internal/UnittDefinitions.h @@ -0,0 +1,33 @@ +#ifndef UNITTEST_INTERNAL_UNITTDEFINITIONS_H_ +#define UNITTEST_INTERNAL_UNITTDEFINITIONS_H_ + +#include "../../returnvalues/HasReturnvaluesIF.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" +#include +#include + +namespace tv { +// POD test values +static const bool tv_bool = true; +static const uint8_t tv_uint8 {5}; +static const uint16_t tv_uint16 {283}; +static const uint32_t tv_uint32 {929221}; +static const uint64_t tv_uint64 {2929329429}; + +static const int8_t tv_int8 {-16}; +static const int16_t tv_int16 {-829}; +static const int32_t tv_int32 {-2312}; + +static const float tv_float {8.2149214}; +static const float tv_sfloat = {-922.2321321}; +static const double tv_double {9.2132142141e8}; +static const double tv_sdouble {-2.2421e19}; +} + +namespace unitt { +ReturnValue_t put_error(std::string errorId); +} + + + +#endif /* UNITTEST_INTERNAL_UNITTDEFINITIONS_H_ */ diff --git a/unittest/internal/internal.mk b/unittest/internal/internal.mk new file mode 100644 index 00000000..799fd796 --- /dev/null +++ b/unittest/internal/internal.mk @@ -0,0 +1,3 @@ +CXXSRC += $(wildcard $(CURRENTPATH)/osal/*.cpp) +CXXSRC += $(wildcard $(CURRENTPATH)/serialize/*.cpp) +CXXSRC += $(wildcard $(CURRENTPATH)/*.cpp) \ No newline at end of file diff --git a/unittest/internal/osal/IntTestMq.cpp b/unittest/internal/osal/IntTestMq.cpp new file mode 100644 index 00000000..63016374 --- /dev/null +++ b/unittest/internal/osal/IntTestMq.cpp @@ -0,0 +1,52 @@ +#include +#include +#include +#include + +#include + +using retval = HasReturnvaluesIF; + +void testmq::testMq() { + std::string id = "[testMq]"; + MessageQueueIF* testSenderMq = + QueueFactory::instance()->createMessageQueue(1); + MessageQueueId_t testSenderMqId = testSenderMq->getId(); + + MessageQueueIF* testReceiverMq = + QueueFactory::instance()->createMessageQueue(1); + MessageQueueId_t testReceiverMqId = testReceiverMq->getId(); + std::array testData { 0 }; + testData[0] = 42; + MessageQueueMessage testMessage(testData.data(), 1); + testSenderMq->setDefaultDestination(testReceiverMqId); + + + auto result = testSenderMq->sendMessage(testReceiverMqId, &testMessage); + if(result != retval::RETURN_OK) { + unitt::put_error(id); + } + MessageQueueMessage recvMessage; + result = testReceiverMq->receiveMessage(&recvMessage); + if(result != retval::RETURN_OK or recvMessage.getData()[0] != 42) { + unitt::put_error(id); + } + + result = testSenderMq->sendMessage(testReceiverMqId, &testMessage); + if(result != retval::RETURN_OK) { + unitt::put_error(id); + } + MessageQueueId_t senderId = 0; + result = testReceiverMq->receiveMessage(&recvMessage,&senderId); + if(result != retval::RETURN_OK or recvMessage.getData()[0] != 42) { + unitt::put_error(id); + } + if(senderId != testSenderMqId) { + unitt::put_error(id); + } + senderId = testReceiverMq->getLastPartner(); + if(senderId != testSenderMqId) { + unitt::put_error(id); + } + +} diff --git a/unittest/internal/osal/IntTestMq.h b/unittest/internal/osal/IntTestMq.h new file mode 100644 index 00000000..bc12a9b0 --- /dev/null +++ b/unittest/internal/osal/IntTestMq.h @@ -0,0 +1,9 @@ +#ifndef UNITTEST_INTERNAL_INTESTMQ_H_ +#define UNITTEST_INTERNAL_INTESTMQ_H_ + +namespace testmq { +void testMq(); +} + + +#endif /* UNITTEST_INTERNAL_INTESTMQ_H_ */ diff --git a/unittest/internal/osal/IntTestMutex.cpp b/unittest/internal/osal/IntTestMutex.cpp new file mode 100644 index 00000000..3fd668df --- /dev/null +++ b/unittest/internal/osal/IntTestMutex.cpp @@ -0,0 +1,42 @@ +#include "IntTestMutex.h" + +#include +#include + +#if defined(hosted) +#include +#include +#include +#endif + + +void testmutex::testMutex() { + std::string id = "[testMutex]"; + MutexIF* mutex = MutexFactory::instance()->createMutex(); + auto result = mutex->lockMutex(MutexIF::POLLING); + if(result != HasReturnvaluesIF::RETURN_OK) { + unitt::put_error(id); + } + // timed_mutex from the C++ library specifies undefined behaviour if + // the timed mutex is locked twice from the same thread. +#if defined(hosted) + // hold on, this actually worked ? :-D This calls the function from + // another thread and stores the returnvalue in a future. + auto future = std::async(&MutexIF::lockMutex, mutex, 1); + result = future.get(); +#else + result = mutex->lockMutex(MutexIF::TimeoutType::WAITING, 1); +#endif + if(result != MutexIF::MUTEX_TIMEOUT) { + unitt::put_error(id); + } + + result = mutex->unlockMutex(); + if(result != HasReturnvaluesIF::RETURN_OK) { + unitt::put_error(id); + } + result = mutex->unlockMutex(); + if(result != MutexIF::CURR_THREAD_DOES_NOT_OWN_MUTEX) { + unitt::put_error(id); + } +} diff --git a/unittest/internal/osal/IntTestMutex.h b/unittest/internal/osal/IntTestMutex.h new file mode 100644 index 00000000..b467ea63 --- /dev/null +++ b/unittest/internal/osal/IntTestMutex.h @@ -0,0 +1,10 @@ +#ifndef UNITTEST_INTERNAL_INTTESTMUTEX_H_ +#define UNITTEST_INTERNAL_INTTESTMUTEX_H_ + +namespace testmutex { +void testMutex(); +} + + + +#endif /* UNITTEST_INTERNAL_INTTESTMUTEX_H_ */ diff --git a/unittest/internal/osal/IntTestSemaphore.cpp b/unittest/internal/osal/IntTestSemaphore.cpp new file mode 100644 index 00000000..534a6a6d --- /dev/null +++ b/unittest/internal/osal/IntTestSemaphore.cpp @@ -0,0 +1,160 @@ +#include "IntTestSemaphore.h" +#include +#include +#include +#include + + +void testsemaph::testBinSemaph() { + std::string id = "[BinSemaphore]"; + SemaphoreIF* binSemaph = + SemaphoreFactory::instance()->createBinarySemaphore(); + if(binSemaph == nullptr) { + return; + } + testBinSemaphoreImplementation(binSemaph, id); + SemaphoreFactory::instance()->deleteSemaphore(binSemaph); +#if defined(freeRTOS) + SemaphoreIF* binSemaphUsingTask = + SemaphoreFactory::instance()->createBinarySemaphore(1); + testBinSemaphoreImplementation(binSemaphUsingTask, id); + SemaphoreFactory::instance()->deleteSemaphore(binSemaphUsingTask); +#endif +} + + +void testsemaph::testCountingSemaph() { + std::string id = "[CountingSemaph]"; + { + // First test: create a binary semaphore by using a counting semaphore. + SemaphoreIF* countingSemaph = SemaphoreFactory::instance()-> + createCountingSemaphore(1,1); + if(countingSemaph == nullptr) { + return; + } + testBinSemaphoreImplementation(countingSemaph, id); + SemaphoreFactory::instance()->deleteSemaphore(countingSemaph); +#if defined(freeRTOS) + countingSemaph = SemaphoreFactory::instance()-> + createCountingSemaphore(1, 1, 1); + testBinSemaphoreImplementation(countingSemaph, id); + SemaphoreFactory::instance()->deleteSemaphore(countingSemaph); +#endif + } + + { + // Second test: counting semaphore with count 3 and init count of 3. + SemaphoreIF* countingSemaph = SemaphoreFactory::instance()-> + createCountingSemaphore(3,3); + testCountingSemaphImplementation(countingSemaph, id); + SemaphoreFactory::instance()->deleteSemaphore(countingSemaph); +#if defined(freeRTOS) + countingSemaph = SemaphoreFactory::instance()-> + createCountingSemaphore(3, 0, 1); + uint8_t semaphCount = countingSemaph->getSemaphoreCounter(); + if(semaphCount != 0) { + unitt::put_error(id); + } + // release 3 times in a row + for(int i = 0; i < 3; i++) { + auto result = countingSemaph->release(); + if(result != HasReturnvaluesIF::RETURN_OK) { + unitt::put_error(id); + } + } + testCountingSemaphImplementation(countingSemaph, id); + SemaphoreFactory::instance()->deleteSemaphore(countingSemaph); +#endif + } +} + + +void testsemaph::testBinSemaphoreImplementation(SemaphoreIF* binSemaph, + std::string id) { + uint8_t semaphCount = binSemaph->getSemaphoreCounter(); + if(semaphCount != 1) { + unitt::put_error(id); + } + + ReturnValue_t result = binSemaph->release(); + if(result != SemaphoreIF::SEMAPHORE_NOT_OWNED) { + unitt::put_error(id); + } + result = binSemaph->acquire(SemaphoreIF::BLOCKING); + if(result != HasReturnvaluesIF::RETURN_OK) { + unitt::put_error(id); + } + + // There is not really a point in testing time related, the task + // might get interrupted.. + { + //Stopwatch stopwatch(false); + result = binSemaph->acquire(SemaphoreIF::TimeoutType::WAITING, 10); + //dur_millis_t time = stopwatch.stop(); +// if(abs(time - 10) > 2) { +// sif::error << "UnitTester: Semaphore timeout measured incorrect." +// << std::endl; +// unitt::put_error(id); +// } + } + + if(result != SemaphoreIF::SEMAPHORE_TIMEOUT) { + unitt::put_error(id); + } + + semaphCount = binSemaph->getSemaphoreCounter(); + if(semaphCount != 0) { + unitt::put_error(id); + } + + result = binSemaph->release(); + if(result != HasReturnvaluesIF::RETURN_OK) { + unitt::put_error(id); + } +} + +void testsemaph::testCountingSemaphImplementation(SemaphoreIF* countingSemaph, + std::string id) { + // check count getter function + uint8_t semaphCount = countingSemaph->getSemaphoreCounter(); + if(semaphCount != 3) { + unitt::put_error(id); + } + ReturnValue_t result = countingSemaph->release(); + if(result != SemaphoreIF::SEMAPHORE_NOT_OWNED) { + unitt::put_error(id); + } + // acquire 3 times in a row + for(int i = 0; i < 3; i++) { + result = countingSemaph->acquire(SemaphoreIF::BLOCKING); + if(result != HasReturnvaluesIF::RETURN_OK) { + unitt::put_error(id); + } + } + + { + Stopwatch stopwatch(false); + // attempt to take when count is 0, measure time + result = countingSemaph->acquire(SemaphoreIF::TimeoutType::WAITING, 10); + dur_millis_t time = stopwatch.stop(); + if(abs(time - 10) > 1) { + unitt::put_error(id); + } + } + + if(result != SemaphoreIF::SEMAPHORE_TIMEOUT) { + unitt::put_error(id); + } + + // release 3 times in a row + for(int i = 0; i < 3; i++) { + result = countingSemaph->release(); + if(result != HasReturnvaluesIF::RETURN_OK) { + unitt::put_error(id); + } + } + // assert correct full count + if(countingSemaph->getSemaphoreCounter() != 3) { + unitt::put_error(id); + } +} diff --git a/unittest/internal/osal/IntTestSemaphore.h b/unittest/internal/osal/IntTestSemaphore.h new file mode 100644 index 00000000..af26c131 --- /dev/null +++ b/unittest/internal/osal/IntTestSemaphore.h @@ -0,0 +1,15 @@ +#ifndef UNITTEST_INTERNAL_INTTESTSEMAPHORE_H_ +#define UNITTEST_INTERNAL_INTTESTSEMAPHORE_H_ +class SemaphoreIF; +#include + +namespace testsemaph { +void testBinSemaph(); +void testBinSemaphoreImplementation(SemaphoreIF* binSemaph, std::string id); +void testCountingSemaph(); +void testCountingSemaphImplementation(SemaphoreIF* countingSemaph, + std::string id); +} + + +#endif /* UNITTEST_INTERNAL_INTTESTSEMAPHORE_H_ */ diff --git a/unittest/internal/serialize/IntTestSerialization.cpp b/unittest/internal/serialize/IntTestSerialization.cpp new file mode 100644 index 00000000..3f231a41 --- /dev/null +++ b/unittest/internal/serialize/IntTestSerialization.cpp @@ -0,0 +1,230 @@ +#include "IntTestSerialization.h" +#include +#include +#include +#include +#include + +using retval = HasReturnvaluesIF; +std::array testserialize::test_array = { 0 }; + +ReturnValue_t testserialize::test_serialization() { + // Here, we test all serialization tools. First test basic cases. + ReturnValue_t result = test_endianness_tools(); + if(result != retval::RETURN_OK) { + return result; + } + result = test_autoserialization(); + if(result != retval::RETURN_OK) { + return result; + } + result = test_serial_buffer_adapter(); + if(result != retval::RETURN_OK) { + return result; + } + return retval::RETURN_OK; +} + +ReturnValue_t testserialize::test_endianness_tools() { + std::string id = "[test_endianness_tools]"; + test_array[0] = 0; + test_array[1] = 0; + uint16_t two_byte_value = 1; + size_t size = 0; + uint8_t* p_array = test_array.data(); + SerializeAdapter::serialize(&two_byte_value, &p_array, &size, 2, + SerializeIF::Endianness::MACHINE); + // Little endian: Value one on first byte + if(test_array[0] != 1 and test_array[1] != 0) { + return unitt::put_error(id); + + } + + p_array = test_array.data(); + size = 0; + SerializeAdapter::serialize(&two_byte_value, &p_array, &size, 2, + SerializeIF::Endianness::BIG); + // Big endian: Value one on second byte + if(test_array[0] != 0 and test_array[1] != 1) { + return unitt::put_error(id); + } + return retval::RETURN_OK; +} + +ReturnValue_t testserialize::test_autoserialization() { + std::string id = "[test_autoserialization]"; + // Unit Test getSerializedSize + if(SerializeAdapter:: + getSerializedSize(&tv::tv_bool) != sizeof(tv::tv_bool) or + SerializeAdapter:: + getSerializedSize(&tv::tv_uint8) != sizeof(tv::tv_uint8) or + SerializeAdapter:: + getSerializedSize(&tv::tv_uint16) != sizeof(tv::tv_uint16) or + SerializeAdapter:: + getSerializedSize(&tv::tv_uint32) != sizeof(tv::tv_uint32) or + SerializeAdapter:: + getSerializedSize(&tv::tv_uint64) != sizeof(tv::tv_uint64) or + SerializeAdapter:: + getSerializedSize(&tv::tv_int8) != sizeof(tv::tv_int8) or + SerializeAdapter:: + getSerializedSize(&tv::tv_double) != sizeof(tv::tv_double) or + SerializeAdapter:: + getSerializedSize(&tv::tv_int16) != sizeof(tv::tv_int16) or + SerializeAdapter:: + getSerializedSize(&tv::tv_int32) != sizeof(tv::tv_int32) or + SerializeAdapter:: + getSerializedSize(&tv::tv_float) != sizeof(tv::tv_float)) + { + return unitt::put_error(id); + } + + size_t serialized_size = 0; + uint8_t * p_array = test_array.data(); + + SerializeAdapter::serialize(&tv::tv_bool, &p_array, + &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tv::tv_uint8, &p_array, + &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tv::tv_uint16, &p_array, + &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tv::tv_uint32, &p_array, + &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tv::tv_int8, &p_array, + &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tv::tv_int16, &p_array, + &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tv::tv_int32, &p_array, + &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tv::tv_uint64, &p_array, + &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tv::tv_float, &p_array, + &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tv::tv_double, &p_array, + &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tv::tv_sfloat, &p_array, + &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tv::tv_sdouble, &p_array, + &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); + // expected size is 1 + 1 + 2 + 4 + 1 + 2 + 4 + 8 + 4 + 8 + 4 + 8 + if(serialized_size != 47) { + return unitt::put_error(id); + } + + p_array = test_array.data(); + size_t remaining_size = serialized_size; + bool tv_bool; + uint8_t tv_uint8; + uint16_t tv_uint16; + uint32_t tv_uint32; + int8_t tv_int8; + int16_t tv_int16; + int32_t tv_int32; + uint64_t tv_uint64; + float tv_float; + double tv_double; + float tv_sfloat; + double tv_sdouble; + + SerializeAdapter::deSerialize(&tv_bool, + const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tv_uint8, + const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tv_uint16, + const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tv_uint32, + const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tv_int8, + const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tv_int16, + const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tv_int32, + const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tv_uint64, + const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tv_float, + const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tv_double, + const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tv_sfloat, + const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tv_sdouble, + const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); + + if(tv_bool != tv::tv_bool or tv_uint8 != tv::tv_uint8 or + tv_uint16 != tv::tv_uint16 or tv_uint32 != tv::tv_uint32 or + tv_uint64 != tv::tv_uint64 or tv_int8 != tv::tv_int8 or + tv_int16 != tv::tv_int16 or tv_int32 != tv::tv_int32) + { + return unitt::put_error(id); + } + + // These epsilon values were just guessed.. It appears to work though. + if(abs(tv_float - tv::tv_float) > 0.0001 or + abs(tv_double - tv::tv_double) > 0.01 or + abs(tv_sfloat - tv::tv_sfloat) > 0.0001 or + abs(tv_sdouble - tv::tv_sdouble) > 0.01) { + return unitt::put_error(id); + } + + // Check overflow + return retval::RETURN_OK; +} + +// TODO: Also test for constant buffers. +ReturnValue_t testserialize::test_serial_buffer_adapter() { + std::string id = "[test_serial_buffer_adapter]"; + + // I will skip endian swapper testing, its going to be changed anyway.. + // uint8_t tv::tv_uint8_swapped = EndianSwapper::swap(tv::tv_uint8); + + size_t serialized_size = 0; + uint8_t * p_array = test_array.data(); + std::array test_serial_buffer {5, 4, 3, 2, 1}; + SerialBufferAdapter tv_serial_buffer_adapter = + SerialBufferAdapter(test_serial_buffer.data(), + test_serial_buffer.size(), false); + uint16_t testUint16 = 16; + + SerializeAdapter::serialize(&tv::tv_bool, &p_array,&serialized_size, + test_array.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tv_serial_buffer_adapter, &p_array, + &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&testUint16, &p_array, &serialized_size, + test_array.size(), SerializeIF::Endianness::MACHINE); + + if(serialized_size != 8 or test_array[0] != true or test_array[1] != 5 + or test_array[2] != 4 or test_array[3] != 3 or test_array[4] != 2 + or test_array[5] != 1) + { + return unitt::put_error(id); + } + memcpy(&testUint16, test_array.data() + 6, sizeof(testUint16)); + if(testUint16 != 16) { + return unitt::put_error(id); + } + + // Serialize with size field + SerialBufferAdapter tv_serial_buffer_adapter2 = + SerialBufferAdapter(test_serial_buffer.data(), + test_serial_buffer.size(), true); + serialized_size = 0; + p_array = test_array.data(); + SerializeAdapter::serialize(&tv::tv_bool, &p_array,&serialized_size, + test_array.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tv_serial_buffer_adapter2, &p_array, + &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&testUint16, &p_array, &serialized_size, + test_array.size(), SerializeIF::Endianness::MACHINE); + + if(serialized_size != 9 or test_array[0] != true or test_array[1] != 5 + or test_array[2] != 5 or test_array[3] != 4 or test_array[4] != 3 + or test_array[5] != 2 or test_array[6] != 1) + { + return unitt::put_error(id); + } + memcpy(&testUint16, test_array.data() + 7, sizeof(testUint16)); + if(testUint16 != 16) { + return unitt::put_error(id); + } + return retval::RETURN_OK; +} diff --git a/unittest/internal/serialize/IntTestSerialization.h b/unittest/internal/serialize/IntTestSerialization.h new file mode 100644 index 00000000..f8841b82 --- /dev/null +++ b/unittest/internal/serialize/IntTestSerialization.h @@ -0,0 +1,15 @@ +#ifndef UNITTEST_INTERNAL_INTTESTSERIALIZATION_H_ +#define UNITTEST_INTERNAL_INTTESTSERIALIZATION_H_ +#include +#include + +namespace testserialize { +ReturnValue_t test_serialization(); +ReturnValue_t test_endianness_tools(); +ReturnValue_t test_autoserialization(); +ReturnValue_t test_serial_buffer_adapter(); + +extern std::array test_array; +} + +#endif /* UNITTEST_INTERNAL_INTTESTSERIALIZATION_H_ */ diff --git a/unittest/lcov.sh b/unittest/lcov.sh new file mode 100644 index 00000000..4db16e5f --- /dev/null +++ b/unittest/lcov.sh @@ -0,0 +1,3 @@ +#!/bin/bash +lcov --capture --directory . --output-file coverage.info +genhtml coverage.info --output-directory _coverage diff --git a/unittest/testcfg/FSFWConfig.h b/unittest/testcfg/FSFWConfig.h new file mode 100644 index 00000000..4fb224c1 --- /dev/null +++ b/unittest/testcfg/FSFWConfig.h @@ -0,0 +1,46 @@ +#ifndef CONFIG_FSFWCONFIG_H_ +#define CONFIG_FSFWCONFIG_H_ + +#include + +//! Used to determine whether C++ ostreams are used +//! Those can lead to code bloat. +#define FSFW_CPP_OSTREAM_ENABLED 1 + +//! Reduced printout to further decrese code size +//! Be careful, this also turns off most diagnostic prinouts! +#define FSFW_REDUCED_PRINTOUT 0 + +//! Can be used to enable debugging printouts for developing the FSFW +#define FSFW_DEBUGGING 0 + +//! Defines the FIFO depth of each commanding service base which +//! also determines how many commands a CSB service can handle in one cycle +//! simulataneously. This will increase the required RAM for +//! each CSB service ! +#define FSFW_CSB_FIFO_DEPTH 6 + +//! If FSFW_OBJ_EVENT_TRANSLATION is set to one, +//! additional output which requires the translation files translateObjects +//! and translateEvents (and their compiled source files) +#define FSFW_OBJ_EVENT_TRANSLATION 0 + +//! If -DDEBUG is supplied in the build defines, there will be +//! additional output which requires the translation files translateObjects +//! and translateEvents (and their compiles source files) +#if FSFW_OBJ_EVENT_TRANSLATION == 1 +#define FSFW_DEBUG_OUTPUT 1 +//! Specify whether info events are printed too. +#define FSFW_DEBUG_INFO 1 +#include +#include +#else +#define FSFW_DEBUG_OUTPUT 0 +#endif + +//! When using the newlib nano library, C99 support for stdio facilities +//! will not be provided. This define should be set to 1 if this is the case. +#define FSFW_NO_C99_IO 1 + + +#endif /* CONFIG_FSFWCONFIG_H_ */ diff --git a/unittest/testcfg/Makefile-FSFW-Tests b/unittest/testcfg/Makefile-FSFW-Tests new file mode 100644 index 00000000..2017d2bd --- /dev/null +++ b/unittest/testcfg/Makefile-FSFW-Tests @@ -0,0 +1,415 @@ +#------------------------------------------------------------------------------- +# Makefile for FSFW Test +#------------------------------------------------------------------------------- +# User-modifiable options +#------------------------------------------------------------------------------- +# Fundamentals on the build process of C/C++ Software: +# https://www3.ntu.edu.sg/home/ehchua/programming/cpp/gcc_make.html + +# Make documentation: https://www.gnu.org/software/make/manual/make.pdf +# Online: https://www.gnu.org/software/make/manual/make.html +# General rules: http://make.mad-scientist.net/papers/rules-of-makefiles/#rule3 +SHELL = /bin/sh + +# Chip & board used for compilation +# (can be overriden by adding CHIP=chip and BOARD=board to the command-line) +# Unit Test can only be run on host machine for now (Linux) +FRAMEWORK_PATH = fsfw +FILE_ROOT = $(FRAMEWORK_PATH)/unittest +BOARD = unittest +LINUX = 1 +OS_FSFW = linux +CUSTOM_DEFINES += -D$(OS_FSFW) + +# Copied from stackoverflow, can be used to differentiate between Windows +# and Linux +ifeq ($(OS),Windows_NT) + CUSTOM_DEFINES += -DWIN32 + ifeq ($(PROCESSOR_ARCHITEW6432),AMD64) + CUSTOM_DEFINES += -DAMD64 + else + ifeq ($(PROCESSOR_ARCHITECTURE),AMD64) + CUSTOM_DEFINES += -DAMD64 + endif + ifeq ($(PROCESSOR_ARCHITECTURE),x86) + CUSTOM_DEFINES += -DIA32 + endif + endif +else + UNAME_S := $(shell uname -s) + ifeq ($(UNAME_S),Linux) + DETECTED_OS = LINUX + CUSTOM_DEFINES += -DLINUX + endif + ifeq ($(UNAME_S),Darwin) + CUSTOM_DEFINES += -DOSX + endif + UNAME_P := $(shell uname -p) + ifeq ($(UNAME_P),x86_64) + CUSTOM_DEFINES += -DAMD64 + endif + ifneq ($(filter %86,$(UNAME_P)),) + CUSTOM_DEFINES += -DIA32 + endif + ifneq ($(filter arm%,$(UNAME_P)),) + CUSTOM_DEFINES += -DARM + endif +endif + +UNIT_TEST = 1 +# General folder paths +CONFIG_PATH = $(FILE_ROOT)/config +UNIT_TEST_PATH = $(FILE_ROOT)/tests +CORE_PATH = $(FILE_ROOT)/core + +# Output file basename +BASENAME = fsfw +BINARY_NAME := $(BASENAME)-$(BOARD) +# Output files will be put in this directory inside +OUTPUT_FOLDER = $(OS) + +# Optimization level. Optimized for debugging. +OPTIMIZATION = -O0 + +# Default debug output. Optimized for debugging. +DEBUG_LEVEL = -g3 + +ifdef GCOV +CUSTOM_DEFINES += -DGCOV +endif + + +# Output directories +BUILDPATH = _bin +DEPENDPATH = _dep +OBJECTPATH = _obj + +ifeq ($(MAKECMDGOALS),mission) +BUILD_FOLDER = mission +else +BUILD_FOLDER = devel +endif + +DEPENDDIR = $(DEPENDPATH)/$(OUTPUT_FOLDER)/$(BUILD_FOLDER) +OBJDIR = $(OBJECTPATH)/$(OUTPUT_FOLDER)/$(BUILD_FOLDER) +BINDIR = $(BUILDPATH) + +CLEANDEP = $(DEPENDPATH)/$(OUTPUT_FOLDER) +CLEANOBJ = $(OBJECTPATH)/$(OUTPUT_FOLDER) +CLEANBIN = $(BUILDPATH) +#------------------------------------------------------------------------------- +# Tools and Includes +#------------------------------------------------------------------------------- + +# Tool suffix when cross-compiling +CROSS_COMPILE = + +# C Compiler +CC = $(CROSS_COMPILE)gcc + +# C++ compiler +CXX = $(CROSS_COMPILE)g++ + +# Additional Tools +SIZE = $(CROSS_COMPILE)size +STRIP = $(CROSS_COMPILE)strip +CP = $(CROSS_COMPILE)objcopy + +HEXCOPY = $(CP) -O ihex +BINCOPY = $(CP) -O binary +# files to be compiled, will be filled in by include makefiles +# := assignment is neccessary so we get all paths right +# https://www.gnu.org/software/make/manual/html_node/Flavors.html +CSRC := +CXXSRC := +ASRC := +INCLUDES := + +# Directories where $(directoryname).mk files should be included from +SUBDIRS := $(FRAMEWORK_PATH) $(TEST_PATH) $(UNIT_TEST_PATH) $(CONFIG_PATH) \ + $(CORE_PATH) + + +I_INCLUDES += $(addprefix -I, $(INCLUDES)) + +# This is a hack from http://make.mad-scientist.net/the-eval-function/ +# +# The problem is, that included makefiles should be aware of their relative path +# but not need to guess or hardcode it. So we set $(CURRENTPATH) for them. If +# we do this globally and the included makefiles want to include other makefiles as +# well, they would overwrite $(CURRENTPATH), screwing the include after them. +# +# By using a for-loop with an eval'd macro, we can generate the code to include all +# sub-makefiles (with the correct $(CURRENTPATH) set) before actually evaluating +# (and by this possibly changing $(CURRENTPATH)) them. +# +# This works recursively, if an included makefile wants to include, it can safely set +# $(SUBDIRS) (which has already been evaluated here) and do +# "$(foreach S,$(SUBDIRS),$(eval $(INCLUDE_FILE)))" +# $(SUBDIRS) must be relative to the project root, so to include subdir foo, set +# $(SUBDIRS) = $(CURRENTPATH)/foo. +define INCLUDE_FILE +CURRENTPATH := $S +include $(S)/$(notdir $S).mk +endef +$(foreach S,$(SUBDIRS),$(eval $(INCLUDE_FILE))) + +INCLUDES += $(FILE_ROOT) +INCLUDES += $(FILE_ROOT)/catch2/ + +#------------------------------------------------------------------------------- +# Source Files +#------------------------------------------------------------------------------- + +# All source files which are not includes by the .mk files are added here +# Please ensure that no files are included by both .mk file and here ! + +# if a target is not listed in the current directory, +# make searches in the directories specified with VPATH + +# All C Sources included by .mk files are assigned here +# Add the objects to sources so dependency handling works +C_OBJECTS += $(CSRC:.c=.o) + +# Objects built from Assembly source files +ASM_OBJECTS = $(ASRC:.S=.o) + +# Objects built from C++ source files +CXX_OBJECTS += $(CXXSRC:.cpp=.o) + +#------------------------------------------------------------------------------- +# Build Configuration + Output +#------------------------------------------------------------------------------- + +TARGET = Debug build. +DEBUG_MESSAGE = Off +OPTIMIZATION_MESSAGE = Off + +# Define Messages +MSG_INFO = Software: Hosted unittest \(Catch2\) for the FSFW. +MSG_OPTIMIZATION = Optimization: $(OPTIMIZATION), $(OPTIMIZATION_MESSAGE) +MSG_TARGET = Target Build: $(TARGET) +MSG_DEBUG = Debug level: $(DEBUG_LEVEL), FSFW Debugging: $(DEBUG_MESSAGE) + +MSG_LINKING = Linking: +MSG_COMPILING = Compiling: +MSG_ASSEMBLING = Assembling: +MSG_DEPENDENCY = Collecting dependencies for: +MSG_BINARY = Generate binary: + +# See https://stackoverflow.com/questions/6687630/how-to-remove-unused-c-c-symbols-with-gcc-and-ld +# Used to throw away unused code. Reduces code size significantly ! +# -Wl,--gc-sections: needs to be passed to the linker to throw aways unused code +ifdef KEEP_UNUSED_CODE +PROTOTYPE_OPTIMIZATION = +UNUSED_CODE_REMOVAL = +else +PROTOTYPE_OPTIMIZATION = -ffunction-sections -fdata-sections +UNUSED_CODE_REMOVAL = -Wl,--gc-sections +# Link time optimization +# See https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html for reference +# Link time is larger and size of object files can not be retrieved +# but resulting binary is smaller. Could be used in mission/deployment build +# Requires -ffunction-section in linker call +LINK_TIME_OPTIMIZATION = -flto +OPTIMIZATION += $(PROTOTYPE_OPTIMIZATION) +endif + +# Dependency Flags +# These flags tell the compiler to build dependencies +# See: https://www.gnu.org/software/make/manual/html_node/Automatic-Prerequisites.html +# Using following guide: http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/#combine +DEPFLAGS = -MT $@ -MMD -MP -MF $(DEPENDDIR)/$*.d + +# Flags for the compiler call +# - std: Which C++ version to use. Common versions: c++11, c++14 and c++17 +# - Wall: enable all warnings +# - Wextra: enable extra warnings +# - g: defines debug level +# - fmessage-length: to control the formatting algorithm for diagnostic messages; +# =0 means no line-wrapping is done; each error message appears on a single line +# - fno-exceptions: stops generating extra code needed to propagate exceptions, +# which can produce significant data size overhead +CUSTOM_DEFINES += -DUNIT_TEST +WARNING_FLAGS = -Wall -Wshadow=local -Wextra -Wimplicit-fallthrough=1 \ + -Wno-unused-parameter + +CXXDEFINES := $(CUSTOM_DEFINES) +CFLAGS += +CXXFLAGS += -I. $(DEBUG_LEVEL) $(WARNING_FLAGS) $(DEPFLAGS) -fmessage-length=0 $(OPTIMIZATION)\ + $(I_INCLUDES) $(CXXDEFINES) +CPPFLAGS += -std=c++11 + +# Flags for the linker call +# LINK_INCLUDES specify the path to used libraries and the linker script +# LINK_LIBRARIES: Link real time support +LDFLAGS := $(DEBUG_LEVEL) $(UNUSED_CODE_REMOVAL) $(OPTIMIZATION) -pthread +LINK_INCLUDES := +LINK_LIBRARIES := + +ifdef LINUX +LINK_LIBRARIES += -lrt +endif + +ifeq ($(OS),Windows_NT) +LINK_LIBRARIES += -lwsock32 -lws2_32 +LDFLASGS += -fuse-ld=lld +endif + +# Gnu Coverage Tools Flags +ifdef GCOV +GCOV_CXXFLAGS = -fprofile-arcs -ftest-coverage --coverage -fno-inline \ + -fno-inline-small-functions -fno-default-inline +CXXFLAGS += $(GCOV_CXXFLAGS) +GCOV_LINKER_LIBS = -lgcov -fprofile-arcs -ftest-coverage +LINK_LIBRARIES += $(GCOV_LINKER_LIBS) +endif + +# $(info $${CXXFLAGS} is [${CXXFLAGS}]) + +#------------------------------------------------------------------------------- +# Rules +#------------------------------------------------------------------------------- +# the call function assigns parameters to temporary variables +# https://www.gnu.org/software/make/manual/make.html#Call-Function +# $(1) = Memory names +# Rules are called for each memory type +# Two Expansion Symbols $$ are to escape the dollar sign for eval. +# See: http://make.mad-scientist.net/the-eval-function/ + +default: all + +# Cleans all files +hardclean: + -rm -rf $(BUILDPATH) + -rm -rf $(OBJECTPATH) + -rm -rf $(DEPENDPATH) + +# Only clean files for current build +clean: + -rm -rf $(CLEANOBJ) + -rm -rf $(CLEANBIN) + -rm -rf $(CLEANDEP) + +# Only clean binaries. Useful for changing the binary type when object files +# are already compiled so complete rebuild is not necessary +cleanbin: + -rm -rf $(CLEANBIN) + +# In this section, the binaries are built for all selected memories +# notestfw: all +all: executable + +# Build target configuration +release: OPTIMIZATION = -Os $(PROTOTYPE_OPTIMIZATION) $(LINK_TIME_OPTIMIZATION) +release: LINK_TIME_OPTIMIZATION = -flto +release: TARGET = Mission build. +release: OPTIMIZATION_MESSAGE = On with Link Time Optimization + +debug: CXXDEFINES += -DDEBUG +debug: TARGET = Debug +debug: DEBUG_MESSAGE = On + +ifndef KEEP_UNUSED_CODE +debug release: OPTIMIZATION_MESSAGE += , no unused code removal +endif + +debug release notestfw: executable + +executable: $(BINDIR)/$(BINARY_NAME).elf + @echo + @echo $(MSG_INFO) + @echo $(MSG_TARGET) + @echo $(MSG_OPTIMIZATION) + @echo $(MSG_DEBUG) + +C_OBJECTS_PREFIXED = $(addprefix $(OBJDIR)/, $(C_OBJECTS)) +CXX_OBJECTS_PREFIXED = $(addprefix $(OBJDIR)/, $(CXX_OBJECTS)) +ASM_OBJECTS_PREFIXED = $(addprefix $(OBJDIR)/, $(ASM_OBJECTS)) +ALL_OBJECTS = $(ASM_OBJECTS_PREFIXED) $(C_OBJECTS_PREFIXED) \ + $(CXX_OBJECTS_PREFIXED) + +# Useful for debugging the Makefile +# Also see: https://www.oreilly.com/openbook/make3/book/ch12.pdf +# $(info $${ALL_OBJECTS} is [${ALL_OBJECTS}]) +# $(info $${CXXSRC} is [${CXXSRC}]) + +# Automatic variables are used here extensively. Some of them +# are escaped($$) to suppress immediate evaluation. The most important ones are: +# $@: Name of Target (left side of rule) +# $<: Name of the first prerequisite (right side of rule) +# @^: List of all prerequisite, omitting duplicates +# @D: Directory and file-within-directory part of $@ + +# Generates binary and displays all build properties +# -p with mkdir ignores error and creates directory when needed. + +# SHOW_DETAILS = 1 + + +# Link with required libraries: HAL (Hardware Abstraction Layer) and +# HCC (File System Library) +$(BINDIR)/$(BINARY_NAME).elf: $(ALL_OBJECTS) + @echo + @echo $(MSG_LINKING) Target $@ + @mkdir -p $(@D) +ifdef SHOW_DETAILS + $(CXX) $(LDFLAGS) $(LINK_INCLUDES) -o $@ $^ $(LINK_LIBRARIES) +else + @$(CXX) $(LDFLAGS) $(LINK_INCLUDES) -o $@ $^ $(LINK_LIBRARIES) +endif +ifeq ($(BUILD_FOLDER), mission) +# With Link Time Optimization, section size is not available + $(SIZE) $@ +else + $(SIZE) $^ $@ +endif + +$(BINDIR)/$(BINARY_NAME).hex: $(BINDIR)/$(BINARY_NAME).elf + @echo + @echo $(MSG_BINARY) + @mkdir -p $(@D) + $(HEXCOPY) $< $@ + +# Build new objects for changed dependencies. +$(OBJDIR)/%.o: %.cpp +$(OBJDIR)/%.o: %.cpp $(DEPENDDIR)/%.d | $(DEPENDDIR) + @echo + @echo $(MSG_COMPILING) $< + @mkdir -p $(@D) +ifdef SHOW_DETAILS + $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $< +else + @$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $< +endif + +$(OBJDIR)/%.o: %.c +$(OBJDIR)/%.o: %.c $(DEPENDDIR)/%.d | $(DEPENDDIR) + @echo + @echo $(MSG_COMPILING) $< + @mkdir -p $(@D) +ifdef SHOW_DETAILS + $(CC) $(CXXFLAGS) $(CFLAGS) -c -o $@ $< +else + @$(CC) $(CXXFLAGS) $(CFLAGS) -c -o $@ $< +endif + +#------------------------------------------------------------------------------- +# Dependency Handling +#------------------------------------------------------------------------------- + +# Dependency Handling according to following guide: +# http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/ +$(DEPENDDIR): + @mkdir -p $(@D) +DEPENDENCY_RELATIVE = $(CSRC:.c=.d) $(CXXSRC:.cpp=.d) +# This is the list of all dependencies +DEPFILES = $(addprefix $(DEPENDDIR)/, $(DEPENDENCY_RELATIVE)) +# Create subdirectories for dependencies +$(DEPFILES): + @mkdir -p $(@D) +# Include all dependencies +include $(wildcard $(DEPFILES)) + +# .PHONY tells make that these targets aren't files +.PHONY: clean release debug all hardclean cleanbin diff --git a/unittest/testcfg/TestsConfig.h b/unittest/testcfg/TestsConfig.h new file mode 100644 index 00000000..cd967fa7 --- /dev/null +++ b/unittest/testcfg/TestsConfig.h @@ -0,0 +1,8 @@ +#ifndef FSFW_UNITTEST_CONFIG_TESTSCONFIG_H_ +#define FSFW_UNITTEST_CONFIG_TESTSCONFIG_H_ + + +#define CUSTOM_UNITTEST_RUNNER 0 + + +#endif /* FSFW_UNITTEST_CONFIG_TESTSCONFIG_H_ */ diff --git a/unittest/testcfg/cdatapool/dataPoolInit.cpp b/unittest/testcfg/cdatapool/dataPoolInit.cpp new file mode 100644 index 00000000..ad2dc4ef --- /dev/null +++ b/unittest/testcfg/cdatapool/dataPoolInit.cpp @@ -0,0 +1,5 @@ +#include "dataPoolInit.h" + +void datapool::dataPoolInit(std::map * poolMap) { + +} diff --git a/unittest/testcfg/cdatapool/dataPoolInit.h b/unittest/testcfg/cdatapool/dataPoolInit.h new file mode 100644 index 00000000..9425d767 --- /dev/null +++ b/unittest/testcfg/cdatapool/dataPoolInit.h @@ -0,0 +1,17 @@ +#ifndef HOSTED_CONFIG_CDATAPOOL_DATAPOOLINIT_H_ +#define HOSTED_CONFIG_CDATAPOOL_DATAPOOLINIT_H_ + +#include +#include +#include +#include + + +namespace datapool { + void dataPoolInit(std::map * poolMap); + + enum datapoolvariables { + NO_PARAMETER = 0, + }; +} +#endif /* CONFIG_CDATAPOOL_DATAPOOLINIT_H_ */ diff --git a/unittest/testcfg/devices/logicalAddresses.cpp b/unittest/testcfg/devices/logicalAddresses.cpp new file mode 100644 index 00000000..c7ce314d --- /dev/null +++ b/unittest/testcfg/devices/logicalAddresses.cpp @@ -0,0 +1,5 @@ +#include "logicalAddresses.h" + + + + diff --git a/unittest/testcfg/devices/logicalAddresses.h b/unittest/testcfg/devices/logicalAddresses.h new file mode 100644 index 00000000..cdf87025 --- /dev/null +++ b/unittest/testcfg/devices/logicalAddresses.h @@ -0,0 +1,15 @@ +#ifndef CONFIG_DEVICES_LOGICALADDRESSES_H_ +#define CONFIG_DEVICES_LOGICALADDRESSES_H_ + +#include +#include +#include + +namespace addresses { + /* Logical addresses have uint32_t datatype */ + enum logicalAddresses: address_t { + }; +} + + +#endif /* CONFIG_DEVICES_LOGICALADDRESSES_H_ */ diff --git a/unittest/testcfg/devices/powerSwitcherList.cpp b/unittest/testcfg/devices/powerSwitcherList.cpp new file mode 100644 index 00000000..343f78d0 --- /dev/null +++ b/unittest/testcfg/devices/powerSwitcherList.cpp @@ -0,0 +1,4 @@ +#include "powerSwitcherList.h" + + + diff --git a/unittest/testcfg/devices/powerSwitcherList.h b/unittest/testcfg/devices/powerSwitcherList.h new file mode 100644 index 00000000..86ddea57 --- /dev/null +++ b/unittest/testcfg/devices/powerSwitcherList.h @@ -0,0 +1,12 @@ +#ifndef CONFIG_DEVICES_POWERSWITCHERLIST_H_ +#define CONFIG_DEVICES_POWERSWITCHERLIST_H_ + +namespace switches { + /* Switches are uint8_t datatype and go from 0 to 255 */ + enum switcherList { + }; + +} + + +#endif /* CONFIG_DEVICES_POWERSWITCHERLIST_H_ */ diff --git a/unittest/testcfg/events/subsystemIdRanges.h b/unittest/testcfg/events/subsystemIdRanges.h new file mode 100644 index 00000000..24eee819 --- /dev/null +++ b/unittest/testcfg/events/subsystemIdRanges.h @@ -0,0 +1,18 @@ +#ifndef CONFIG_EVENTS_SUBSYSTEMIDRANGES_H_ +#define CONFIG_EVENTS_SUBSYSTEMIDRANGES_H_ + +#include +#include + +/** + * @brief Custom subsystem IDs can be added here + * @details + * Subsystem IDs are used to create unique events. + */ +namespace SUBSYSTEM_ID { +enum: uint8_t { + SUBSYSTEM_ID_START = FW_SUBSYSTEM_ID_RANGE, +}; +} + +#endif /* CONFIG_EVENTS_SUBSYSTEMIDRANGES_H_ */ diff --git a/unittest/testcfg/ipc/MissionMessageTypes.cpp b/unittest/testcfg/ipc/MissionMessageTypes.cpp new file mode 100644 index 00000000..d68cb58c --- /dev/null +++ b/unittest/testcfg/ipc/MissionMessageTypes.cpp @@ -0,0 +1,12 @@ +#include "MissionMessageTypes.h" + +#include + +void messagetypes::clearMissionMessage(CommandMessage* message) { + switch(message->getMessageType()) { + default: + break; + } +} + + diff --git a/unittest/testcfg/ipc/MissionMessageTypes.h b/unittest/testcfg/ipc/MissionMessageTypes.h new file mode 100644 index 00000000..832d8e58 --- /dev/null +++ b/unittest/testcfg/ipc/MissionMessageTypes.h @@ -0,0 +1,22 @@ +#ifndef CONFIG_IPC_MISSIONMESSAGETYPES_H_ +#define CONFIG_IPC_MISSIONMESSAGETYPES_H_ + +#include + +class CommandMessage; + +/** + * Custom command messages are specified here. + * Most messages needed to use FSFW are already located in + * + * @param message Generic Command Message + */ +namespace messagetypes{ +enum MESSAGE_TYPE { + MISSION_MESSAGE_TYPE_START = FW_MESSAGES_COUNT, +}; + +void clearMissionMessage(CommandMessage* message); +} + +#endif /* CONFIG_IPC_MISSIONMESSAGETYPES_H_ */ diff --git a/unittest/testcfg/objects/Factory.cpp b/unittest/testcfg/objects/Factory.cpp new file mode 100644 index 00000000..e05b7942 --- /dev/null +++ b/unittest/testcfg/objects/Factory.cpp @@ -0,0 +1,34 @@ +#include "Factory.h" + +#include +#include + +#include +#include + +/** + * @brief Produces system objects. + * @details + * Build tasks by using SystemObject Interface (Interface). + * Header files of all tasks must be included + * Please note that an object has to implement the system object interface + * if the interface validity is checked or retrieved later by using the + * get(object_id) function from the ObjectManagerIF. + * + * Framework objects are created first. + * + * @ingroup init + */ +void Factory::produce(void) { + setStaticFrameworkObjectIds(); + new EventManager(objects::EVENT_MANAGER); + new HealthTable(objects::HEALTH_TABLE); + new InternalErrorReporter(objects::INTERNAL_ERROR_REPORTER); + +} + +void Factory::setStaticFrameworkObjectIds() { + +} + + diff --git a/unittest/testcfg/objects/Factory.h b/unittest/testcfg/objects/Factory.h new file mode 100644 index 00000000..84f9207e --- /dev/null +++ b/unittest/testcfg/objects/Factory.h @@ -0,0 +1,16 @@ +#ifndef FACTORY_H_ +#define FACTORY_H_ + +#include + +namespace Factory { + /** + * @brief Creates all SystemObject elements which are persistent + * during execution. + */ + void produce(); + void setStaticFrameworkObjectIds(); + +} + +#endif /* FACTORY_H_ */ diff --git a/unittest/testcfg/objects/systemObjectList.h b/unittest/testcfg/objects/systemObjectList.h new file mode 100644 index 00000000..0e034aff --- /dev/null +++ b/unittest/testcfg/objects/systemObjectList.h @@ -0,0 +1,16 @@ +#ifndef HOSTED_CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_ +#define HOSTED_CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_ + +#include +#include + +// The objects will be instantiated in the ID order +namespace objects { + enum sourceObjects: uint32_t { + /* All addresses between start and end are reserved for the FSFW */ + FSFW_CONFIG_RESERVED_START = PUS_SERVICE_1_VERIFICATION, + FSFW_CONFIG_RESERVED_END = TM_STORE + }; +} + +#endif /* BSP_CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_ */ diff --git a/unittest/testcfg/pollingsequence/PollingSequenceFactory.cpp b/unittest/testcfg/pollingsequence/PollingSequenceFactory.cpp new file mode 100644 index 00000000..f836a746 --- /dev/null +++ b/unittest/testcfg/pollingsequence/PollingSequenceFactory.cpp @@ -0,0 +1,23 @@ +#include "PollingSequenceFactory.h" + +#include +#include +#include + +ReturnValue_t pst::pollingSequenceInitDefault( + FixedTimeslotTaskIF *thisSequence) { + /* Length of a communication cycle */ + uint32_t length = thisSequence->getPeriodMs(); + + /* Add polling sequence table here */ + + if (thisSequence->checkSequence() == HasReturnvaluesIF::RETURN_OK) { + return HasReturnvaluesIF::RETURN_OK; + } + else { + sif::error << "pst::pollingSequenceInitDefault: Sequence invalid!" + << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } +} + diff --git a/unittest/testcfg/pollingsequence/PollingSequenceFactory.h b/unittest/testcfg/pollingsequence/PollingSequenceFactory.h new file mode 100644 index 00000000..c5d41b7d --- /dev/null +++ b/unittest/testcfg/pollingsequence/PollingSequenceFactory.h @@ -0,0 +1,32 @@ +#ifndef POLLINGSEQUENCEFACTORY_H_ +#define POLLINGSEQUENCEFACTORY_H_ + +#include + +class FixedTimeslotTaskIF; + +/** + * All device handlers are scheduled by adding them into Polling Sequence Tables (PST) + * to satisfy stricter timing requirements of device communication, + * A device handler has four different communication steps: + * 1. DeviceHandlerIF::SEND_WRITE -> Send write via interface + * 2. DeviceHandlerIF::GET_WRITE -> Get confirmation for write + * 3. DeviceHandlerIF::SEND_READ -> Send read request + * 4. DeviceHandlerIF::GET_READ -> Read from interface + * The PST specifies precisely when the respective ComIF functions are called + * during the communication cycle time. + * The task is created using the FixedTimeslotTaskIF, + * which utilises the underlying Operating System Abstraction Layer (OSAL) + * + * @param thisSequence FixedTimeslotTaskIF * object is passed inside the Factory class when creating the PST + * @return + */ +namespace pst { + +/* Default PST */ +ReturnValue_t pollingSequenceInitDefault(FixedTimeslotTaskIF *thisSequence); + + +} + +#endif /* POLLINGSEQUENCEINIT_H_ */ diff --git a/unittest/testcfg/returnvalues/classIds.h b/unittest/testcfg/returnvalues/classIds.h new file mode 100644 index 00000000..606cc60b --- /dev/null +++ b/unittest/testcfg/returnvalues/classIds.h @@ -0,0 +1,16 @@ +#ifndef CONFIG_RETURNVALUES_CLASSIDS_H_ +#define CONFIG_RETURNVALUES_CLASSIDS_H_ + +#include + +/** + * @brief CLASS_ID defintions which are required for custom returnvalues. + */ +namespace CLASS_ID { +enum { + MISSION_CLASS_ID_START = FW_CLASS_ID_COUNT, +}; +} + + +#endif /* CONFIG_RETURNVALUES_CLASSIDS_H_ */ diff --git a/unittest/testcfg/testcfg.mk b/unittest/testcfg/testcfg.mk new file mode 100644 index 00000000..64fa87f6 --- /dev/null +++ b/unittest/testcfg/testcfg.mk @@ -0,0 +1,15 @@ +CXXSRC += $(wildcard $(CURRENTPATH)/cdatapool/*.cpp) +CXXSRC += $(wildcard $(CURRENTPATH)/ipc/*.cpp) +CXXSRC += $(wildcard $(CURRENTPATH)/objects/*.cpp) +CXXSRC += $(wildcard $(CURRENTPATH)/pollingsequence/*.cpp) +CXXSRC += $(wildcard $(CURRENTPATH)/events/*.cpp) + +INCLUDES += $(CURRENTPATH) +INCLUDES += $(CURRENTPATH)/objects +INCLUDES += $(CURRENTPATH)/ipc +INCLUDES += $(CURRENTPATH)/pollingsequence +INCLUDES += $(CURRENTPATH)/returnvalues +INCLUDES += $(CURRENTPATH)/tmtc +INCLUDES += $(CURRENTPATH)/events +INCLUDES += $(CURRENTPATH)/devices +INCLUDES += $(CURRENTPATH)/cdatapool diff --git a/unittest/testcfg/tmtc/apid.h b/unittest/testcfg/tmtc/apid.h new file mode 100644 index 00000000..c0231bca --- /dev/null +++ b/unittest/testcfg/tmtc/apid.h @@ -0,0 +1,18 @@ +#ifndef CONFIG_TMTC_APID_H_ +#define CONFIG_TMTC_APID_H_ + +#include + +/** + * Application Process Definition: entity, uniquely identified by an + * application process ID (APID), capable of generating telemetry source + * packets and receiving telecommand packets. + * + * Chose APID(s) for mission and define it here. + */ +namespace apid { + static const uint16_t DEFAULT_APID = 0x00; +} + + +#endif /* CONFIG_TMTC_APID_H_ */ diff --git a/unittest/testcfg/tmtc/pusIds.h b/unittest/testcfg/tmtc/pusIds.h new file mode 100644 index 00000000..821a9982 --- /dev/null +++ b/unittest/testcfg/tmtc/pusIds.h @@ -0,0 +1,25 @@ +#ifndef CONFIG_TMTC_PUSIDS_HPP_ +#define CONFIG_TMTC_PUSIDS_HPP_ + +#include + +namespace pus { +enum Ids: uint8_t { + PUS_SERVICE_1 = 1, + PUS_SERVICE_2 = 2, + PUS_SERVICE_3 = 3, + PUS_SERVICE_5 = 5, + PUS_SERVICE_6 = 6, + PUS_SERVICE_8 = 8, + PUS_SERVICE_9 = 9, + PUS_SERVICE_11 = 11, + PUS_SERVICE_17 = 17, + PUS_SERVICE_19 = 19, + PUS_SERVICE_20 = 20, + PUS_SERVICE_23 = 23, + PUS_SERVICE_200 = 200, + PUS_SERVICE_201 = 201, +}; +}; + +#endif /* CONFIG_TMTC_PUSIDS_HPP_ */ diff --git a/unittest/tests/action/TestActionHelper.cpp b/unittest/tests/action/TestActionHelper.cpp new file mode 100644 index 00000000..d5b2e467 --- /dev/null +++ b/unittest/tests/action/TestActionHelper.cpp @@ -0,0 +1,106 @@ +//#include "TestActionHelper.h" +//#include +//#include +//#include +//#include "../../core/CatchDefinitions.h" +// +// +//TEST_CASE( "Action Helper" , "[ActionHelper]") { +// ActionHelperOwnerMockBase testDhMock; +// MessageQueueMockBase testMqMock; +// ActionHelper actionHelper = ActionHelper( +// &testDhMock, dynamic_cast(&testMqMock)); +// CommandMessage actionMessage; +// ActionId_t testActionId = 777; +// std::array testParams {1, 2, 3}; +// store_address_t paramAddress; +// StorageManagerIF *ipcStore = tglob::getIpcStoreHandle(); +// ipcStore->addData(¶mAddress, testParams.data(), 3); +// REQUIRE(actionHelper.initialize() == retval::CATCH_OK); +// +// SECTION ("Simple tests") { +// ActionMessage::setCommand(&actionMessage, testActionId, paramAddress); +// CHECK(not testDhMock.executeActionCalled); +// REQUIRE(actionHelper.handleActionMessage(&actionMessage) == retval::CATCH_OK); +// CHECK(testDhMock.executeActionCalled); +// // No message is sent if everything is alright. +// CHECK(not testMqMock.wasMessageSent()); +// store_address_t invalidAddress; +// ActionMessage::setCommand(&actionMessage, testActionId, invalidAddress); +// actionHelper.handleActionMessage(&actionMessage); +// CHECK(testMqMock.wasMessageSent()); +// const uint8_t* ptr = nullptr; +// size_t size = 0; +// REQUIRE(ipcStore->getData(paramAddress, &ptr, &size) == static_cast(StorageManagerIF::DATA_DOES_NOT_EXIST)); +// REQUIRE(ptr == nullptr); +// REQUIRE(size == 0); +// testDhMock.getBuffer(&ptr, &size); +// REQUIRE(size == 3); +// for(uint8_t i = 0; i<3;i++){ +// REQUIRE(ptr[i] == (i+1)); +// } +// testDhMock.clearBuffer(); +// } +// +// SECTION("Handle failures"){ +// actionMessage.setCommand(1234); +// REQUIRE(actionHelper.handleActionMessage(&actionMessage) == static_cast(CommandMessage::UNKNOWN_COMMAND)); +// CHECK(not testMqMock.wasMessageSent()); +// uint16_t step = 5; +// ReturnValue_t status = 0x1234; +// actionHelper.step(step, testMqMock.getId(), testActionId, status); +// step += 1; +// CHECK(testMqMock.wasMessageSent()); +// CommandMessage testMessage; +// REQUIRE(testMqMock.receiveMessage(&testMessage) == static_cast(HasReturnvaluesIF::RETURN_OK)); +// REQUIRE(testMessage.getCommand() == static_cast(ActionMessage::STEP_FAILED)); +// REQUIRE(testMessage.getParameter() == static_cast(testActionId)); +// uint32_t parameter2 = ((uint32_t)step << 16) | (uint32_t)status; +// REQUIRE(testMessage.getParameter2() == parameter2); +// REQUIRE(ActionMessage::getStep(&testMessage) == step); +// } +// +// SECTION("Handle finish"){ +// CHECK(not testMqMock.wasMessageSent()); +// ReturnValue_t status = 0x9876; +// actionHelper.finish(testMqMock.getId(), testActionId, status); +// CHECK(testMqMock.wasMessageSent()); +// CommandMessage testMessage; +// REQUIRE(testMqMock.receiveMessage(&testMessage) == static_cast(HasReturnvaluesIF::RETURN_OK)); +// REQUIRE(testMessage.getCommand() == static_cast(ActionMessage::COMPLETION_FAILED)); +// REQUIRE(ActionMessage::getActionId(&testMessage) == testActionId); +// REQUIRE(ActionMessage::getReturnCode(&testMessage) == static_cast(status)); +// } +// +// SECTION("Handle failed"){ +// store_address_t toLongParamAddress = StorageManagerIF::INVALID_ADDRESS; +// std::array toLongData = {5, 4, 3, 2, 1}; +// REQUIRE(ipcStore->addData(&toLongParamAddress, toLongData.data(), 5) == retval::CATCH_OK); +// ActionMessage::setCommand(&actionMessage, testActionId, toLongParamAddress); +// CHECK(not testDhMock.executeActionCalled); +// REQUIRE(actionHelper.handleActionMessage(&actionMessage) == retval::CATCH_OK); +// REQUIRE(ipcStore->getData(toLongParamAddress).first == static_cast(StorageManagerIF::DATA_DOES_NOT_EXIST)); +// CommandMessage testMessage; +// REQUIRE(testMqMock.receiveMessage(&testMessage) == static_cast(HasReturnvaluesIF::RETURN_OK)); +// REQUIRE(testMessage.getCommand() == static_cast(ActionMessage::STEP_FAILED)); +// REQUIRE(ActionMessage::getReturnCode(&testMessage) == 0xAFFE); +// REQUIRE(ActionMessage::getStep(&testMessage) == 0); +// REQUIRE(ActionMessage::getActionId(&testMessage) == testActionId); +// } +// +// SECTION("Missing IPC Data"){ +// ActionMessage::setCommand(&actionMessage, testActionId, StorageManagerIF::INVALID_ADDRESS); +// CHECK(not testDhMock.executeActionCalled); +// REQUIRE(actionHelper.handleActionMessage(&actionMessage) == retval::CATCH_OK); +// CommandMessage testMessage; +// REQUIRE(testMqMock.receiveMessage(&testMessage) == static_cast(HasReturnvaluesIF::RETURN_OK)); +// REQUIRE(testMessage.getCommand() == static_cast(ActionMessage::STEP_FAILED)); +// REQUIRE(ActionMessage::getReturnCode(&testMessage) == static_cast(StorageManagerIF::ILLEGAL_STORAGE_ID)); +// REQUIRE(ActionMessage::getStep(&testMessage) == 0); +// } +// +// +// SECTION("Data Reply"){ +// +// } +//} diff --git a/unittest/tests/action/TestActionHelper.h b/unittest/tests/action/TestActionHelper.h new file mode 100644 index 00000000..9bc93d3e --- /dev/null +++ b/unittest/tests/action/TestActionHelper.h @@ -0,0 +1,131 @@ +//#ifndef UNITTEST_HOSTED_TESTACTIONHELPER_H_ +//#define UNITTEST_HOSTED_TESTACTIONHELPER_H_ +// +//#include +//#include +//#include +//#include +// +// +//class ActionHelperOwnerMockBase: public HasActionsIF { +//public: +// bool getCommandQueueCalled = false; +// bool executeActionCalled = false; +// static const size_t MAX_SIZE = 3; +// uint8_t buffer[MAX_SIZE] = {0, 0, 0}; +// size_t size = 0; +// +// MessageQueueId_t getCommandQueue() const override { +// return tconst::testQueueId; +// } +// +// ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy, +// const uint8_t* data, size_t size) override { +// executeActionCalled = true; +// if(size > MAX_SIZE){ +// return 0xAFFE; +// } +// this->size = size; +// memcpy(buffer, data, size); +// return HasReturnvaluesIF::RETURN_OK; +// } +// +// void clearBuffer(){ +// this->size = 0; +// for(size_t i = 0; isize; +// } +// if(ptr != nullptr){ +// *ptr = buffer; +// } +// } +//}; +// +// +//class MessageQueueMockBase: public MessageQueueIF { +//public: +// MessageQueueId_t myQueueId = 0; +// bool defaultDestSet = false; +// bool messageSent = false; +// +// +// +// bool wasMessageSent() { +// bool tempMessageSent = messageSent; +// messageSent = false; +// return tempMessageSent; +// } +// +// virtual ReturnValue_t reply( MessageQueueMessage* message ) { +// messageSent = true; +// lastMessage = (*message); +// return HasReturnvaluesIF::RETURN_OK; +// }; +// virtual ReturnValue_t receiveMessage(MessageQueueMessage* message, +// MessageQueueId_t *receivedFrom) { +// (*message) = lastMessage; +// lastMessage.clear(); +// return HasReturnvaluesIF::RETURN_OK; +// } +// virtual ReturnValue_t receiveMessage(MessageQueueMessage* message) { +// (*message) = lastMessage; +// lastMessage.clear(); +// return HasReturnvaluesIF::RETURN_OK; +// } +// virtual ReturnValue_t flush(uint32_t* count) { +// return HasReturnvaluesIF::RETURN_OK; +// } +// virtual MessageQueueId_t getLastPartner() const { +// return tconst::testQueueId; +// } +// virtual MessageQueueId_t getId() const { +// return tconst::testQueueId; +// } +// virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo, +// MessageQueueMessage* message, MessageQueueId_t sentFrom, +// bool ignoreFault = false ) { +// messageSent = true; +// lastMessage = (*message); +// return HasReturnvaluesIF::RETURN_OK; +// } +// virtual ReturnValue_t sendMessage( MessageQueueId_t sendTo, +// MessageQueueMessage* message, bool ignoreFault = false ) override { +// messageSent = true; +// lastMessage = (*message); +// return HasReturnvaluesIF::RETURN_OK; +// } +// virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessage* message, +// MessageQueueId_t sentFrom, bool ignoreFault = false ) { +// messageSent = true; +// lastMessage = (*message); +// return HasReturnvaluesIF::RETURN_OK; +// } +// virtual ReturnValue_t sendToDefault( MessageQueueMessage* message ) { +// messageSent = true; +// lastMessage = (*message); +// return HasReturnvaluesIF::RETURN_OK; +// } +// virtual void setDefaultDestination(MessageQueueId_t defaultDestination) { +// myQueueId = defaultDestination; +// defaultDestSet = true; +// } +// +// virtual MessageQueueId_t getDefaultDestination() const { +// return myQueueId; +// } +// virtual bool isDefaultDestinationSet() const { +// return defaultDestSet; +// } +//private: +// MessageQueueMessage lastMessage; +// +//}; +// +// +//#endif /* UNITTEST_TESTFW_NEWTESTS_TESTACTIONHELPER_H_ */ diff --git a/unittest/tests/container/RingBufferTest.cpp b/unittest/tests/container/RingBufferTest.cpp new file mode 100644 index 00000000..8b82d407 --- /dev/null +++ b/unittest/tests/container/RingBufferTest.cpp @@ -0,0 +1,327 @@ +#include +#include +#include "../../core/CatchDefinitions.h" + +#include + +TEST_CASE("Ring Buffer Test" , "[RingBufferTest]") { + uint8_t testData[13]= {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + uint8_t readBuffer[10] = {13, 13, 13, 13, 13, 13, 13, 13, 13, 13}; + SimpleRingBuffer ringBuffer(10, false, 5); + + SECTION("Simple Test") { + REQUIRE(ringBuffer.availableWriteSpace() == 9); + REQUIRE(ringBuffer.writeData(testData, 9) == retval::CATCH_OK); + REQUIRE(ringBuffer.writeData(testData, 3) == retval::CATCH_FAILED); + REQUIRE(ringBuffer.readData(readBuffer, 5, true) == retval::CATCH_OK); + for(uint8_t i = 0; i< 5; i++) { + CHECK(readBuffer[i] == i); + } + REQUIRE(ringBuffer.availableWriteSpace() == 5); + ringBuffer.clear(); + REQUIRE(ringBuffer.availableWriteSpace() == 9); + REQUIRE(ringBuffer.writeData(testData, 4) == retval::CATCH_OK); + REQUIRE(ringBuffer.readData(readBuffer, 4, true) == retval::CATCH_OK); + for(uint8_t i = 0; i< 4; i++) { + CHECK(readBuffer[i] == i); + } + REQUIRE(ringBuffer.writeData(testData, 9) == retval::CATCH_OK); + REQUIRE(ringBuffer.readData(readBuffer, 9, true) == retval::CATCH_OK); + for(uint8_t i = 0; i< 9; i++) { + CHECK(readBuffer[i] == i); + } + + } + + SECTION("Get Free Element Test") { + REQUIRE(ringBuffer.availableWriteSpace() == 9); + REQUIRE(ringBuffer.writeData(testData, 8) == retval::CATCH_OK); + REQUIRE(ringBuffer.availableWriteSpace() == 1); + REQUIRE(ringBuffer.readData(readBuffer, 8, true) == retval::CATCH_OK); + REQUIRE(ringBuffer.availableWriteSpace() == 9); + uint8_t *testPtr = nullptr; + REQUIRE(ringBuffer.getFreeElement(&testPtr, 10) == retval::CATCH_FAILED); + + + REQUIRE(ringBuffer.writeTillWrap() == 2); + // too many excess bytes. + REQUIRE(ringBuffer.getFreeElement(&testPtr, 8) == retval::CATCH_FAILED); + REQUIRE(ringBuffer.getFreeElement(&testPtr, 5) == retval::CATCH_OK); + REQUIRE(ringBuffer.getExcessBytes() == 3); + std::memcpy(testPtr, testData, 5); + ringBuffer.confirmBytesWritten(5); + REQUIRE(ringBuffer.getAvailableReadData() == 5); + ringBuffer.readData(readBuffer, 5, true); + for(uint8_t i = 0; i< 5; i++) { + CHECK(readBuffer[i] == i); + } + } + + SECTION("Read Remaining Test") { + REQUIRE(ringBuffer.writeData(testData, 3) == retval::CATCH_OK); + REQUIRE(ringBuffer.getAvailableReadData() == 3); + REQUIRE(ringBuffer.readData(readBuffer, 5, false, false, nullptr) == retval::CATCH_FAILED); + size_t trueSize = 0; + REQUIRE(ringBuffer.readData(readBuffer, 5, false, true, &trueSize) == retval::CATCH_OK); + REQUIRE(trueSize == 3); + for(uint8_t i = 0; i< 3; i++) { + CHECK(readBuffer[i] == i); + } + trueSize = 0; + REQUIRE(ringBuffer.deleteData(5, false, &trueSize) == retval::CATCH_FAILED); + REQUIRE(trueSize == 0); + REQUIRE(ringBuffer.deleteData(5, true, &trueSize) == retval::CATCH_OK); + REQUIRE(trueSize == 3); + } +} + +TEST_CASE("Ring Buffer Test2" , "[RingBufferTest2]") { + uint8_t testData[13]= {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + uint8_t readBuffer[10] = {13, 13, 13, 13, 13, 13, 13, 13, 13, 13}; + uint8_t* newBuffer = new uint8_t[10]; + SimpleRingBuffer ringBuffer(newBuffer, 10, true, 5); + + SECTION("Simple Test") { + REQUIRE(ringBuffer.availableWriteSpace() == 9); + REQUIRE(ringBuffer.writeData(testData, 9) == retval::CATCH_OK); + REQUIRE(ringBuffer.readData(readBuffer, 5, true) == retval::CATCH_OK); + for(uint8_t i = 0; i< 5; i++) { + CHECK(readBuffer[i] == i); + } + REQUIRE(ringBuffer.availableWriteSpace() == 5); + ringBuffer.clear(); + REQUIRE(ringBuffer.availableWriteSpace() == 9); + REQUIRE(ringBuffer.writeData(testData, 4) == retval::CATCH_OK); + REQUIRE(ringBuffer.readData(readBuffer, 4, true) == retval::CATCH_OK); + for(uint8_t i = 0; i< 4; i++) { + CHECK(readBuffer[i] == i); + } + REQUIRE(ringBuffer.writeData(testData, 9) == retval::CATCH_OK); + REQUIRE(ringBuffer.readData(readBuffer, 9, true) == retval::CATCH_OK); + for(uint8_t i = 0; i< 9; i++) { + CHECK(readBuffer[i] == i); + } + + } + + SECTION("Get Free Element Test") { + REQUIRE(ringBuffer.availableWriteSpace() == 9); + REQUIRE(ringBuffer.writeData(testData, 8) == retval::CATCH_OK); + REQUIRE(ringBuffer.availableWriteSpace() == 1); + REQUIRE(ringBuffer.readData(readBuffer, 8, true) == retval::CATCH_OK); + REQUIRE(ringBuffer.availableWriteSpace() == 9); + uint8_t *testPtr = nullptr; + REQUIRE(ringBuffer.getFreeElement(&testPtr, 10) == retval::CATCH_FAILED); + + + REQUIRE(ringBuffer.writeTillWrap() == 2); + // too many excess bytes. + REQUIRE(ringBuffer.getFreeElement(&testPtr, 8) == retval::CATCH_FAILED); + REQUIRE(ringBuffer.getFreeElement(&testPtr, 5) == retval::CATCH_OK); + REQUIRE(ringBuffer.getExcessBytes() == 3); + std::memcpy(testPtr, testData, 5); + ringBuffer.confirmBytesWritten(5); + REQUIRE(ringBuffer.getAvailableReadData() == 5); + ringBuffer.readData(readBuffer, 5, true); + for(uint8_t i = 0; i< 5; i++) { + CHECK(readBuffer[i] == i); + } + } + + SECTION("Read Remaining Test") { + REQUIRE(ringBuffer.writeData(testData, 3) == retval::CATCH_OK); + REQUIRE(ringBuffer.getAvailableReadData() == 3); + REQUIRE(ringBuffer.readData(readBuffer, 5, false, false, nullptr) == retval::CATCH_FAILED); + size_t trueSize = 0; + REQUIRE(ringBuffer.readData(readBuffer, 5, false, true, &trueSize) == retval::CATCH_OK); + REQUIRE(trueSize == 3); + for(uint8_t i = 0; i< 3; i++) { + CHECK(readBuffer[i] == i); + } + trueSize = 0; + REQUIRE(ringBuffer.deleteData(5, false, &trueSize) == retval::CATCH_FAILED); + REQUIRE(trueSize == 0); + REQUIRE(ringBuffer.deleteData(5, true, &trueSize) == retval::CATCH_OK); + REQUIRE(trueSize == 3); + } + + SECTION("Overflow"){ + REQUIRE(ringBuffer.availableWriteSpace()==9); + //Writing more than the buffer is large, technically thats allowed + //But it is senseless and has undesired impact on read call + REQUIRE(ringBuffer.writeData(testData, 13) == retval::CATCH_OK); + REQUIRE(ringBuffer.getAvailableReadData()==3); + ringBuffer.clear(); + uint8_t * ptr = nullptr; + REQUIRE(ringBuffer.getFreeElement(&ptr, 13) == retval::CATCH_OK); + REQUIRE(ptr != nullptr); + memcpy(ptr, testData, 13); + ringBuffer.confirmBytesWritten(13); + REQUIRE(ringBuffer.getAvailableReadData()==3); + REQUIRE(ringBuffer.readData(readBuffer, 3, true)== retval::CATCH_OK); + for(auto i =0;i<3;i++){ + REQUIRE(readBuffer[i] == testData[i+10]); + } + } +} + +TEST_CASE("Ring Buffer Test3" , "[RingBufferTest3]") { + uint8_t testData[13]= {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + uint8_t readBuffer[10] = {13, 13, 13, 13, 13, 13, 13, 13, 13, 13}; + uint8_t* newBuffer = new uint8_t[10]; + SimpleRingBuffer ringBuffer(newBuffer, 10, true, 15); + + SECTION("Simple Test") { + REQUIRE(ringBuffer.availableWriteSpace() == 9); + REQUIRE(ringBuffer.writeData(testData, 9) == retval::CATCH_OK); + REQUIRE(ringBuffer.readData(readBuffer, 5, true) == retval::CATCH_OK); + for(uint8_t i = 0; i< 5; i++) { + CHECK(readBuffer[i] == i); + } + REQUIRE(ringBuffer.availableWriteSpace() == 5); + ringBuffer.clear(); + REQUIRE(ringBuffer.availableWriteSpace() == 9); + REQUIRE(ringBuffer.writeData(testData, 4) == retval::CATCH_OK); + REQUIRE(ringBuffer.readData(readBuffer, 4, true) == retval::CATCH_OK); + for(uint8_t i = 0; i< 4; i++) { + CHECK(readBuffer[i] == i); + } + REQUIRE(ringBuffer.writeData(testData, 9) == retval::CATCH_OK); + REQUIRE(ringBuffer.readData(readBuffer, 9, true) == retval::CATCH_OK); + for(uint8_t i = 0; i< 9; i++) { + CHECK(readBuffer[i] == i); + } + + } + + SECTION("Get Free Element Test") { + REQUIRE(ringBuffer.availableWriteSpace() == 9); + REQUIRE(ringBuffer.writeData(testData, 8) == retval::CATCH_OK); + REQUIRE(ringBuffer.availableWriteSpace() == 1); + REQUIRE(ringBuffer.readData(readBuffer, 8, true) == retval::CATCH_OK); + REQUIRE(ringBuffer.availableWriteSpace() == 9); + uint8_t *testPtr = nullptr; + REQUIRE(ringBuffer.getFreeElement(&testPtr, 10) == retval::CATCH_OK); + REQUIRE(ringBuffer.getExcessBytes() == 8); + + REQUIRE(ringBuffer.writeTillWrap() == 2); + // too many excess bytes. + REQUIRE(ringBuffer.getFreeElement(&testPtr, 8) == retval::CATCH_FAILED); + // Less Execss bytes overwrites before + REQUIRE(ringBuffer.getFreeElement(&testPtr, 3) == retval::CATCH_OK); + REQUIRE(ringBuffer.getExcessBytes() == 1); + std::memcpy(testPtr, testData, 3); + ringBuffer.confirmBytesWritten(3); + REQUIRE(ringBuffer.getAvailableReadData() == 3); + ringBuffer.readData(readBuffer, 3, true); + for(uint8_t i = 0; i< 3; i++) { + CHECK(readBuffer[i] == i); + } + } + + SECTION("Read Remaining Test") { + REQUIRE(ringBuffer.writeData(testData, 3) == retval::CATCH_OK); + REQUIRE(ringBuffer.getAvailableReadData() == 3); + REQUIRE(ringBuffer.readData(readBuffer, 5, false, false, nullptr) == retval::CATCH_FAILED); + size_t trueSize = 0; + REQUIRE(ringBuffer.readData(readBuffer, 5, false, true, &trueSize) == retval::CATCH_OK); + REQUIRE(trueSize == 3); + for(uint8_t i = 0; i< 3; i++) { + CHECK(readBuffer[i] == i); + } + trueSize = 0; + REQUIRE(ringBuffer.deleteData(5, false, &trueSize) == retval::CATCH_FAILED); + REQUIRE(trueSize == 0); + REQUIRE(ringBuffer.deleteData(5, true, &trueSize) == retval::CATCH_OK); + REQUIRE(trueSize == 3); + } + + SECTION("Overflow"){ + REQUIRE(ringBuffer.availableWriteSpace()==9); + //Writing more than the buffer is large, technically thats allowed + //But it is senseless and has undesired impact on read call + REQUIRE(ringBuffer.writeData(testData, 13) == retval::CATCH_OK); + REQUIRE(ringBuffer.getAvailableReadData()==3); + ringBuffer.clear(); + uint8_t * ptr = nullptr; + REQUIRE(ringBuffer.getFreeElement(&ptr, 13) == retval::CATCH_OK); + REQUIRE(ptr != nullptr); + memcpy(ptr, testData, 13); + ringBuffer.confirmBytesWritten(13); + REQUIRE(ringBuffer.getAvailableReadData()==3); + REQUIRE(ringBuffer.readData(readBuffer, 3, true)== retval::CATCH_OK); + for(auto i =0;i<3;i++){ + REQUIRE(readBuffer[i] == testData[i+10]); + } + } +} + +TEST_CASE("Ring Buffer Test4" , "[RingBufferTest4]") { + uint8_t testData[13]= {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + uint8_t readBuffer[10] = {13, 13, 13, 13, 13, 13, 13, 13, 13, 13}; + SimpleRingBuffer ringBuffer(10, false, 15); + + SECTION("Simple Test") { + REQUIRE(ringBuffer.availableWriteSpace() == 9); + REQUIRE(ringBuffer.writeData(testData, 9) == retval::CATCH_OK); + REQUIRE(ringBuffer.writeData(testData, 3) == retval::CATCH_FAILED); + REQUIRE(ringBuffer.readData(readBuffer, 5, true) == retval::CATCH_OK); + for(uint8_t i = 0; i< 5; i++) { + CHECK(readBuffer[i] == i); + } + REQUIRE(ringBuffer.availableWriteSpace() == 5); + ringBuffer.clear(); + REQUIRE(ringBuffer.availableWriteSpace() == 9); + REQUIRE(ringBuffer.writeData(testData, 4) == retval::CATCH_OK); + REQUIRE(ringBuffer.readData(readBuffer, 4, true) == retval::CATCH_OK); + for(uint8_t i = 0; i< 4; i++) { + CHECK(readBuffer[i] == i); + } + REQUIRE(ringBuffer.writeData(testData, 9) == retval::CATCH_OK); + REQUIRE(ringBuffer.readData(readBuffer, 9, true) == retval::CATCH_OK); + for(uint8_t i = 0; i< 9; i++) { + CHECK(readBuffer[i] == i); + } + + } + + SECTION("Get Free Element Test") { + REQUIRE(ringBuffer.availableWriteSpace() == 9); + REQUIRE(ringBuffer.writeData(testData, 8) == retval::CATCH_OK); + REQUIRE(ringBuffer.availableWriteSpace() == 1); + REQUIRE(ringBuffer.readData(readBuffer, 8, true) == retval::CATCH_OK); + REQUIRE(ringBuffer.availableWriteSpace() == 9); + uint8_t *testPtr = nullptr; + REQUIRE(ringBuffer.getFreeElement(&testPtr, 10) == retval::CATCH_FAILED); + + + REQUIRE(ringBuffer.writeTillWrap() == 2); + REQUIRE(ringBuffer.getFreeElement(&testPtr, 8) == retval::CATCH_OK); + REQUIRE(ringBuffer.getFreeElement(&testPtr, 5) == retval::CATCH_OK); + REQUIRE(ringBuffer.getExcessBytes() == 3); + std::memcpy(testPtr, testData, 5); + ringBuffer.confirmBytesWritten(5); + REQUIRE(ringBuffer.getAvailableReadData() == 5); + ringBuffer.readData(readBuffer, 5, true); + for(uint8_t i = 0; i< 5; i++) { + CHECK(readBuffer[i] == i); + } + } + + SECTION("Read Remaining Test") { + REQUIRE(ringBuffer.writeData(testData, 3) == retval::CATCH_OK); + REQUIRE(ringBuffer.getAvailableReadData() == 3); + REQUIRE(ringBuffer.readData(readBuffer, 5, false, false, nullptr) == retval::CATCH_FAILED); + size_t trueSize = 0; + REQUIRE(ringBuffer.readData(readBuffer, 5, false, true, &trueSize) == retval::CATCH_OK); + REQUIRE(trueSize == 3); + for(uint8_t i = 0; i< 3; i++) { + CHECK(readBuffer[i] == i); + } + trueSize = 0; + REQUIRE(ringBuffer.deleteData(5, false, &trueSize) == retval::CATCH_FAILED); + REQUIRE(trueSize == 0); + REQUIRE(ringBuffer.deleteData(5, true, &trueSize) == retval::CATCH_OK); + REQUIRE(trueSize == 3); + } +} diff --git a/unittest/tests/container/TestArrayList.cpp b/unittest/tests/container/TestArrayList.cpp new file mode 100644 index 00000000..914188cb --- /dev/null +++ b/unittest/tests/container/TestArrayList.cpp @@ -0,0 +1,90 @@ +#include +#include +#include +#include "../../core/CatchDefinitions.h" + +/** + * @brief Array List test + */ +TEST_CASE("Array List" , "[ArrayListTest]") { + //perform set-up here + ArrayList list(20); + struct TestClass{ + public: + TestClass(){}; + TestClass(uint32_t number1, uint64_t number2): + number1(number1), number2(number2){}; + uint32_t number1 = -1; + uint64_t number2 = -1; + bool operator==(const TestClass& other){ + return ((this->number1 == other.number1) and (this->number2 == other.number2)); + }; + }; + ArrayList complexList(20); + SECTION("SimpleTest") { + REQUIRE(list.maxSize()==20); + REQUIRE(list.size == 0); + REQUIRE(list.insert(10) == static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(list[0] == 10); + REQUIRE(list.front() != nullptr); + REQUIRE((*list.front()) == 10); + REQUIRE(list.back() != nullptr); + REQUIRE((*list.back()) == 10); + // Need to test the const version of back as well + const uint16_t* number = const_cast*>(&list)->back(); + REQUIRE(*number == 10); + list.clear(); + REQUIRE(list.size == 0); + } + SECTION("Fill and check"){ + //This is an invalid element but its not a nullptr + REQUIRE(list.back() != nullptr); + for (auto i =0; i < 20; i++){ + REQUIRE(list.insert(i) == static_cast(HasReturnvaluesIF::RETURN_OK)); + } + REQUIRE(list.insert(20) == static_cast(ArrayList::FULL)); + ArrayList::Iterator it = list.begin(); + REQUIRE((*it) == 0); + it++; + REQUIRE((*it) == 1); + it--; + REQUIRE((*it) == 0); + it++; + for(auto it2 = list.begin(); it2!=list.end(); it2++){ + if (it == it2){ + REQUIRE((*it) == (*it2)); + break; + }else{ + REQUIRE((*it2) == 0); + REQUIRE(it2 != it); + } + } + } + SECTION("Const Iterator"){ + ArrayList::Iterator it = list.begin(); + for (auto i =0; i < 10; i++){ + REQUIRE(list.insert(i) == static_cast(HasReturnvaluesIF::RETURN_OK)); + } + it++; + const uint16_t* number = it.value; + REQUIRE(*number == 1); + } + + SECTION("Const Iterator"){ + ArrayList::Iterator it = complexList.begin(); + for (auto i =0; i < 10; i++){ + REQUIRE(complexList.insert(TestClass(i, i+1)) == static_cast(HasReturnvaluesIF::RETURN_OK)); + } + it++; + const TestClass* secondTest = it.value; + bool compare = TestClass(1, 2) == *secondTest; + REQUIRE(compare); + it++; + REQUIRE(it->number1 == 2); + REQUIRE(it->number2 == 3); + const ArrayList::Iterator it4(&(complexList[2])); + REQUIRE(it4->number1 == 2); + REQUIRE((*it4).number2 == 3); + REQUIRE(complexList.remaining()==10); + } +} diff --git a/unittest/tests/container/TestDynamicFifo.cpp b/unittest/tests/container/TestDynamicFifo.cpp new file mode 100644 index 00000000..6c9b7415 --- /dev/null +++ b/unittest/tests/container/TestDynamicFifo.cpp @@ -0,0 +1,149 @@ + +#include +#include +#include + +#include +#include + +TEST_CASE( "Dynamic Fifo Tests", "[TestDynamicFifo]") { + INFO("Dynamic Fifo Tests"); + struct Test{ + uint64_t number1; + uint32_t number2; + uint8_t number3; + bool operator==(struct Test& other){ + if ((other.number1 == this->number1) and + (other.number1 == this->number1) and + (other.number1 == this->number1)){ + return true; + } + return false; + } + }; + DynamicFIFO fifo(3); + std::vector list; + + struct Test structOne({UINT64_MAX, UINT32_MAX, UINT8_MAX}); + struct Test structTwo({0, 1, 2}); + struct Test structThree({42, 43, 44}); + list.push_back(structThree); + list.push_back(structTwo); + list.push_back(structOne); + SECTION("Insert, retrieval test"){ + REQUIRE(fifo.getMaxCapacity()==3); + REQUIRE(fifo.size()==0); + REQUIRE(fifo.empty()); + REQUIRE(not fifo.full()); + + REQUIRE(fifo.insert(structOne)==static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(fifo.insert(structTwo)==static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(fifo.insert(structThree)==static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(fifo.insert(structTwo)==static_cast(FIFOBase::FULL)); + + struct Test testptr; + REQUIRE(fifo.peek(&testptr)==static_cast(HasReturnvaluesIF::RETURN_OK)); + bool equal = testptr == structOne; + REQUIRE(equal); + REQUIRE(fifo.size()==3); + REQUIRE(fifo.full()); + REQUIRE(not fifo.empty()); + + for(size_t i=2;i<3;i--){ + testptr.number1 = 0; + testptr.number2 = 0; + testptr.number3 = 0; + REQUIRE(fifo.retrieve(&testptr)==static_cast(HasReturnvaluesIF::RETURN_OK)); + equal = testptr == list[i]; + REQUIRE(equal); + REQUIRE(fifo.size()==i); + } + testptr.number1 = 0; + testptr.number2 = 0; + testptr.number3 = 0; + REQUIRE(fifo.retrieve(&testptr)==static_cast(FIFOBase::EMPTY)); + REQUIRE(fifo.peek(&testptr)==static_cast(FIFOBase::EMPTY)); + REQUIRE(not fifo.full()); + REQUIRE(fifo.empty()); + REQUIRE(fifo.pop()==static_cast(FIFOBase::EMPTY)); + + REQUIRE(fifo.insert(structOne)==static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(fifo.size()==1); + REQUIRE(fifo.insert(structTwo)==static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(fifo.size()==2); + REQUIRE(fifo.pop()==static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(fifo.size()==1); + testptr.number1 = 0; + testptr.number2 = 0; + testptr.number3 = 0; + REQUIRE(fifo.peek(&testptr)==static_cast(HasReturnvaluesIF::RETURN_OK)); + equal = testptr == structTwo; + REQUIRE(equal); + REQUIRE(fifo.pop()==static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(fifo.size()==0); + REQUIRE(fifo.empty()); + //struct Test* ptr = nullptr; + //REQUIRE(fifo.retrieve(ptr) == static_cast(HasReturnvaluesIF::RETURN_FAILED)); + //REQUIRE(fifo.peek(ptr) == static_cast(HasReturnvaluesIF::RETURN_FAILED)); + }; + SECTION("Copy Test"){ + REQUIRE(fifo.insert(structOne)==static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(fifo.insert(structTwo)==static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(fifo.insert(structThree)==static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(fifo.size()==3); + REQUIRE(fifo.full()); + REQUIRE(not fifo.empty()); + + DynamicFIFO fifo2(fifo); + REQUIRE(fifo2.size()==3); + REQUIRE(fifo2.full()); + REQUIRE(not fifo2.empty()); + + }; + + SECTION("Assignment Test"){ + REQUIRE(fifo.insert(structOne)==static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(fifo.insert(structTwo)==static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(fifo.insert(structThree)==static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(fifo.size()==3); + REQUIRE(fifo.full()); + REQUIRE(not fifo.empty()); + + DynamicFIFO fifo2(6); + fifo2 = fifo; + REQUIRE(fifo2.size()==3); + REQUIRE(fifo2.full()); + REQUIRE(not fifo2.empty()); + for(size_t i=2;i<3;i--){ + struct Test testptr = {0, 0, 0}; + REQUIRE(fifo2.retrieve(&testptr)==static_cast(HasReturnvaluesIF::RETURN_OK)); + bool equal = testptr == list[i]; + REQUIRE(equal); + REQUIRE(fifo2.size()==i); + } + + }; + + SECTION("Assignment Test Smaller"){ + REQUIRE(fifo.insert(structOne)==static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(fifo.insert(structTwo)==static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(fifo.insert(structThree)==static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(fifo.size()==3); + REQUIRE(fifo.full()); + REQUIRE(not fifo.empty()); + + DynamicFIFO fifo2(2); + fifo2 = fifo; + REQUIRE(fifo2.size()==3); + REQUIRE(fifo2.full()); + REQUIRE(not fifo2.empty()); + for(size_t i=2;i<3;i--){ + struct Test testptr = {0, 0, 0}; + REQUIRE(fifo2.retrieve(&testptr)==static_cast(HasReturnvaluesIF::RETURN_OK)); + bool equal = testptr == list[i]; + REQUIRE(equal); + REQUIRE(fifo2.size()==i); + } + }; + +}; diff --git a/unittest/tests/container/TestFifo.cpp b/unittest/tests/container/TestFifo.cpp new file mode 100644 index 00000000..3775f424 --- /dev/null +++ b/unittest/tests/container/TestFifo.cpp @@ -0,0 +1,138 @@ + +#include +#include +#include + +#include +#include "../../core/CatchDefinitions.h" + +TEST_CASE( "Static Fifo Tests", "[TestFifo]") { + INFO("Fifo Tests"); + struct Test{ + uint64_t number1; + uint32_t number2; + uint8_t number3; + bool operator==(struct Test& other){ + if ((other.number1 == this->number1) and + (other.number1 == this->number1) and + (other.number1 == this->number1)){ + return true; + } + return false; + } + }; + FIFO fifo; + std::vector list; + + struct Test structOne({UINT64_MAX, UINT32_MAX, UINT8_MAX}); + struct Test structTwo({0, 1, 2}); + struct Test structThree({42, 43, 44}); + list.push_back(structThree); + list.push_back(structTwo); + list.push_back(structOne); + SECTION("Insert, retrieval test"){ + REQUIRE(fifo.getMaxCapacity()==3); + REQUIRE(fifo.size()==0); + REQUIRE(fifo.empty()); + REQUIRE(not fifo.full()); + + REQUIRE(fifo.insert(structOne)==static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(fifo.insert(structTwo)==static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(fifo.insert(structThree)==static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(fifo.insert(structTwo)==static_cast(FIFOBase::FULL)); + + struct Test testptr; + REQUIRE(fifo.peek(&testptr)==static_cast(HasReturnvaluesIF::RETURN_OK)); + bool equal = testptr == structOne; + REQUIRE(equal); + REQUIRE(fifo.size()==3); + REQUIRE(fifo.full()); + REQUIRE(not fifo.empty()); + + for(size_t i=2;i<3;i--){ + testptr.number1 = 0; + testptr.number2 = 0; + testptr.number3 = 0; + REQUIRE(fifo.retrieve(&testptr)==static_cast(HasReturnvaluesIF::RETURN_OK)); + equal = testptr == list[i]; + REQUIRE(equal); + REQUIRE(fifo.size()==i); + } + testptr.number1 = 0; + testptr.number2 = 0; + testptr.number3 = 0; + REQUIRE(fifo.retrieve(&testptr)==static_cast(FIFOBase::EMPTY)); + REQUIRE(fifo.peek(&testptr)==static_cast(FIFOBase::EMPTY)); + REQUIRE(not fifo.full()); + REQUIRE(fifo.empty()); + REQUIRE(fifo.pop()==static_cast(FIFOBase::EMPTY)); + + REQUIRE(fifo.insert(structOne)==static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(fifo.size()==1); + REQUIRE(fifo.insert(structTwo)==static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(fifo.size()==2); + REQUIRE(fifo.pop()==static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(fifo.size()==1); + testptr.number1 = 0; + testptr.number2 = 0; + testptr.number3 = 0; + + // Test that retrieve and peek will not cause a nullptr dereference + struct Test* ptr = nullptr; + REQUIRE(fifo.retrieve(ptr) == static_cast(HasReturnvaluesIF::RETURN_FAILED)); + REQUIRE(fifo.peek(ptr) == static_cast(HasReturnvaluesIF::RETURN_FAILED)); + + + REQUIRE(fifo.peek(&testptr)==static_cast(HasReturnvaluesIF::RETURN_OK)); + equal = testptr == structTwo; + REQUIRE(equal); + REQUIRE(fifo.pop()==static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(fifo.size()==0); + REQUIRE(fifo.empty()); + + + }; + SECTION("Copy Test"){ + REQUIRE(fifo.insert(structOne)==static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(fifo.insert(structTwo)==static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(fifo.insert(structThree)==static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(fifo.size()==3); + REQUIRE(fifo.full()); + REQUIRE(not fifo.empty()); + + FIFO fifo2(fifo); + REQUIRE(fifo2.size()==3); + REQUIRE(fifo2.full()); + REQUIRE(not fifo2.empty()); + for(size_t i=2;i<3;i--){ + struct Test testptr = {0, 0, 0}; + REQUIRE(fifo2.retrieve(&testptr)==static_cast(HasReturnvaluesIF::RETURN_OK)); + bool equal = testptr == list[i]; + REQUIRE(equal); + REQUIRE(fifo2.size()==i); + } + + }; + + SECTION("Assignment Test"){ + REQUIRE(fifo.insert(structOne)==static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(fifo.insert(structTwo)==static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(fifo.insert(structThree)==static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(fifo.size()==3); + REQUIRE(fifo.full()); + REQUIRE(not fifo.empty()); + + FIFO fifo2; + fifo2 = fifo; + REQUIRE(fifo2.size()==3); + REQUIRE(fifo2.full()); + REQUIRE(not fifo2.empty()); + for(size_t i=2;i<3;i--){ + struct Test testptr = {0, 0, 0}; + REQUIRE(fifo2.retrieve(&testptr)==static_cast(HasReturnvaluesIF::RETURN_OK)); + bool equal = testptr == list[i]; + REQUIRE(equal); + REQUIRE(fifo2.size()==i); + } + }; +}; diff --git a/unittest/tests/container/TestFixedArrayList.cpp b/unittest/tests/container/TestFixedArrayList.cpp new file mode 100644 index 00000000..737932e3 --- /dev/null +++ b/unittest/tests/container/TestFixedArrayList.cpp @@ -0,0 +1,42 @@ +#include "../../core/CatchDefinitions.h" + +#include +#include + +#include + + +TEST_CASE( "FixedArrayList Tests", "[TestFixedArrayList]") { + INFO("FixedArrayList Tests"); + using testList = FixedArrayList; + testList list; + REQUIRE(list.size==0); + REQUIRE(list.insert(10) == static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(list.size==1); + REQUIRE(list.maxSize()==260); + SECTION("Copy Constructor"){ + testList list2(list); + REQUIRE(list2.size==1); + REQUIRE(list2[0] == 10); + REQUIRE(list.maxSize()==260); + }; + SECTION("Assignment copy"){ + testList list2; + REQUIRE(list2.size==0); + list2 = list; + REQUIRE(list2.size==1); + REQUIRE(list2[0] == 10); + REQUIRE(list.maxSize()==260); + }; + SECTION("Fill"){ + for(auto i=1;i<260;i++){ + REQUIRE(list.insert(i) == static_cast(HasReturnvaluesIF::RETURN_OK)); + } + REQUIRE(list.insert(260) == static_cast(ArrayList::FULL)); + list.clear(); + REQUIRE(list.size == 0); + } +} + + + diff --git a/unittest/tests/container/TestFixedMap.cpp b/unittest/tests/container/TestFixedMap.cpp new file mode 100644 index 00000000..079062f0 --- /dev/null +++ b/unittest/tests/container/TestFixedMap.cpp @@ -0,0 +1,172 @@ +#include +#include + +#include +#include "../../core/CatchDefinitions.h" + +template class FixedMap; + +TEST_CASE( "FixedMap Tests", "[TestFixedMap]") { + INFO("FixedMap Tests"); + + FixedMap map(30); + REQUIRE(map.size() == 0); + REQUIRE(map.maxSize() == 30); + REQUIRE(map.getSerializedSize() == sizeof(uint32_t)); + REQUIRE(map.empty()); + REQUIRE(not map.full()); + + SECTION("Fill and erase"){ + for (uint16_t i=0;i<30;i++){ + REQUIRE(map.insert(std::make_pair(i, i+1))== static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(map.exists(i) == static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(map.find(i)->second==i+1); + REQUIRE(not map.empty()); + } + REQUIRE(map.insert(0, 0) == static_cast(FixedMap::KEY_ALREADY_EXISTS)); + REQUIRE(map.insert(31, 0) == static_cast(FixedMap::MAP_FULL)); + REQUIRE(map.exists(31) == static_cast(FixedMap::KEY_DOES_NOT_EXIST)); + REQUIRE(map.size() == 30); + REQUIRE(map.full()); + { + uint16_t* ptr; + REQUIRE(map.find(5,&ptr) == static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(*ptr == 6); + REQUIRE(*(map.findValue(6)) == 7); + REQUIRE(map.find(31,&ptr) == static_cast(FixedMap::KEY_DOES_NOT_EXIST)); + } + + REQUIRE(map.getSerializedSize() == (sizeof(uint32_t)+ 30*(sizeof(uint32_t) + sizeof(uint16_t)))); + REQUIRE(map.erase(2) == static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(map.erase(31) == static_cast(FixedMap::KEY_DOES_NOT_EXIST)); + REQUIRE(map.exists(2) == static_cast(FixedMap::KEY_DOES_NOT_EXIST)); + REQUIRE(map.size() == 29); + + for (auto element: map){ + if (element.first == 5){ + REQUIRE(element.second == 6); + } + } + + for (FixedMap::Iterator it = map.begin(); it != map.end(); it++){ + REQUIRE(it->second == it->first + 1); + REQUIRE((*it).second == (*it).first + 1); + it->second = it->second + 1; + REQUIRE(it->second == it->first + 2); + } + + for (FixedMap::Iterator it = map.begin(); it != map.end(); it++){ + REQUIRE(map.erase(&it) == static_cast(HasReturnvaluesIF::RETURN_OK)); + } + + REQUIRE(map.size() == 0); + + for (FixedMap::Iterator it = map.begin(); it != map.end(); it++){ + // This line should never executed if begin and end is correct + FAIL("Should never be reached, Iterators invalid"); + } + }; + + SECTION("Insert variants"){ + FixedMap::Iterator it = map.end(); + REQUIRE(map.insert(36, 37, &it) == static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(it->first == 36); + REQUIRE(it->second == 37); + REQUIRE(map.size() == 1); + REQUIRE(map.insert(37, 38, nullptr) == static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(map.find(37)->second == 38); + REQUIRE(map.size() == 2); + REQUIRE(map.insert(37, 24, nullptr) == static_cast(FixedMap::KEY_ALREADY_EXISTS)); + REQUIRE(map.find(37)->second != 24); + REQUIRE(map.size() == 2); + }; + SECTION("Serialize and DeSerialize") { + REQUIRE(map.insert(36, 37, nullptr) == static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(map.insert(37, 38, nullptr) == static_cast(HasReturnvaluesIF::RETURN_OK)); + uint8_t buffer[sizeof(uint32_t) + + 2 * (sizeof(uint32_t) + sizeof(uint16_t))]; + REQUIRE( + map.getSerializedSize() + == (sizeof(uint32_t) + + 2 * (sizeof(uint32_t) + sizeof(uint16_t)))); + uint8_t *loc_ptr = buffer; + size_t size = 0; + REQUIRE( + map.serialize(&loc_ptr, &size, 10, SerializeIF::Endianness::BIG) + == static_cast(SerializeIF::BUFFER_TOO_SHORT)); + loc_ptr = buffer; + size = 0; + REQUIRE( + map.serialize(&loc_ptr, &size, + sizeof(uint32_t) + + 2 * (sizeof(uint32_t) + sizeof(uint16_t)), + SerializeIF::Endianness::BIG) + == static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(size == 16); + + uint32_t internal_size = 0; + const uint8_t *ptr2 = buffer; + REQUIRE( + SerializeAdapter::deSerialize(&internal_size, &ptr2, &size, + SerializeIF::Endianness::BIG) + == static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(internal_size == 2); + for (uint8_t i = 36; i < 38; i++) { + uint32_t first_element = 0; + REQUIRE( + SerializeAdapter::deSerialize(&first_element, &ptr2, &size, + SerializeIF::Endianness::BIG) + == static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(first_element == i); + uint16_t second_element = 0; + REQUIRE( + SerializeAdapter::deSerialize(&second_element, &ptr2, &size, + SerializeIF::Endianness::BIG) + == static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(second_element == i + 1); + } + REQUIRE(size == 0); + map.clear(); + const uint8_t* constPtr = buffer; + size = 16; + REQUIRE(map.size() == 0); + REQUIRE(map.deSerialize(&constPtr, &size, + SerializeIF::Endianness::BIG) == static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(map.size() == 2); + REQUIRE(map.find(36)->second == 37); + for(auto& element: map){ + REQUIRE((element.first+1) == element.second); + } + }; + + + SECTION("Failed erase and deSerialize"){ + FixedMap::Iterator it; + std::pair pair = std::make_pair(44, 43); + it = FixedMap::Iterator(&pair); + REQUIRE(map.erase(&it) == static_cast(FixedMap::KEY_DOES_NOT_EXIST)); + REQUIRE(map.find(45) == map.end()); + size_t toLargeMap = 100; + const uint8_t* ptr = reinterpret_cast(&toLargeMap); + size_t size = sizeof(size_t); + REQUIRE(map.deSerialize(&ptr, &size, SerializeIF::Endianness::BIG) == + static_cast(SerializeIF::TOO_MANY_ELEMENTS)); + }; + SECTION("Little Endianess"){ + map.clear(); + map.insert(10,20, nullptr); + uint8_t newBuffer[sizeof(uint32_t)+ 1*(sizeof(uint32_t) + sizeof(uint16_t))]; + uint8_t* ptr = newBuffer; + size_t size = 0; + size_t max_size = sizeof(uint32_t)+ 1*(sizeof(uint32_t) + sizeof(uint16_t)); + REQUIRE(map.serialize(&ptr, &size, max_size, + SerializeIF::Endianness::LITTLE) == static_cast(HasReturnvaluesIF::RETURN_OK)); + map.clear(); + REQUIRE(map.size()==0); + const uint8_t* ptr2 = newBuffer; + REQUIRE(map.deSerialize(&ptr2, &size, + SerializeIF::Endianness::LITTLE) == static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(map.size()==1); + REQUIRE(map.find(10)->second == 20); + }; +} diff --git a/unittest/tests/container/TestFixedOrderedMultimap.cpp b/unittest/tests/container/TestFixedOrderedMultimap.cpp new file mode 100644 index 00000000..95194cb5 --- /dev/null +++ b/unittest/tests/container/TestFixedOrderedMultimap.cpp @@ -0,0 +1,203 @@ +#include +#include + +#include +#include "../../core/CatchDefinitions.h" + +TEST_CASE( "FixedOrderedMultimap Tests", "[TestFixedOrderedMultimap]") { + INFO("FixedOrderedMultimap Tests"); + + FixedOrderedMultimap map(30); + REQUIRE(map.size() == 0); + REQUIRE(map.maxSize() == 30); + + SECTION("Test insert, find, exists"){ + for (uint16_t i=0;i<30;i++){ + REQUIRE(map.insert(std::make_pair(i, i+1))== static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(map.exists(i) == static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(map.find(i)->second==i+1); + } + REQUIRE(map.insert(0, 0) == static_cast(FixedOrderedMultimap::MAP_FULL)); + REQUIRE(map.exists(31) == static_cast(FixedOrderedMultimap::KEY_DOES_NOT_EXIST)); + REQUIRE(map.size() == 30); + { + uint16_t* ptr; + REQUIRE(map.find(5,&ptr) == static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(*ptr == 6); + REQUIRE(map.find(31,&ptr) == static_cast(FixedOrderedMultimap::KEY_DOES_NOT_EXIST)); + } + REQUIRE(map.erase(2) == static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(map.erase(31) == static_cast(FixedOrderedMultimap::KEY_DOES_NOT_EXIST)); + REQUIRE(map.exists(2) == static_cast(FixedOrderedMultimap::KEY_DOES_NOT_EXIST)); + REQUIRE(map.size() == 29); + + for (auto element: map){ + if (element.first == 5){ + REQUIRE(element.second == 6); + } + } + + for (FixedOrderedMultimap::Iterator it = map.begin(); it != map.end(); it++){ + REQUIRE(it->second == it->first + 1); + REQUIRE((*it).second == (*it).first + 1); + it->second = it->second + 1; + REQUIRE(it->second == it->first + 2); + } + + { + FixedOrderedMultimap::Iterator it = map.begin(); + while(it != map.end()){ + REQUIRE(map.erase(&it) == static_cast(HasReturnvaluesIF::RETURN_OK)); + } + REQUIRE(map.size() == 0); + } + + for (FixedOrderedMultimap::Iterator it = map.begin(); it != map.end(); it++){ + // This line should never executed if begin and end is correct + FAIL("Should never be reached, Iterators invalid"); + } + }; + + SECTION("Test different insert variants") + { + FixedOrderedMultimap::Iterator it = map.end(); + REQUIRE(map.insert(36, 37, &it) == static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(it->first == 36); + REQUIRE(it->second == 37); + REQUIRE(map.size() == 1); + REQUIRE(map.insert(37, 38, nullptr) == static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(map.find(37)->second == 38); + REQUIRE(map.size() == 2); + REQUIRE(map.insert(37, 24, nullptr) == static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(map.find(37)->second == 38); + REQUIRE(map.insert(0, 1, nullptr) == static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(map.find(0)->second == 1); + REQUIRE(map.size() == 4); + map.clear(); + REQUIRE(map.size() == 0); + } + SECTION("Test different erase and find with no entries"){ + FixedOrderedMultimap::Iterator it; + it = map.end(); + REQUIRE(map.erase(&it) == static_cast(FixedOrderedMultimap::KEY_DOES_NOT_EXIST)); + REQUIRE(map.find(1)== map.end()); + } +} + +TEST_CASE( "FixedOrderedMultimap Non Trivial Type", "[TestFixedOrderedMultimapNonTrivial]") { + INFO("FixedOrderedMultimap Non Trivial Type"); + + class TestClass{ + public: + TestClass(){}; + TestClass(uint32_t number1, uint64_t number2): + number1(number1),number2(number2){}; + ~TestClass(){}; + + bool operator==(const TestClass& lhs){ + return ((this->number1 == lhs.number1) and (this->number2 == lhs.number2)); + } + bool operator!=(const TestClass& lhs){ + return not(this->operator ==(lhs)); + } + + TestClass(const TestClass& other){ + this->number1 = other.number1; + this->number2 = other.number2; + }; + TestClass& operator=(const TestClass& other){ + this->number1 = other.number1; + this->number2 = other.number2; + return *this; + }; + + private: + uint32_t number1 = 0; + uint64_t number2 = 5; + }; + FixedOrderedMultimap map(30); + REQUIRE(map.size() == 0); + REQUIRE(map.maxSize() == 30); + + SECTION("Test insert, find, exists"){ + for (uint16_t i=0;i<30;i++){ + REQUIRE(map.insert(std::make_pair(i, TestClass(i+1,i)))== static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(map.exists(i) == static_cast(HasReturnvaluesIF::RETURN_OK)); + bool compare = map.find(i)->second == TestClass(i+1,i); + REQUIRE(compare); + } + REQUIRE(map.insert(0, TestClass()) == static_cast(FixedOrderedMultimap::MAP_FULL)); + REQUIRE(map.exists(31) == static_cast(FixedOrderedMultimap::KEY_DOES_NOT_EXIST)); + REQUIRE(map.size() == 30); + { + TestClass* ptr = nullptr; + REQUIRE(map.find(5,&ptr) == static_cast(HasReturnvaluesIF::RETURN_OK)); + bool compare = *ptr == TestClass(6, 5); + REQUIRE(compare); + REQUIRE(map.find(31,&ptr) == static_cast(FixedOrderedMultimap::KEY_DOES_NOT_EXIST)); + } + REQUIRE(map.erase(2) == static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(map.erase(31) == static_cast(FixedOrderedMultimap::KEY_DOES_NOT_EXIST)); + REQUIRE(map.exists(2) == static_cast(FixedOrderedMultimap::KEY_DOES_NOT_EXIST)); + REQUIRE(map.size() == 29); + + for (auto element: map){ + if (element.first == 5){ + bool compare = element.second == TestClass(6, 5); + REQUIRE(compare); + } + } + + for (FixedOrderedMultimap::Iterator it = map.begin(); it != map.end(); it++){ + bool compare = it->second == TestClass(it->first + 1, it->first); + REQUIRE(compare); + compare = (*it).second == TestClass((*it).first + 1, (*it).first); + REQUIRE(compare); + it->second = TestClass(it->first + 2, it->first); + compare = it->second == TestClass(it->first + 2, it->first); + REQUIRE(compare); + } + + { + FixedOrderedMultimap::Iterator it = map.begin(); + while(it != map.end()){ + REQUIRE(map.erase(&it) == static_cast(HasReturnvaluesIF::RETURN_OK)); + } + REQUIRE(map.size() == 0); + } + + for (FixedOrderedMultimap::Iterator it = map.begin(); it != map.end(); it++){ + // This line should never executed if begin and end is correct + FAIL("Should never be reached, Iterators invalid"); + } + }; + + SECTION("Test different insert variants") + { + FixedOrderedMultimap::Iterator it = map.end(); + REQUIRE(map.insert(36, TestClass(37, 36), &it) == static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(it->first == 36); + bool compare = it->second == TestClass(37, 36); + REQUIRE(compare); + REQUIRE(map.size() == 1); + REQUIRE(map.insert(37, TestClass(38, 37), nullptr) == static_cast(HasReturnvaluesIF::RETURN_OK)); + compare = map.find(37)->second == TestClass(38, 37); + REQUIRE(compare); + REQUIRE(map.size() == 2); + REQUIRE(map.insert(37, TestClass(24, 37), nullptr) == static_cast(HasReturnvaluesIF::RETURN_OK)); + compare = map.find(37)->second == TestClass(38, 37); + REQUIRE(compare); + REQUIRE(map.insert(0, TestClass(1, 0), nullptr) == static_cast(HasReturnvaluesIF::RETURN_OK)); + compare = map.find(0)->second == TestClass(1, 0); + REQUIRE(compare); + REQUIRE(map.size() == 4); + map.clear(); + REQUIRE(map.size() == 0); + } + SECTION("Test different erase and find with no entries"){ + FixedOrderedMultimap::Iterator it; + it = map.end(); + REQUIRE(map.erase(&it) == static_cast(FixedOrderedMultimap::KEY_DOES_NOT_EXIST)); + REQUIRE(map.find(1)== map.end()); + } +} diff --git a/unittest/tests/container/TestPlacementFactory.cpp b/unittest/tests/container/TestPlacementFactory.cpp new file mode 100644 index 00000000..5edbb9d2 --- /dev/null +++ b/unittest/tests/container/TestPlacementFactory.cpp @@ -0,0 +1,45 @@ +//#include +//#include +//#include +//#include +// +//#include +//#include "../../core/CatchDefinitions.h" +// +//TEST_CASE( "PlacementFactory Tests", "[TestPlacementFactory]") { +// INFO("PlacementFactory Tests"); +// +// const uint16_t element_sizes[3] = {sizeof(uint16_t), sizeof(uint32_t), sizeof(uint64_t)}; +// const uint16_t n_elements[3] = {1, 1, 1}; +// LocalPool<3> storagePool(0x1, element_sizes, n_elements, false, true); +// PlacementFactory factory(&storagePool); +// +// SECTION("Pool overload"){ +// store_address_t address; +// uint8_t* ptr = nullptr; +// REQUIRE(storagePool.getFreeElement(&address, sizeof(ArrayList), &ptr) +// == static_cast(StorageManagerIF::DATA_TOO_LARGE)); +// ArrayList* list2 = factory.generate >(80); +// REQUIRE(list2 == nullptr); +// } +// +// SECTION("Test generate and destroy"){ +// uint64_t* number = factory.generate(32000); +// REQUIRE(number != nullptr); +// REQUIRE(*number == 32000); +// store_address_t address; +// uint8_t* ptr = nullptr; +// REQUIRE(storagePool.getFreeElement(&address, sizeof(uint64_t), &ptr) +// == static_cast(StorageManagerIF::DATA_TOO_LARGE)); +// uint64_t* number2 = factory.generate(12345); +// REQUIRE(number2 == nullptr); +// REQUIRE(factory.destroy(number) == static_cast(HasReturnvaluesIF::RETURN_OK)); +// REQUIRE(storagePool.getFreeElement(&address, sizeof(uint64_t), &ptr) +// == static_cast(HasReturnvaluesIF::RETURN_OK)); +// REQUIRE(storagePool.deleteData(address) == static_cast(HasReturnvaluesIF::RETURN_OK)); +// +// //Check that PlacementFactory checks for nullptr +// ptr = nullptr; +// REQUIRE(factory.destroy(ptr) == static_cast(HasReturnvaluesIF::RETURN_FAILED)); +// } +//} diff --git a/unittest/tests/osal/TestMessageQueue.cpp b/unittest/tests/osal/TestMessageQueue.cpp new file mode 100644 index 00000000..8e59fa08 --- /dev/null +++ b/unittest/tests/osal/TestMessageQueue.cpp @@ -0,0 +1,40 @@ +#include +#include +#include "catch.hpp" +#include +#include "core/CatchDefinitions.h" + +TEST_CASE("MessageQueue Basic Test","[TestMq]") { + MessageQueueIF* testSenderMq = + QueueFactory::instance()->createMessageQueue(1); + MessageQueueId_t testSenderMqId = testSenderMq->getId(); + + MessageQueueIF* testReceiverMq = + QueueFactory::instance()->createMessageQueue(1); + MessageQueueId_t testReceiverMqId = testReceiverMq->getId(); + std::array testData { 0 }; + testData[0] = 42; + MessageQueueMessage testMessage(testData.data(), 1); + testSenderMq->setDefaultDestination(testReceiverMqId); + + SECTION("Simple Tests") { + auto result = testSenderMq->sendMessage(testReceiverMqId, &testMessage); + REQUIRE(result == retval::CATCH_OK); + MessageQueueMessage recvMessage; + result = testReceiverMq->receiveMessage(&recvMessage); + REQUIRE(result == retval::CATCH_OK); + CHECK(recvMessage.getData()[0] == 42); + + result = testSenderMq->sendMessage(testReceiverMqId, &testMessage); + REQUIRE(result == retval::CATCH_OK); + MessageQueueId_t senderId = 0; + result = testReceiverMq->receiveMessage(&recvMessage,&senderId); + REQUIRE(result == retval::CATCH_OK); + CHECK(recvMessage.getData()[0] == 42); + CHECK(senderId == testSenderMqId); + senderId = testReceiverMq->getLastPartner(); + CHECK(senderId == testSenderMqId); + } + + +} diff --git a/unittest/tests/osal/TestSemaphore.cpp b/unittest/tests/osal/TestSemaphore.cpp new file mode 100644 index 00000000..f7b25534 --- /dev/null +++ b/unittest/tests/osal/TestSemaphore.cpp @@ -0,0 +1,46 @@ + +#ifdef LINUX + +/* +#include "core/CatchDefinitions.h" +#include "catch.hpp" + +#include +#include + +TEST_CASE("Binary Semaphore Test" , "[BinSemaphore]") { + //perform set-up here + SemaphoreIF* binSemaph = SemaphoreFactory::instance()-> + createBinarySemaphore(); + REQUIRE(binSemaph != nullptr); + SECTION("Simple Test") { + // set-up is run for each section + REQUIRE(binSemaph->getSemaphoreCounter() == 1); + REQUIRE(binSemaph->release() == + static_cast(SemaphoreIF::SEMAPHORE_NOT_OWNED)); + REQUIRE(binSemaph->acquire(SemaphoreIF::POLLING) == + retval::CATCH_OK); + { + // not precise enough on linux.. should use clock instead.. + //Stopwatch stopwatch(false); + //REQUIRE(binSemaph->acquire(SemaphoreIF::TimeoutType::WAITING, 5) == + // SemaphoreIF::SEMAPHORE_TIMEOUT); + //dur_millis_t time = stopwatch.stop(); + //CHECK(time == 5); + } + REQUIRE(binSemaph->getSemaphoreCounter() == 0); + REQUIRE(binSemaph->release() == retval::CATCH_OK); + } + SemaphoreFactory::instance()->deleteSemaphore(binSemaph); + // perform tear-down here +} + + +TEST_CASE("Counting Semaphore Test" , "[CountingSemaph]") { + SECTION("Simple Test") { + + } +} +*/ + +#endif diff --git a/unittest/tests/serialize/TestSerialBufferAdapter.cpp b/unittest/tests/serialize/TestSerialBufferAdapter.cpp new file mode 100644 index 00000000..9919ed84 --- /dev/null +++ b/unittest/tests/serialize/TestSerialBufferAdapter.cpp @@ -0,0 +1,143 @@ +#include + +#include +#include "../../core/CatchDefinitions.h" + + +static bool test_value_bool = true; +static uint16_t tv_uint16 {283}; +static std::array testArray; + +TEST_CASE("Serial Buffer Adapter", "[single-file]") { + size_t serialized_size = 0; + test_value_bool = true; + uint8_t * arrayPtr = testArray.data(); + std::array test_serial_buffer {5, 4, 3, 2, 1}; + SerialBufferAdapter tv_serial_buffer_adapter = + SerialBufferAdapter(test_serial_buffer.data(), + test_serial_buffer.size(), false); + tv_uint16 = 16; + + SECTION("Serialize without size field") { + SerializeAdapter::serialize(&test_value_bool, &arrayPtr, + &serialized_size, testArray.size(), + SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tv_serial_buffer_adapter, &arrayPtr, + &serialized_size, testArray.size(), + SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tv_uint16, &arrayPtr, &serialized_size, + testArray.size(), SerializeIF::Endianness::MACHINE); + + REQUIRE(serialized_size == 8); + REQUIRE(testArray[0] == true); + REQUIRE(testArray[1] == 5); + REQUIRE(testArray[2] == 4); + REQUIRE(testArray[3] == 3); + REQUIRE(testArray[4] == 2); + REQUIRE(testArray[5] == 1); + memcpy(&tv_uint16, testArray.data() + 6, sizeof(tv_uint16)); + REQUIRE(tv_uint16 == 16); + } + + SECTION("Serialize with size field") { + SerialBufferAdapter tv_serial_buffer_adapter_loc = + SerialBufferAdapter(test_serial_buffer.data(), + test_serial_buffer.size(), true); + serialized_size = 0; + arrayPtr = testArray.data(); + SerializeAdapter::serialize(&test_value_bool, &arrayPtr,&serialized_size, + testArray.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tv_serial_buffer_adapter_loc, &arrayPtr, + &serialized_size, testArray.size(), + SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tv_uint16, &arrayPtr, &serialized_size, + testArray.size(), SerializeIF::Endianness::MACHINE); + + REQUIRE(serialized_size == 9); + REQUIRE(testArray[0] == true); + REQUIRE(testArray[1] == 5); + REQUIRE(testArray[2] == 5); + REQUIRE(testArray[3] == 4); + REQUIRE(testArray[4] == 3); + REQUIRE(testArray[5] == 2); + REQUIRE(testArray[6] == 1); + memcpy(&tv_uint16, testArray.data() + 7, sizeof(tv_uint16)); + REQUIRE(tv_uint16 == 16); + } + + SECTION("Test set buffer function") { + SerialBufferAdapter tv_serial_buffer_adapter_loc = + SerialBufferAdapter((uint8_t*)nullptr, + 0, true); + tv_serial_buffer_adapter_loc.setBuffer(test_serial_buffer.data(), + test_serial_buffer.size()); + serialized_size = 0; + arrayPtr = testArray.data(); + SerializeAdapter::serialize(&test_value_bool, &arrayPtr,&serialized_size, + testArray.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tv_serial_buffer_adapter_loc, &arrayPtr, + &serialized_size, testArray.size(), + SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tv_uint16, &arrayPtr, &serialized_size, + testArray.size(), SerializeIF::Endianness::MACHINE); + REQUIRE(serialized_size == 9); + REQUIRE(testArray[0] == true); + REQUIRE(testArray[1] == 5); + REQUIRE(testArray[2] == 5); + REQUIRE(testArray[3] == 4); + REQUIRE(testArray[4] == 3); + REQUIRE(testArray[5] == 2); + REQUIRE(testArray[6] == 1); + memcpy(&tv_uint16, testArray.data() + 7, sizeof(tv_uint16)); + REQUIRE(tv_uint16 == 16); + } + + SECTION("Deserialization with size field") { + size_t buffer_size = 4; + memcpy(testArray.data(), &buffer_size, sizeof(uint16_t)); + testArray[2] = 1; + testArray[3] = 1; + testArray[4] = 1; + testArray[5] = 0; + std::array test_recv_array; + arrayPtr = testArray.data(); + // copy testArray[1] to testArray[4] into receive buffer, skip + // size field (testArray[0]) for deSerialization. + SerialBufferAdapter tv_serial_buffer_adapter3 = + SerialBufferAdapter(test_recv_array.data(), 4, true); + // Deserialization + size_t size = 6; + auto result = tv_serial_buffer_adapter3.deSerialize( + const_cast(&arrayPtr), &size, + SerializeIF::Endianness::MACHINE); + REQUIRE(result == retval::CATCH_OK); + CHECK(test_recv_array[0] == 1); + CHECK(test_recv_array[1] == 1); + CHECK(test_recv_array[2] == 1); + CHECK(test_recv_array[3] == 0); + } + + SECTION("Deserialization without size field") { + size_t buffer_size = 4; + memcpy(testArray.data(), &buffer_size, sizeof(uint16_t)); + testArray[2] = 1; + testArray[3] = 1; + testArray[4] = 1; + testArray[5] = 0; + std::array test_recv_array; + arrayPtr = testArray.data() + 2; + // copy testArray[1] to testArray[4] into receive buffer, skip + // size field (testArray[0]) + SerialBufferAdapter tv_serial_buffer_adapter3 = + SerialBufferAdapter(test_recv_array.data(), 4, false); + // Deserialization + size_t size = 4; + tv_serial_buffer_adapter3.deSerialize( + const_cast(&arrayPtr), &size, + SerializeIF::Endianness::MACHINE); + CHECK(test_recv_array[0] == 1); + CHECK(test_recv_array[1] == 1); + CHECK(test_recv_array[2] == 1); + CHECK(test_recv_array[3] == 0); + } +} diff --git a/unittest/tests/serialize/TestSerialLinkedPacket.cpp b/unittest/tests/serialize/TestSerialLinkedPacket.cpp new file mode 100644 index 00000000..0a09e430 --- /dev/null +++ b/unittest/tests/serialize/TestSerialLinkedPacket.cpp @@ -0,0 +1,73 @@ +#include + +#include +#include "../../core/CatchDefinitions.h" +#include "TestSerialLinkedPacket.h" + + +TEST_CASE("Serial Linked Packet" , "[SerLinkPacket]") { + // perform set-up here + uint32_t header = 42; + std::array testArray {1,2,3}; + uint32_t tail = 96; + size_t packetMaxSize = 256; + uint8_t packet [packetMaxSize] = {}; + size_t packetLen = 0; + + SECTION("Test Deserialization with Serial Buffer Adapter.") { + // This is a serialization of a packet, made "manually". + // We generate a packet which store data big-endian by swapping some + // values. (like coming from ground). + header = EndianConverter::convertBigEndian(header); + std::memcpy(packet, &header, sizeof(header)); + packetLen += sizeof(header); + + std::copy(testArray.data(), testArray.data() + testArray.size(), + packet + packetLen); + packetLen += testArray.size(); + + tail = EndianConverter::convertBigEndian(tail); + std::memcpy(packet + packetLen, &tail, sizeof(tail)); + packetLen += sizeof(tail); + + //arrayprinter::print(packet, packetLen, OutputType::DEC); + + // This is the buffer which will be filled when testClass.deSerialize + // is called. + std::array bufferAdaptee = {}; + TestPacket testClass(packet, packetLen, bufferAdaptee.data(), + bufferAdaptee.size()); + const uint8_t* readOnlyPointer = packet; + // Deserialize big endian packet by setting bigEndian to true. + ReturnValue_t result = testClass.deSerialize(&readOnlyPointer, + &packetLen, SerializeIF::Endianness::BIG); + REQUIRE(result == retval::CATCH_OK); + CHECK(testClass.getHeader() == 42); + // Equivalent check. + // CHECK(testClass.getBuffer()[0] == 1); + CHECK(bufferAdaptee[0] == 1); + CHECK(bufferAdaptee[1] == 2); + CHECK(bufferAdaptee[2] == 3); + CHECK(testClass.getTail() == 96); + } + + SECTION("Test Serialization") { + // Same process as performed in setup, this time using the class + // instead of doing it manually. + TestPacket testClass(header, tail, testArray.data(), testArray.size()); + size_t serializedSize = 0; + uint8_t* packetPointer = packet; + // serialize for ground: bigEndian = true. + ReturnValue_t result = testClass.serialize(&packetPointer, + &serializedSize, packetMaxSize, SerializeIF::Endianness::BIG); + REQUIRE(result == retval::CATCH_OK); + // Result should be big endian now. + CHECK(packet[3] == 42); + CHECK(packet[4] == 1); + CHECK(packet[5] == 2); + CHECK(packet[6] == 3); + CHECK(packet[10] == 96); + } + + // perform tear-down here +} diff --git a/unittest/tests/serialize/TestSerialLinkedPacket.h b/unittest/tests/serialize/TestSerialLinkedPacket.h new file mode 100644 index 00000000..6c720577 --- /dev/null +++ b/unittest/tests/serialize/TestSerialLinkedPacket.h @@ -0,0 +1,61 @@ +#ifndef UNITTEST_HOSTED_TESTSERIALLINKEDPACKET_H_ +#define UNITTEST_HOSTED_TESTSERIALLINKEDPACKET_H_ + +#include +#include +#include +#include +#include + +class TestPacket: public SerialLinkedListAdapter { +public: + /** + * For Deserialization + */ + TestPacket(const uint8_t *somePacket, size_t size, uint8_t * storePointer, + size_t storeSize): + buffer(storePointer, storeSize) + { + setLinks(); + } + + /** + * For Serialization + */ + TestPacket(uint32_t header, uint32_t tail, + const uint8_t* parameters, size_t paramSize): + header(header), buffer(parameters, paramSize), + tail(tail) { + setLinks(); + } + + uint32_t getHeader() const { + return header.entry; + } + + const uint8_t * getBuffer() { + return buffer.entry.getConstBuffer(); + } + + const size_t getBufferLength() { + return buffer.getSerializedSize(); + } + + + uint16_t getTail() const { + return tail.entry; + } +private: + void setLinks() { + setStart(&header); + header.setNext(&buffer); + buffer.setNext(&tail); + tail.setEnd(); + } + + SerializeElement header = 0; + SerializeElement> buffer; + SerializeElement tail = 0; +}; + +#endif /* UNITTEST_TESTFW_NEWTESTS_TESTTEMPLATE_H_ */ diff --git a/unittest/tests/serialize/TestSerialization.cpp b/unittest/tests/serialize/TestSerialization.cpp new file mode 100644 index 00000000..4c9ba181 --- /dev/null +++ b/unittest/tests/serialize/TestSerialization.cpp @@ -0,0 +1,129 @@ +#include + +#include "catch.hpp" +#include +#include "../../core/CatchDefinitions.h" + +static bool test_value_bool = true; +static uint8_t tv_uint8 {5}; +static uint16_t tv_uint16 {283}; +static uint32_t tv_uint32 {929221}; +static uint64_t tv_uint64 {2929329429}; + +static int8_t tv_int8 {-16}; +static int16_t tv_int16 {-829}; +static int32_t tv_int32 {-2312}; + +static float tv_float {8.2149214}; +static float tv_sfloat = {-922.2321321}; +static double tv_double {9.2132142141e8}; +static double tv_sdouble {-2.2421e19}; + +static std::array test_array; + +TEST_CASE( "Serialization size tests", "[TestSerialization]") { + //REQUIRE(unitTestClass.test_autoserialization() == 0); + REQUIRE(SerializeAdapter::getSerializedSize(&test_value_bool) == + sizeof(test_value_bool)); + REQUIRE(SerializeAdapter::getSerializedSize(&tv_uint8) == + sizeof(tv_uint8)); + REQUIRE(SerializeAdapter::getSerializedSize(&tv_uint16) == + sizeof(tv_uint16)); + REQUIRE(SerializeAdapter::getSerializedSize(&tv_uint32 ) == + sizeof(tv_uint32)); + REQUIRE(SerializeAdapter::getSerializedSize(&tv_uint64) == + sizeof(tv_uint64)); + REQUIRE(SerializeAdapter::getSerializedSize(&tv_int8) == + sizeof(tv_int8)); + REQUIRE(SerializeAdapter::getSerializedSize(&tv_int16) == + sizeof(tv_int16)); + REQUIRE(SerializeAdapter::getSerializedSize(&tv_int32) == + sizeof(tv_int32)); + REQUIRE(SerializeAdapter::getSerializedSize(&tv_float) == + sizeof(tv_float)); + REQUIRE(SerializeAdapter::getSerializedSize(&tv_sfloat) == + sizeof(tv_sfloat )); + REQUIRE(SerializeAdapter::getSerializedSize(&tv_double) == + sizeof(tv_double)); + REQUIRE(SerializeAdapter::getSerializedSize(&tv_sdouble) == + sizeof(tv_sdouble)); +} + + +TEST_CASE("Auto Serialize Adapter testing", "[single-file]") { + size_t serialized_size = 0; + uint8_t * p_array = test_array.data(); + + SECTION("Serializing...") { + SerializeAdapter::serialize(&test_value_bool, &p_array, + &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tv_uint8, &p_array, + &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tv_uint16, &p_array, + &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tv_uint32, &p_array, + &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tv_int8, &p_array, + &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tv_int16, &p_array, + &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tv_int32, &p_array, + &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tv_uint64, &p_array, + &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tv_float, &p_array, + &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tv_double, &p_array, + &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tv_sfloat, &p_array, + &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tv_sdouble, &p_array, + &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); + REQUIRE (serialized_size == 47); + } + + SECTION("Deserializing") { + p_array = test_array.data(); + size_t remaining_size = serialized_size; + SerializeAdapter::deSerialize(&test_value_bool, + const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tv_uint8, + const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tv_uint16, + const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tv_uint32, + const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tv_int8, + const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tv_int16, + const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tv_int32, + const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tv_uint64, + const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tv_float, + const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tv_double, + const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tv_sfloat, + const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tv_sdouble, + const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); + + REQUIRE(test_value_bool == true); + REQUIRE(tv_uint8 == 5); + REQUIRE(tv_uint16 == 283); + REQUIRE(tv_uint32 == 929221); + REQUIRE(tv_uint64 == 2929329429); + REQUIRE(tv_int8 == -16); + REQUIRE(tv_int16 == -829); + REQUIRE(tv_int32 == -2312); + + REQUIRE(tv_float == Approx(8.214921)); + REQUIRE(tv_double == Approx(9.2132142141e8)); + REQUIRE(tv_sfloat == Approx(-922.2321321)); + REQUIRE(tv_sdouble == Approx(-2.2421e19)); + } +} + + diff --git a/unittest/tests/storagemanager/TestNewAccessor.cpp b/unittest/tests/storagemanager/TestNewAccessor.cpp new file mode 100644 index 00000000..7bd0dee2 --- /dev/null +++ b/unittest/tests/storagemanager/TestNewAccessor.cpp @@ -0,0 +1,161 @@ +//#include +//#include +//#include "../../core/CatchDefinitions.h" +//#include +// +//TEST_CASE( "New Accessor" , "[NewAccessor]") { +// uint16_t numberOfElements[1] = {1}; +// uint16_t sizeofElements[1] = {10}; +// LocalPool<1> SimplePool = LocalPool<1>(0, sizeofElements, numberOfElements); +// std::array testDataArray; +// std::array receptionArray; +// store_address_t testStoreId; +// ReturnValue_t result = retval::CATCH_FAILED; +// +// for(size_t i = 0; i < testDataArray.size(); i++) { +// testDataArray[i] = i; +// } +// size_t size = 10; +// +// SECTION ("Simple tests getter functions") { +// result = SimplePool.addData(&testStoreId, testDataArray.data(), size); +// REQUIRE(result == retval::CATCH_OK); +// auto resultPair = SimplePool.getData(testStoreId); +// REQUIRE(resultPair.first == retval::CATCH_OK); +// resultPair.second.getDataCopy(receptionArray.data(), 20); +// CHECK(resultPair.second.getId() == testStoreId); +// CHECK(resultPair.second.size() == 10); +// for(size_t i = 0; i < size; i++) { +// CHECK(receptionArray[i] == i ); +// } +// +// std::copy(resultPair.second.data(), resultPair.second.data() + +// resultPair.second.size(), receptionArray.data()); +// for(size_t i = 0; i < size; i++) { +// CHECK(receptionArray[i] == i ); +// } +// +// { +// auto resultPairLoc = SimplePool.getData(testStoreId); +// REQUIRE(resultPairLoc.first == retval::CATCH_OK); +// // data should be deleted when accessor goes out of scope. +// } +// resultPair = SimplePool.getData(testStoreId); +// REQUIRE(resultPair.first == (int) StorageManagerIF::DATA_DOES_NOT_EXIST); +// +// result = SimplePool.addData(&testStoreId, testDataArray.data(), size); +// REQUIRE(result == retval::CATCH_OK); +// { +// ConstStorageAccessor constAccessor(testStoreId); +// result = SimplePool.getData(testStoreId, constAccessor); +// REQUIRE(result == retval::CATCH_OK); +// constAccessor.getDataCopy(receptionArray.data(), 20); +// for(size_t i = 0; i < size; i++) { +// CHECK(receptionArray[i] == i ); +// } +// // likewise, data should be deleted when accessor gets out of scope. +// } +// resultPair = SimplePool.getData(testStoreId); +// REQUIRE(resultPair.first == (int) StorageManagerIF::DATA_DOES_NOT_EXIST); +// +// result = SimplePool.addData(&testStoreId, testDataArray.data(), size); +// { +// resultPair = SimplePool.getData(testStoreId); +// REQUIRE(resultPair.first == retval::CATCH_OK); +// resultPair.second.release(); +// // now data should not be deleted anymore +// } +// resultPair = SimplePool.getData(testStoreId); +// REQUIRE(resultPair.first == retval::CATCH_OK); +// resultPair.second.getDataCopy(receptionArray.data(), 20); +// for(size_t i = 0; i < size; i++) { +// CHECK(receptionArray[i] == i ); +// } +// } +// +// +// SECTION("Simple tests modify functions") { +// result = SimplePool.addData(&testStoreId, testDataArray.data(), size); +// REQUIRE(result == retval::CATCH_OK); +// { +// StorageAccessor accessor(testStoreId); +// result = SimplePool.modifyData(testStoreId, accessor); +// REQUIRE(result == retval::CATCH_OK); +// CHECK(accessor.getId() == testStoreId); +// CHECK(accessor.size() == 10); +// accessor.getDataCopy(receptionArray.data(), 20); +// for(size_t i = 0; i < size; i++) { +// CHECK(receptionArray[i] == i ); +// } +// std::copy(accessor.data(), accessor.data() + +// accessor.size(), receptionArray.data()); +// for(size_t i = 0; i < size; i++) { +// CHECK(receptionArray[i] == i ); +// } +// // data should be deleted when accessor goes out of scope +// } +// auto resultPair = SimplePool.getData(testStoreId); +// REQUIRE(resultPair.first == (int) StorageManagerIF::DATA_DOES_NOT_EXIST); +// +// result = SimplePool.addData(&testStoreId, testDataArray.data(), size); +// REQUIRE(result == retval::CATCH_OK); +// { +// auto resultPairLoc = SimplePool.modifyData(testStoreId); +// REQUIRE(resultPairLoc.first == retval::CATCH_OK); +// CHECK(resultPairLoc.second.getId() == testStoreId); +// CHECK(resultPairLoc.second.size() == 10); +// resultPairLoc.second.getDataCopy(receptionArray.data(), 20); +// for(size_t i = 0; i < size; i++) { +// CHECK(receptionArray[i] == i ); +// } +// std::copy(resultPairLoc.second.data(), resultPairLoc.second.data() + +// resultPairLoc.second.size(), receptionArray.data()); +// for(size_t i = 0; i < size; i++) { +// CHECK(receptionArray[i] == i ); +// } +// resultPairLoc.second.release(); +// // data should not be deleted when accessor goes out of scope +// } +// resultPair = SimplePool.getData(testStoreId); +// REQUIRE(resultPair.first == retval::CATCH_OK); +// } +// +// +// SECTION("Write tests") { +// result = SimplePool.addData(&testStoreId, testDataArray.data(), size); +// REQUIRE(result == retval::CATCH_OK); +// { +// auto resultPair = SimplePool.modifyData(testStoreId); +// REQUIRE(resultPair.first == retval::CATCH_OK); +// testDataArray[9] = 42; +// resultPair.second.write(testDataArray.data(), 10, 0); +// // now data should not be deleted +// resultPair.second.release(); +// } +// auto resultConstPair = SimplePool.getData(testStoreId); +// REQUIRE(resultConstPair.first == retval::CATCH_OK); +// +// resultConstPair.second.getDataCopy(receptionArray.data(), 10); +// for(size_t i = 0; i < size-1; i++) { +// CHECK(receptionArray[i] == i ); +// } +// CHECK(receptionArray[9] == 42 ); +// +// auto resultPair = SimplePool.modifyData(testStoreId); +// REQUIRE(resultPair.first == retval::CATCH_OK); +// result = resultPair.second.write(testDataArray.data(), 20, 0); +// REQUIRE(result == retval::CATCH_FAILED); +// result = resultPair.second.write(testDataArray.data(), 10, 5); +// REQUIRE(result == retval::CATCH_FAILED); +// +// memset(testDataArray.data(), 42, 5); +// result = resultPair.second.write(testDataArray.data(), 5, 5); +// REQUIRE(result == retval::CATCH_OK); +// resultConstPair = SimplePool.getData(testStoreId); +// resultPair.second.getDataCopy(receptionArray.data(), 20); +// for(size_t i = 5; i < 10; i++) { +// CHECK(receptionArray[i] == 42 ); +// } +// +// } +//} diff --git a/unittest/tests/storagemanager/TestPool.cpp b/unittest/tests/storagemanager/TestPool.cpp new file mode 100644 index 00000000..f278c40c --- /dev/null +++ b/unittest/tests/storagemanager/TestPool.cpp @@ -0,0 +1,296 @@ +//#include "CatchDefinitions.h" +// +//#include +//#include +//#include +// +//#include +//#include +// +//#include +// +// +//TEST_CASE( "Local Pool Simple Tests [1 Pool]" , "[TestPool]") { +//// uint16_t numberOfElements[1] = {1}; +//// uint16_t sizeofElements[1] = {10}; +// LocalPool::LocalPoolConfig config = {{1, 10}}; +// LocalPool simplePool(0, config); +// std::array testDataArray; +// std::array receptionArray; +// store_address_t testStoreId; +// ReturnValue_t result = retval::CATCH_FAILED; +// uint8_t *pointer = nullptr; +// const uint8_t * constPointer = nullptr; +// +// for(size_t i = 0; i < testDataArray.size(); i++) { +// testDataArray[i] = i; +// } +// size_t size = 10; +// +// SECTION ( "Basic tests") { +// result = simplePool.addData(&testStoreId, testDataArray.data(), size); +// REQUIRE(result == retval::CATCH_OK); +// result = simplePool.getData(testStoreId, &constPointer, &size); +// REQUIRE(result == retval::CATCH_OK); +// memcpy(receptionArray.data(), constPointer, size); +// for(size_t i = 0; i < size; i++) { +// CHECK(receptionArray[i] == i ); +// } +// memset(receptionArray.data(), 0, size); +// result = simplePool.modifyData(testStoreId, &pointer, &size); +// memcpy(receptionArray.data(), pointer, size); +// REQUIRE(result == retval::CATCH_OK); +// for(size_t i = 0; i < size; i++) { +// CHECK(receptionArray[i] == i ); +// } +// result = simplePool.deleteData(testStoreId); +// REQUIRE(result == retval::CATCH_OK); +// result = simplePool.addData(&testStoreId, testDataArray.data(), 15); +// CHECK (result == (int) StorageManagerIF::DATA_TOO_LARGE); +// } +// +// SECTION ( "Reservation Tests ") { +// pointer = nullptr; +// result = simplePool.getFreeElement(&testStoreId, size, &pointer); +// REQUIRE (result == retval::CATCH_OK); +// memcpy(pointer, testDataArray.data(), size); +// constPointer = nullptr; +// result = simplePool.getData(testStoreId, &constPointer, &size); +// +// REQUIRE (result == retval::CATCH_OK); +// memcpy(receptionArray.data(), constPointer, size); +// for(size_t i = 0; i < size; i++) { +// CHECK(receptionArray[i] == i ); +// } +// } +// +// SECTION ( "Add, delete, add, add when full") { +// result = simplePool.addData(&testStoreId, testDataArray.data(), size); +// REQUIRE(result == retval::CATCH_OK); +// result = simplePool.getData(testStoreId, &constPointer, &size); +// REQUIRE( result == retval::CATCH_OK); +// memcpy(receptionArray.data(), constPointer, size); +// for(size_t i = 0; i < size; i++) { +// CHECK(receptionArray[i] == i ); +// } +// +// result = simplePool.deleteData(testStoreId); +// REQUIRE(result == retval::CATCH_OK); +// +// result = simplePool.addData(&testStoreId, testDataArray.data(), size); +// REQUIRE(result == retval::CATCH_OK); +// result = simplePool.getData(testStoreId, &constPointer, &size); +// REQUIRE( result == retval::CATCH_OK); +// memcpy(receptionArray.data(), constPointer, size); +// for(size_t i = 0; i < size; i++) { +// CHECK(receptionArray[i] == i ); +// } +// +// store_address_t newAddress; +// result = simplePool.addData(&newAddress, testDataArray.data(), size); +// REQUIRE(result == (int) StorageManagerIF::DATA_STORAGE_FULL); +// +// // Packet Index to high intentionally +// newAddress.packetIndex = 2; +// pointer = testDataArray.data(); +// result = simplePool.modifyData(newAddress, &pointer, &size); +// REQUIRE(result == (int) StorageManagerIF::ILLEGAL_STORAGE_ID); +// +// result = simplePool.deleteData(newAddress); +// REQUIRE(result == (int) StorageManagerIF::ILLEGAL_STORAGE_ID); +// +// newAddress.packetIndex = 0; +// newAddress.poolIndex = 2; +// result = simplePool.deleteData(newAddress); +// REQUIRE(result == (int) StorageManagerIF::ILLEGAL_STORAGE_ID); +// } +// +// SECTION ( "Initialize and clear store, delete with pointer") { +// result = simplePool.initialize(); +// REQUIRE(result == retval::CATCH_OK); +// result = simplePool.addData(&testStoreId, testDataArray.data(), size); +// REQUIRE(result == retval::CATCH_OK); +// simplePool.clearStore(); +// result = simplePool.addData(&testStoreId, testDataArray.data(), size); +// REQUIRE(result == retval::CATCH_OK); +// result = simplePool.modifyData(testStoreId, &pointer, &size); +// REQUIRE(result == retval::CATCH_OK); +// store_address_t newId; +// result = simplePool.deleteData(pointer, size, &testStoreId); +// REQUIRE(result == retval::CATCH_OK); +// REQUIRE(testStoreId.raw != (uint32_t) StorageManagerIF::INVALID_ADDRESS); +// result = simplePool.addData(&testStoreId, testDataArray.data(), size); +// REQUIRE(result == retval::CATCH_OK); +// } +//} +// +//int runIdx = 0; +// +//TEST_CASE( "Local Pool Extended Tests [3 Pools]" , "[TestPool2]") { +// LocalPool::LocalPoolConfig* config; +// if(runIdx == 0) { +// config = new LocalPool::LocalPoolConfig{{10, 5}, {5, 10}, {2, 20}}; +// } +// else { +// // shufle the order, they should be sort implictely so that the +// // order is ascending for the page sizes. +// config = new LocalPool::LocalPoolConfig{{5, 10}, {2, 20}, {10, 5}}; +// size_t lastSize = 0; +// for(const auto& pair: *config) { +// CHECK(pair.second > lastSize); +// lastSize = pair.second; +// } +// } +// runIdx++; +// +// LocalPool simplePool(0, *config); +// std::array testDataArray; +// std::array receptionArray; +// store_address_t testStoreId; +// ReturnValue_t result = retval::CATCH_FAILED; +// for(size_t i = 0; i < testDataArray.size(); i++) { +// testDataArray[i] = i; +// } +// size_t size = 0; +// +// SECTION ("Basic tests") { +// size = 8; +// result = simplePool.addData(&testStoreId, testDataArray.data(), size); +// REQUIRE(result == retval::CATCH_OK); +// // Should be on second page of the pool now for 8 bytes +// CHECK(testStoreId.poolIndex == 1); +// CHECK(testStoreId.packetIndex == 0); +// +// size = 15; +// result = simplePool.addData(&testStoreId, testDataArray.data(), size); +// REQUIRE(result == retval::CATCH_OK); +// // Should be on third page of the pool now for 15 bytes +// CHECK(testStoreId.poolIndex == 2); +// CHECK(testStoreId.packetIndex == 0); +// +// result = simplePool.addData(&testStoreId, testDataArray.data(), size); +// REQUIRE(result == retval::CATCH_OK); +// // Should be on third page of the pool now for 15 bytes +// CHECK(testStoreId.poolIndex == 2); +// CHECK(testStoreId.packetIndex == 1); +// +// result = simplePool.addData(&testStoreId, testDataArray.data(), size); +// // Should be on third page of the pool now for 15 bytes +// REQUIRE(result == (int) LocalPool::DATA_STORAGE_FULL); +// +// size = 8; +// result = simplePool.addData(&testStoreId, testDataArray.data(), size); +// REQUIRE(result == retval::CATCH_OK); +// // Should still work +// CHECK(testStoreId.poolIndex == 1); +// CHECK(testStoreId.packetIndex == 1); +// +// // fill the rest of the pool +// for(uint8_t idx = 2; idx < 5; idx++) { +// result = simplePool.addData(&testStoreId, testDataArray.data(), size); +// REQUIRE(result == retval::CATCH_OK); +// CHECK(testStoreId.poolIndex == 1); +// CHECK(testStoreId.packetIndex == idx); +// } +// } +// +// SECTION ("Fill Count and Clearing") { +// //SECTION("Basic tests"); +// uint8_t bytesWritten = 0; +// simplePool.getFillCount(receptionArray.data(), &bytesWritten); +// // fill count should be all zeros now. +// CHECK(bytesWritten == 4); +// CHECK(receptionArray[0] == 0); +// CHECK(receptionArray[1] == 0); +// CHECK(receptionArray[2] == 0); +// CHECK(receptionArray[3] == 0); +// +// // now fill the store completely. +// size = 5; +// for(uint8_t idx = 0; idx < 10; idx++) { +// result = simplePool.addData(&testStoreId, testDataArray.data(), size); +// REQUIRE(result == retval::CATCH_OK); +// CHECK(testStoreId.poolIndex == 0); +// CHECK(testStoreId.packetIndex == idx); +// } +// size = 10; +// for(uint8_t idx = 0; idx < 5; idx++) { +// result = simplePool.addData(&testStoreId, testDataArray.data(), size); +// REQUIRE(result == retval::CATCH_OK); +// CHECK(testStoreId.poolIndex == 1); +// CHECK(testStoreId.packetIndex == idx); +// } +// size = 20; +// for(uint8_t idx = 0; idx < 2; idx++) { +// result = simplePool.addData(&testStoreId, testDataArray.data(), size); +// REQUIRE(result == retval::CATCH_OK); +// CHECK(testStoreId.poolIndex == 2); +// CHECK(testStoreId.packetIndex == idx); +// } +// bytesWritten = 0; +// simplePool.getFillCount(receptionArray.data(), &bytesWritten); +// // fill count should be all 100 now. +// CHECK(bytesWritten == 4); +// CHECK(receptionArray[0] == 100); +// CHECK(receptionArray[1] == 100); +// CHECK(receptionArray[2] == 100); +// CHECK(receptionArray[3] == 100); +// +// // now clear the store +// simplePool.clearStore(); +// bytesWritten = 0; +// simplePool.getFillCount(receptionArray.data(), &bytesWritten); +// CHECK(bytesWritten == 4); +// CHECK(receptionArray[0] == 0); +// CHECK(receptionArray[1] == 0); +// CHECK(receptionArray[2] == 0); +// CHECK(receptionArray[3] == 0); +// +// // now fill one page +// size = 5; +// for(uint8_t idx = 0; idx < 10; idx++) { +// result = simplePool.addData(&testStoreId, testDataArray.data(), size); +// REQUIRE(result == retval::CATCH_OK); +// CHECK(testStoreId.poolIndex == 0); +// CHECK(testStoreId.packetIndex == idx); +// } +// bytesWritten = 0; +// simplePool.getFillCount(receptionArray.data(), &bytesWritten); +// // First page full, median fill count is 33 % +// CHECK(bytesWritten == 4); +// CHECK(receptionArray[0] == 100); +// CHECK(receptionArray[1] == 0); +// CHECK(receptionArray[2] == 0); +// CHECK(receptionArray[3] == 33); +// +// // now fill second page +// size = 10; +// for(uint8_t idx = 0; idx < 5; idx++) { +// result = simplePool.addData(&testStoreId, testDataArray.data(), size); +// REQUIRE(result == retval::CATCH_OK); +// CHECK(testStoreId.poolIndex == 1); +// CHECK(testStoreId.packetIndex == idx); +// } +// bytesWritten = 0; +// simplePool.getFillCount(receptionArray.data(), &bytesWritten); +// // First and second page full, median fill count is 66 % +// CHECK(bytesWritten == 4); +// CHECK(receptionArray[0] == 100); +// CHECK(receptionArray[1] == 100); +// CHECK(receptionArray[2] == 0); +// CHECK(receptionArray[3] == 66); +// +// // now clear first page +// simplePool.clearPage(0); +// bytesWritten = 0; +// simplePool.getFillCount(receptionArray.data(), &bytesWritten); +// // Second page full, median fill count is 33 % +// CHECK(bytesWritten == 4); +// CHECK(receptionArray[0] == 0); +// CHECK(receptionArray[1] == 100); +// CHECK(receptionArray[2] == 0); +// CHECK(receptionArray[3] == 33); +// } +// +// delete(config); +//} diff --git a/unittest/tests/tests.mk b/unittest/tests/tests.mk new file mode 100644 index 00000000..47e634a2 --- /dev/null +++ b/unittest/tests/tests.mk @@ -0,0 +1,8 @@ +CXXSRC += $(wildcard $(CURRENTPATH)/container/*.cpp) +CXXSRC += $(wildcard $(CURRENTPATH)/action/*.cpp) +CXXSRC += $(wildcard $(CURRENTPATH)/serialize/*.cpp) +CXXSRC += $(wildcard $(CURRENTPATH)/storagemanager/*.cpp) + +# OSAL not included for now. + +INCLUDES += $(CURRENTPATH) \ No newline at end of file diff --git a/unittest/testtemplate/TestTemplate.cpp b/unittest/testtemplate/TestTemplate.cpp new file mode 100644 index 00000000..6b5fc3d2 --- /dev/null +++ b/unittest/testtemplate/TestTemplate.cpp @@ -0,0 +1,31 @@ +#include +#include + + +/** + * @brief Template test file + * @details + * In each test case, the code outside the sections is executed + * for EACH section. + * The most common macros to perform tests are: + * - CHECK(...): assert expression and continues even if it fails + * - REQUIRE(...): test case fails if assertion fails + * + * Tests are generally sturctured in test cases and sections, see example + * below. + * + * More Documentation: + * - https://github.com/catchorg/Catch2 + * - https://github.com/catchorg/Catch2/blob/master/docs/assertions.md + * - https://github.com/catchorg/Catch2/blob/master/docs/test-cases-and-sections.md + */ +TEST_CASE("Dummy Test" , "[DummyTest]") { + uint8_t testVariable = 1; + //perform set-up here + CHECK(testVariable == 1); + SECTION("TestSection") { + // set-up is run for each section + REQUIRE(testVariable == 1); + } + // perform tear-down here +} diff --git a/unittest/unlockRealtime.sh b/unittest/unlockRealtime.sh new file mode 100644 index 00000000..b28d5490 --- /dev/null +++ b/unittest/unlockRealtime.sh @@ -0,0 +1,34 @@ +#!/bin/bash +# Run this script to unlock all permissions to run the linux binaries +# and create threads + +binaries=$(find $directory -type f -name "*.elf") + +echo Unlocking real time permissions for binaries and bash console... + +# Set up the soft realtime limit to maximum (99) +# Please note that the hard limit needs to be set to 99 too +# for this to work (check with ulimit -Hr). +# If that has not been done yet, add +# hard rtprio 99 +# to /etc/security/limits.conf +# It is also necessary and recommended to add +# soft rtprio 99 +# as well. This can also be done in the command line +# but would need to be done for each session. +ulimit -Sr 99 + +for binary in ${binaries}; do + sudo setcap 'cap_sys_nice=eip' ${binary} + result=$? + if [ ${result} = 0 ];then + echo ${binary} was unlocked + fi +done + +# sudo setcap 'cap_sys_nice=eip' /bin/bash +# result=$? +# if [ ${result} = 0 ];then +# echo /bin/bash was unlocked +# fi +