diff --git a/.run/fsfw-tests_coverage.run.xml b/.run/fsfw-tests_coverage.run.xml deleted file mode 100644 index 49d9b135..00000000 --- a/.run/fsfw-tests_coverage.run.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.run/fsfw.run.xml b/.run/fsfw.run.xml deleted file mode 100644 index 72f74939..00000000 --- a/.run/fsfw.run.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ba6d754..394f1e45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,12 +19,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Bump C++ required version to C++17. Every project which uses the FSFW and every modern compiler supports it PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/622 -- HAL Linux SPI: Set the Clock Default State when setting new SPI speed - and mode - PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/573 -- GPIO HAL: `Direction`, `GpioOperation` and `Levels` are enum classes now, which prevents - name clashes with Windows defines. - PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/572 - New CMake option `FSFW_HAL_LINUX_ADD_LIBGPIOD` to specifically exclude `gpiod` code. PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/572 - HAL Devicehandlers: Periodic printout is run-time configurable now @@ -120,6 +114,8 @@ https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/593 ## Additions +- New constructor for PoolEntry which allows to simply specify the length of the pool entry. + This is also the new default constructor for scalar value with 0 as an initial value - Added options for CI/CD builds: `FSFW_CICD_BUILD`. This allows the source code to know whether it is running in CI/CD PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/623 diff --git a/CMakeLists.txt b/CMakeLists.txt index d8163f3e..e9e3e471 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,6 +67,7 @@ endif() set(FSFW_SOURCES_DIR "${CMAKE_SOURCE_DIR}/src/fsfw") set(FSFW_ETL_LIB_NAME etl) +set(FSFW_ETL_LINK_TARGET etl::etl) set(FSFW_ETL_LIB_MAJOR_VERSION 20 CACHE STRING "ETL library major version requirement") @@ -447,8 +448,8 @@ target_include_directories( target_compile_options(${LIB_FSFW_NAME} PRIVATE ${FSFW_WARNING_FLAGS} ${COMPILER_FLAGS}) -target_link_libraries(${LIB_FSFW_NAME} PRIVATE ${FSFW_ETL_LINK_TARGET} - ${FSFW_ADDITIONAL_LINK_LIBS}) +target_link_libraries(${LIB_FSFW_NAME} PRIVATE ${FSFW_ADDITIONAL_LINK_LIBS}) +target_link_libraries(${LIB_FSFW_NAME} PUBLIC ${FSFW_ETL_LINK_TARGET}) string( CONCAT diff --git a/README.md b/README.md index 8d611c57..847e5e9a 100644 --- a/README.md +++ b/README.md @@ -139,7 +139,7 @@ You can also use `-DFSFW_OSAL=linux` on Linux systems. Coverage data in HTML format can be generated using the `CodeCoverage` [CMake module](https://github.com/bilke/cmake-modules/tree/master). -To build the unittests, run them and then generare the coverage data in this format, +To build the unittests, run them and then generate the coverage data in this format, the following command can be used inside the build directory after the build system was set up ```sh @@ -188,7 +188,10 @@ and open the documentation conveniently. Try `helper.py -h for more information. The formatting is done by the `clang-format` tool. The configuration is contained within the `.clang-format` file in the repository root. As long as `clang-format` is installed, you -can run the `apply-clang-format.sh` helper script to format all source files consistently. +can run the `auto-format.sh` helper script to format all source files consistently. Furthermore cmake-format is required to format CMake files which can be installed with: +````sh +sudo pip install cmakelang +```` ## Index diff --git a/automation/Dockerfile b/automation/Dockerfile index 0eb98fbb..2ed2a7d9 100644 --- a/automation/Dockerfile +++ b/automation/Dockerfile @@ -12,3 +12,9 @@ RUN git clone https://github.com/catchorg/Catch2.git && \ git checkout v3.0.0-preview5 && \ cmake -Bbuild -H. -DBUILD_TESTING=OFF && \ cmake --build build/ --target install + +RUN git clone https://github.com/ETLCPP/etl.git && \ + cd etl && \ + git checkout 20.28.0 && \ + cmake -B build . && \ + cmake --install build/ diff --git a/automation/Jenkinsfile b/automation/Jenkinsfile index 798b6b1a..7101958e 100644 --- a/automation/Jenkinsfile +++ b/automation/Jenkinsfile @@ -3,7 +3,7 @@ pipeline { BUILDDIR = 'build-tests' } agent { - docker { image 'fsfw-ci:d2'} + docker { image 'fsfw-ci:d3'} } stages { stage('Clean') { diff --git a/scripts/helper.py b/scripts/helper.py index 4dff908d..56cf352b 100755 --- a/scripts/helper.py +++ b/scripts/helper.py @@ -48,6 +48,20 @@ def main(): action="store_true", help="Run valgrind on generated test binary", ) + parser.add_argument( + "-g", + "--generators", + default = "Ninja", + action="store", + help="CMake generators", + ) + parser.add_argument( + "-w", + "--windows", + default=False, + action="store_true", + help="Run on windows", + ) args = parser.parse_args() if args.all: @@ -115,14 +129,14 @@ def handle_tests_type(args, build_dir_list: list): if args.create: if os.path.exists(UNITTEST_FOLDER_NAME): shutil.rmtree(UNITTEST_FOLDER_NAME) - create_tests_build_cfg() + create_tests_build_cfg(args) build_directory = UNITTEST_FOLDER_NAME elif len(build_dir_list) == 0: print( "No valid CMake tests build directory found. " "Trying to set up test build system" ) - create_tests_build_cfg() + create_tests_build_cfg(args) build_directory = UNITTEST_FOLDER_NAME elif len(build_dir_list) == 1: build_directory = build_dir_list[0] @@ -147,10 +161,15 @@ def handle_tests_type(args, build_dir_list: list): os.chdir("..") -def create_tests_build_cfg(): +def create_tests_build_cfg(args): os.mkdir(UNITTEST_FOLDER_NAME) os.chdir(UNITTEST_FOLDER_NAME) - cmd_runner("cmake -DFSFW_OSAL=host -DFSFW_BUILD_UNITTESTS=ON ..") + if args.windows: + cmake_cmd = 'cmake -G "' + args.generators + '" -DFSFW_OSAL=host -DFSFW_BUILD_UNITTESTS=ON \ + -DGCOVR_PATH="py -m gcovr" ..' + else: + cmake_cmd = 'cmake -G "' + args.generators + '" -DFSFW_OSAL=host -DFSFW_BUILD_UNITTESTS=ON ..' + cmd_runner(cmake_cmd) os.chdir("..") diff --git a/src/fsfw/action/ActionHelper.cpp b/src/fsfw/action/ActionHelper.cpp index d41c78b4..bee68b40 100644 --- a/src/fsfw/action/ActionHelper.cpp +++ b/src/fsfw/action/ActionHelper.cpp @@ -6,7 +6,7 @@ ActionHelper::ActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue) : owner(setOwner), queueToUse(useThisQueue) {} -ActionHelper::~ActionHelper() {} +ActionHelper::~ActionHelper() = default; ReturnValue_t ActionHelper::handleActionMessage(CommandMessage* command) { if (command->getCommand() == ActionMessage::EXECUTE_ACTION) { @@ -59,7 +59,7 @@ void ActionHelper::setQueueToUse(MessageQueueIF* queue) { queueToUse = queue; } void ActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId, store_address_t dataAddress) { - const uint8_t* dataPtr = NULL; + const uint8_t* dataPtr = nullptr; size_t size = 0; ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size); if (result != HasReturnvaluesIF::RETURN_OK) { diff --git a/src/fsfw/action/ActionHelper.h b/src/fsfw/action/ActionHelper.h index d86e87d2..a9910b05 100644 --- a/src/fsfw/action/ActionHelper.h +++ b/src/fsfw/action/ActionHelper.h @@ -1,9 +1,9 @@ #ifndef FSFW_ACTION_ACTIONHELPER_H_ #define FSFW_ACTION_ACTIONHELPER_H_ -#include "../ipc/MessageQueueIF.h" -#include "../serialize/SerializeIF.h" #include "ActionMessage.h" +#include "fsfw/ipc/MessageQueueIF.h" +#include "fsfw/serialize/SerializeIF.h" /** * @brief Action Helper is a helper class which handles action messages * diff --git a/src/fsfw/action/ActionMessage.cpp b/src/fsfw/action/ActionMessage.cpp index 40a516b1..7fc68558 100644 --- a/src/fsfw/action/ActionMessage.cpp +++ b/src/fsfw/action/ActionMessage.cpp @@ -2,9 +2,9 @@ #include "fsfw/objectmanager/ObjectManager.h" #include "fsfw/storagemanager/StorageManagerIF.h" -ActionMessage::ActionMessage() {} +ActionMessage::ActionMessage() = default; -ActionMessage::~ActionMessage() {} +ActionMessage::~ActionMessage() = default; void ActionMessage::setCommand(CommandMessage* message, ActionId_t fid, store_address_t parameters) { @@ -64,9 +64,8 @@ void ActionMessage::clear(CommandMessage* message) { switch (message->getCommand()) { case EXECUTE_ACTION: case DATA_REPLY: { - StorageManagerIF* ipcStore = - ObjectManager::instance()->get(objects::IPC_STORE); - if (ipcStore != NULL) { + auto* ipcStore = ObjectManager::instance()->get(objects::IPC_STORE); + if (ipcStore != nullptr) { ipcStore->deleteData(getStoreId(message)); } break; diff --git a/src/fsfw/action/CommandActionHelper.cpp b/src/fsfw/action/CommandActionHelper.cpp index 19d8e9b8..a06bc44c 100644 --- a/src/fsfw/action/CommandActionHelper.cpp +++ b/src/fsfw/action/CommandActionHelper.cpp @@ -2,14 +2,14 @@ #include "fsfw/objectmanager/ObjectManager.h" CommandActionHelper::CommandActionHelper(CommandsActionsIF *setOwner) - : owner(setOwner), queueToUse(NULL), ipcStore(NULL), commandCount(0), lastTarget(0) {} + : owner(setOwner), queueToUse(nullptr), ipcStore(nullptr), commandCount(0), lastTarget(0) {} -CommandActionHelper::~CommandActionHelper() {} +CommandActionHelper::~CommandActionHelper() = default; ReturnValue_t CommandActionHelper::commandAction(object_id_t commandTo, ActionId_t actionId, SerializeIF *data) { - HasActionsIF *receiver = ObjectManager::instance()->get(commandTo); - if (receiver == NULL) { + auto *receiver = ObjectManager::instance()->get(commandTo); + if (receiver == nullptr) { return CommandsActionsIF::OBJECT_HAS_NO_FUNCTIONS; } store_address_t storeId; @@ -29,11 +29,8 @@ ReturnValue_t CommandActionHelper::commandAction(object_id_t commandTo, ActionId ReturnValue_t CommandActionHelper::commandAction(object_id_t commandTo, ActionId_t actionId, const uint8_t *data, uint32_t size) { - // if (commandCount != 0) { - // return CommandsFunctionsIF::ALREADY_COMMANDING; - // } - HasActionsIF *receiver = ObjectManager::instance()->get(commandTo); - if (receiver == NULL) { + auto *receiver = ObjectManager::instance()->get(commandTo); + if (receiver == nullptr) { return CommandsActionsIF::OBJECT_HAS_NO_FUNCTIONS; } store_address_t storeId; @@ -59,12 +56,12 @@ ReturnValue_t CommandActionHelper::sendCommand(MessageQueueId_t queueId, ActionI ReturnValue_t CommandActionHelper::initialize() { ipcStore = ObjectManager::instance()->get(objects::IPC_STORE); - if (ipcStore == NULL) { + if (ipcStore == nullptr) { return HasReturnvaluesIF::RETURN_FAILED; } queueToUse = owner->getCommandQueuePtr(); - if (queueToUse == NULL) { + if (queueToUse == nullptr) { return HasReturnvaluesIF::RETURN_FAILED; } return HasReturnvaluesIF::RETURN_OK; @@ -104,7 +101,7 @@ ReturnValue_t CommandActionHelper::handleReply(CommandMessage *reply) { uint8_t CommandActionHelper::getCommandCount() const { return commandCount; } void CommandActionHelper::extractDataForOwner(ActionId_t actionId, store_address_t storeId) { - const uint8_t *data = NULL; + const uint8_t *data = nullptr; size_t size = 0; ReturnValue_t result = ipcStore->getData(storeId, &data, &size); if (result != HasReturnvaluesIF::RETURN_OK) { diff --git a/src/fsfw/action/CommandActionHelper.h b/src/fsfw/action/CommandActionHelper.h index dd8ad7f1..a6ec0ca7 100644 --- a/src/fsfw/action/CommandActionHelper.h +++ b/src/fsfw/action/CommandActionHelper.h @@ -14,14 +14,14 @@ class CommandActionHelper { friend class CommandsActionsIF; public: - CommandActionHelper(CommandsActionsIF* owner); + explicit CommandActionHelper(CommandsActionsIF* owner); virtual ~CommandActionHelper(); ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId, const uint8_t* data, uint32_t size); ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId, SerializeIF* data); ReturnValue_t initialize(); ReturnValue_t handleReply(CommandMessage* reply); - uint8_t getCommandCount() const; + [[nodiscard]] uint8_t getCommandCount() const; private: CommandsActionsIF* owner; diff --git a/src/fsfw/action/CommandsActionsIF.h b/src/fsfw/action/CommandsActionsIF.h index 5870a9f2..94d9a7c4 100644 --- a/src/fsfw/action/CommandsActionsIF.h +++ b/src/fsfw/action/CommandsActionsIF.h @@ -1,9 +1,9 @@ #ifndef FSFW_ACTION_COMMANDSACTIONSIF_H_ #define FSFW_ACTION_COMMANDSACTIONSIF_H_ -#include "../ipc/MessageQueueIF.h" -#include "../returnvalues/HasReturnvaluesIF.h" #include "CommandActionHelper.h" +#include "fsfw/ipc/MessageQueueIF.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" /** * Interface to separate commanding actions of other objects. @@ -21,7 +21,7 @@ class CommandsActionsIF { static const uint8_t INTERFACE_ID = CLASS_ID::COMMANDS_ACTIONS_IF; static const ReturnValue_t OBJECT_HAS_NO_FUNCTIONS = MAKE_RETURN_CODE(1); static const ReturnValue_t ALREADY_COMMANDING = MAKE_RETURN_CODE(2); - virtual ~CommandsActionsIF() {} + virtual ~CommandsActionsIF() = default; virtual MessageQueueIF* getCommandQueuePtr() = 0; protected: diff --git a/src/fsfw/action/HasActionsIF.h b/src/fsfw/action/HasActionsIF.h index acc502d7..89e58add 100644 --- a/src/fsfw/action/HasActionsIF.h +++ b/src/fsfw/action/HasActionsIF.h @@ -1,11 +1,11 @@ #ifndef FSFW_ACTION_HASACTIONSIF_H_ #define FSFW_ACTION_HASACTIONSIF_H_ -#include "../ipc/MessageQueueIF.h" -#include "../returnvalues/HasReturnvaluesIF.h" #include "ActionHelper.h" #include "ActionMessage.h" #include "SimpleActionHelper.h" +#include "fsfw/ipc/MessageQueueIF.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" /** * @brief @@ -40,12 +40,12 @@ class HasActionsIF { static const ReturnValue_t INVALID_PARAMETERS = MAKE_RETURN_CODE(2); static const ReturnValue_t EXECUTION_FINISHED = MAKE_RETURN_CODE(3); static const ReturnValue_t INVALID_ACTION_ID = MAKE_RETURN_CODE(4); - virtual ~HasActionsIF() {} + virtual ~HasActionsIF() = default; /** * Function to get the MessageQueueId_t of the implementing object * @return MessageQueueId_t of the object */ - virtual MessageQueueId_t getCommandQueue() const = 0; + [[nodiscard]] virtual MessageQueueId_t getCommandQueue() const = 0; /** * Execute or initialize the execution of a certain function. * The ActionHelpers will execute this function and behave differently diff --git a/src/fsfw/action/SimpleActionHelper.cpp b/src/fsfw/action/SimpleActionHelper.cpp index 894f0df6..fc7e064e 100644 --- a/src/fsfw/action/SimpleActionHelper.cpp +++ b/src/fsfw/action/SimpleActionHelper.cpp @@ -3,7 +3,7 @@ SimpleActionHelper::SimpleActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue) : ActionHelper(setOwner, useThisQueue), isExecuting(false) {} -SimpleActionHelper::~SimpleActionHelper() {} +SimpleActionHelper::~SimpleActionHelper() = default; void SimpleActionHelper::step(ReturnValue_t result) { // STEP_OFFESET is subtracted to compensate for adding offset in base @@ -38,7 +38,7 @@ void SimpleActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId ActionMessage::setStepReply(&reply, actionId, 0, HasActionsIF::IS_BUSY); queueToUse->sendMessage(commandedBy, &reply); } - const uint8_t* dataPtr = NULL; + const uint8_t* dataPtr = nullptr; size_t size = 0; ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size); if (result != HasReturnvaluesIF::RETURN_OK) { diff --git a/src/fsfw/action/SimpleActionHelper.h b/src/fsfw/action/SimpleActionHelper.h index 5cb85fbd..973c7cf2 100644 --- a/src/fsfw/action/SimpleActionHelper.h +++ b/src/fsfw/action/SimpleActionHelper.h @@ -11,15 +11,15 @@ class SimpleActionHelper : public ActionHelper { public: SimpleActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue); - virtual ~SimpleActionHelper(); + ~SimpleActionHelper() override; void step(ReturnValue_t result = HasReturnvaluesIF::RETURN_OK); void finish(ReturnValue_t result = HasReturnvaluesIF::RETURN_OK); ReturnValue_t reportData(SerializeIF* data); protected: void prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId, - store_address_t dataAddress); - virtual void resetHelper(); + store_address_t dataAddress) override; + void resetHelper() override; private: bool isExecuting; @@ -28,4 +28,4 @@ class SimpleActionHelper : public ActionHelper { uint8_t stepCount = 0; }; -#endif /* SIMPLEACTIONHELPER_H_ */ +#endif /* FSFW_ACTION_SIMPLEACTIONHELPER_H_ */ diff --git a/src/fsfw/controller/ControllerBase.cpp b/src/fsfw/controller/ControllerBase.cpp index 953dacb4..7a8b6bc4 100644 --- a/src/fsfw/controller/ControllerBase.cpp +++ b/src/fsfw/controller/ControllerBase.cpp @@ -26,7 +26,7 @@ ReturnValue_t ControllerBase::initialize() { MessageQueueId_t parentQueue = 0; if (parentId != objects::NO_OBJECT) { - SubsystemBase* parent = ObjectManager::instance()->get(parentId); + auto* parent = ObjectManager::instance()->get(parentId); if (parent == nullptr) { return RETURN_FAILED; } @@ -52,7 +52,7 @@ MessageQueueId_t ControllerBase::getCommandQueue() const { return commandQueue-> void ControllerBase::handleQueue() { CommandMessage command; - ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + ReturnValue_t result; for (result = commandQueue->receiveMessage(&command); result == RETURN_OK; result = commandQueue->receiveMessage(&command)) { result = modeHelper.handleModeCommand(&command); @@ -73,20 +73,20 @@ void ControllerBase::handleQueue() { } } -void ControllerBase::startTransition(Mode_t mode, Submode_t submode) { +void ControllerBase::startTransition(Mode_t mode_, Submode_t submode_) { changeHK(this->mode, this->submode, false); triggerEvent(CHANGING_MODE, mode, submode); - this->mode = mode; - this->submode = submode; + mode = mode_; + submode = submode_; modeHelper.modeChanged(mode, submode); modeChanged(mode, submode); announceMode(false); changeHK(this->mode, this->submode, true); } -void ControllerBase::getMode(Mode_t* mode, Submode_t* submode) { - *mode = this->mode; - *submode = this->submode; +void ControllerBase::getMode(Mode_t* mode_, Submode_t* submode_) { + *mode_ = this->mode; + *submode_ = this->submode; } void ControllerBase::setToExternalControl() { healthHelper.setHealth(EXTERNAL_CONTROL); } @@ -99,7 +99,7 @@ ReturnValue_t ControllerBase::performOperation(uint8_t opCode) { return RETURN_OK; } -void ControllerBase::modeChanged(Mode_t mode, Submode_t submode) { return; } +void ControllerBase::modeChanged(Mode_t mode_, Submode_t submode_) {} ReturnValue_t ControllerBase::setHealth(HealthState health) { switch (health) { @@ -115,6 +115,6 @@ ReturnValue_t ControllerBase::setHealth(HealthState health) { HasHealthIF::HealthState ControllerBase::getHealth() { return healthHelper.getHealth(); } void ControllerBase::setTaskIF(PeriodicTaskIF* task_) { executingTask = task_; } -void ControllerBase::changeHK(Mode_t mode, Submode_t submode, bool enable) {} +void ControllerBase::changeHK(Mode_t mode_, Submode_t submode_, bool enable) {} ReturnValue_t ControllerBase::initializeAfterTaskCreation() { return HasReturnvaluesIF::RETURN_OK; } diff --git a/src/fsfw/controller/ControllerBase.h b/src/fsfw/controller/ControllerBase.h index 227b859b..550659b8 100644 --- a/src/fsfw/controller/ControllerBase.h +++ b/src/fsfw/controller/ControllerBase.h @@ -24,21 +24,21 @@ class ControllerBase : public HasModesIF, static const Mode_t MODE_NORMAL = 2; ControllerBase(object_id_t setObjectId, object_id_t parentId, size_t commandQueueDepth = 3); - virtual ~ControllerBase(); + ~ControllerBase() override; /** SystemObject override */ - virtual ReturnValue_t initialize() override; + ReturnValue_t initialize() override; - virtual MessageQueueId_t getCommandQueue() const override; + [[nodiscard]] MessageQueueId_t getCommandQueue() const override; /** HasHealthIF overrides */ - virtual ReturnValue_t setHealth(HealthState health) override; - virtual HasHealthIF::HealthState getHealth() override; + ReturnValue_t setHealth(HealthState health) override; + HasHealthIF::HealthState getHealth() override; /** ExecutableObjectIF overrides */ - virtual ReturnValue_t performOperation(uint8_t opCode) override; - virtual void setTaskIF(PeriodicTaskIF *task) override; - virtual ReturnValue_t initializeAfterTaskCreation() override; + ReturnValue_t performOperation(uint8_t opCode) override; + void setTaskIF(PeriodicTaskIF *task) override; + ReturnValue_t initializeAfterTaskCreation() override; protected: /** @@ -54,8 +54,8 @@ class ControllerBase : public HasModesIF, */ virtual void performControlOperation() = 0; - virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, - uint32_t *msToReachTheMode) override = 0; + ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, + uint32_t *msToReachTheMode) override = 0; const object_id_t parentId; @@ -80,10 +80,10 @@ class ControllerBase : public HasModesIF, /** Mode helpers */ virtual void modeChanged(Mode_t mode, Submode_t submode); - virtual void startTransition(Mode_t mode, Submode_t submode) override; - virtual void getMode(Mode_t *mode, Submode_t *submode) override; - virtual void setToExternalControl() override; - virtual void announceMode(bool recursive); + void startTransition(Mode_t mode, Submode_t submode) override; + void getMode(Mode_t *mode, Submode_t *submode) override; + void setToExternalControl() override; + void announceMode(bool recursive) override; /** HK helpers */ virtual void changeHK(Mode_t mode, Submode_t submode, bool enable); }; diff --git a/src/fsfw/controller/ExtendedControllerBase.cpp b/src/fsfw/controller/ExtendedControllerBase.cpp index 0dfd9dc7..64b39a31 100644 --- a/src/fsfw/controller/ExtendedControllerBase.cpp +++ b/src/fsfw/controller/ExtendedControllerBase.cpp @@ -6,7 +6,7 @@ ExtendedControllerBase::ExtendedControllerBase(object_id_t objectId, object_id_t poolManager(this, commandQueue), actionHelper(this, commandQueue) {} -ExtendedControllerBase::~ExtendedControllerBase() {} +ExtendedControllerBase::~ExtendedControllerBase() = default; ReturnValue_t ExtendedControllerBase::executeAction(ActionId_t actionId, MessageQueueId_t commandedBy, @@ -31,7 +31,7 @@ ReturnValue_t ExtendedControllerBase::handleCommandMessage(CommandMessage *messa void ExtendedControllerBase::handleQueue() { CommandMessage command; - ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + ReturnValue_t result; for (result = commandQueue->receiveMessage(&command); result == RETURN_OK; result = commandQueue->receiveMessage(&command)) { result = actionHelper.handleActionMessage(&command); diff --git a/src/fsfw/controller/ExtendedControllerBase.h b/src/fsfw/controller/ExtendedControllerBase.h index 0c64f5b9..b5583a88 100644 --- a/src/fsfw/controller/ExtendedControllerBase.h +++ b/src/fsfw/controller/ExtendedControllerBase.h @@ -18,16 +18,16 @@ class ExtendedControllerBase : public ControllerBase, public HasLocalDataPoolIF { public: ExtendedControllerBase(object_id_t objectId, object_id_t parentId, size_t commandQueueDepth = 3); - virtual ~ExtendedControllerBase(); + ~ExtendedControllerBase() override; /* SystemObjectIF overrides */ - virtual ReturnValue_t initialize() override; + ReturnValue_t initialize() override; - virtual MessageQueueId_t getCommandQueue() const override; + [[nodiscard]] MessageQueueId_t getCommandQueue() const override; /* ExecutableObjectIF overrides */ - virtual ReturnValue_t performOperation(uint8_t opCode) override; - virtual ReturnValue_t initializeAfterTaskCreation() override; + ReturnValue_t performOperation(uint8_t opCode) override; + ReturnValue_t initializeAfterTaskCreation() override; protected: LocalDataPoolManager poolManager; @@ -39,32 +39,32 @@ class ExtendedControllerBase : public ControllerBase, * @param message * @return */ - virtual ReturnValue_t handleCommandMessage(CommandMessage* message) = 0; + ReturnValue_t handleCommandMessage(CommandMessage* message) override = 0; /** * Periodic helper from ControllerBase, implemented by child class. */ - virtual void performControlOperation() = 0; + void performControlOperation() override = 0; /* Handle the four messages mentioned above */ void handleQueue() override; /* HasActionsIF overrides */ - virtual ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy, - const uint8_t* data, size_t size) override; + ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy, + const uint8_t* data, size_t size) override; /* HasLocalDatapoolIF overrides */ - virtual LocalDataPoolManager* getHkManagerHandle() override; - virtual object_id_t getObjectId() const override; - virtual uint32_t getPeriodicOperationFrequency() const override; + LocalDataPoolManager* getHkManagerHandle() override; + [[nodiscard]] object_id_t getObjectId() const override; + [[nodiscard]] uint32_t getPeriodicOperationFrequency() const override; - virtual ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap, - LocalDataPoolManager& poolManager) override = 0; - virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override = 0; + ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap, + LocalDataPoolManager& poolManager) override = 0; + LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override = 0; // Mode abstract functions - virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, - uint32_t* msToReachTheMode) override = 0; + ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, + uint32_t* msToReachTheMode) override = 0; }; #endif /* FSFW_CONTROLLER_EXTENDEDCONTROLLERBASE_H_ */ diff --git a/src/fsfw/datapool/PoolEntry.cpp b/src/fsfw/datapool/PoolEntry.cpp index fd110e6c..9138a705 100644 --- a/src/fsfw/datapool/PoolEntry.cpp +++ b/src/fsfw/datapool/PoolEntry.cpp @@ -7,24 +7,26 @@ #include "fsfw/serviceinterface/ServiceInterface.h" template -PoolEntry::PoolEntry(std::initializer_list initValue, bool setValid) - : length(static_cast(initValue.size())), valid(setValid) { - this->address = new T[this->length]; - if (initValue.size() == 0) { - std::memset(this->address, 0, this->getByteSize()); - } else { - std::copy(initValue.begin(), initValue.end(), this->address); +PoolEntry::PoolEntry(uint8_t len, bool setValid) : length(len), valid(setValid) { + this->address = new T[this->length](); + std::memset(this->address, 0, this->getByteSize()); +} + +template +PoolEntry::PoolEntry(std::initializer_list initValues, bool setValid) + : length(static_cast(initValues.size())), valid(setValid) { + this->address = new T[this->length](); + if (initValues.size() > 0) { + std::copy(initValues.begin(), initValues.end(), this->address); } } template -PoolEntry::PoolEntry(T* initValue, uint8_t setLength, bool setValid) +PoolEntry::PoolEntry(const T* initValue, uint8_t setLength, bool setValid) : length(setLength), valid(setValid) { - this->address = new T[this->length]; + this->address = new T[this->length](); if (initValue != nullptr) { std::memcpy(this->address, initValue, this->getByteSize()); - } else { - std::memset(this->address, 0, this->getByteSize()); } } diff --git a/src/fsfw/datapool/PoolEntry.h b/src/fsfw/datapool/PoolEntry.h index d3d80f09..4010f78d 100644 --- a/src/fsfw/datapool/PoolEntry.h +++ b/src/fsfw/datapool/PoolEntry.h @@ -33,6 +33,9 @@ class PoolEntry : public PoolEntryIF { "instead! The ECSS standard defines a boolean as a one bit " "field. Therefore it is preferred to store a boolean as an " "uint8_t"); + + PoolEntry(uint8_t len = 1, bool setValid = false); + /** * @brief In the classe's constructor, space is allocated on the heap and * potential initialization values are copied to that space. @@ -49,7 +52,7 @@ class PoolEntry : public PoolEntryIF { * @param setValid * Sets the initialization flag. It is invalid by default. */ - PoolEntry(std::initializer_list initValue = {0}, bool setValid = false); + PoolEntry(std::initializer_list initValue, bool setValid = false); /** * @brief In the classe's constructor, space is allocated on the heap and @@ -62,7 +65,7 @@ class PoolEntry : public PoolEntryIF { * @param setValid * Sets the initialization flag. It is invalid by default. */ - PoolEntry(T* initValue, uint8_t setLength = 1, bool setValid = false); + PoolEntry(const T* initValue, uint8_t setLength = 1, bool setValid = false); //! Explicitely deleted copy ctor, copying is not allowed. PoolEntry(const PoolEntry&) = delete; diff --git a/src/fsfw/datapoollocal/LocalDataPoolManager.cpp b/src/fsfw/datapoollocal/LocalDataPoolManager.cpp index 215d1753..9b7f800f 100644 --- a/src/fsfw/datapoollocal/LocalDataPoolManager.cpp +++ b/src/fsfw/datapoollocal/LocalDataPoolManager.cpp @@ -696,7 +696,8 @@ void LocalDataPoolManager::performPeriodicHkGeneration(HkReceiver& receiver) { if (result != HasReturnvaluesIF::RETURN_OK) { /* Configuration error */ #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "LocalDataPoolManager::performPeriodicHkOperation: HK generation failed." << std::endl; + sif::warning << "LocalDataPoolManager::performPeriodicHkOperation: HK generation failed." + << std::endl; #else sif::printWarning("LocalDataPoolManager::performPeriodicHkOperation: HK generation failed.\n"); #endif diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp index dd9bd5d7..cf457a03 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp @@ -65,7 +65,9 @@ void DeviceHandlerBase::setThermalStateRequestPoolIds(lp_id_t thermalStatePoolId } DeviceHandlerBase::~DeviceHandlerBase() { - delete comCookie; + if (comCookie != nullptr) { + delete comCookie; + } if (defaultFDIRUsed) { delete fdirInstance; } @@ -233,17 +235,26 @@ ReturnValue_t DeviceHandlerBase::initialize() { } void DeviceHandlerBase::decrementDeviceReplyMap() { + bool timedOut = false; for (std::pair& replyPair : deviceReplyMap) { - if (replyPair.second.delayCycles != 0) { + if (replyPair.second.countdown != nullptr && replyPair.second.active) { + if (replyPair.second.countdown->hasTimedOut()) { + resetTimeoutControlledReply(&replyPair.second); + timedOut = true; + } + } + if (replyPair.second.delayCycles != 0 && replyPair.second.countdown == nullptr) { replyPair.second.delayCycles--; if (replyPair.second.delayCycles == 0) { - if (replyPair.second.periodic) { - replyPair.second.delayCycles = replyPair.second.maxDelayCycles; - } - replyToReply(replyPair.first, replyPair.second, TIMEOUT); - missedReply(replyPair.first); + resetDelayCyclesControlledReply(&replyPair.second); + timedOut = true; } } + if (timedOut) { + replyToReply(replyPair.first, replyPair.second, TIMEOUT); + missedReply(replyPair.first); + timedOut = false; + } } } @@ -359,7 +370,6 @@ void DeviceHandlerBase::doStateMachine() { setMode(MODE_OFF); break; } - if (currentUptime - timeoutStart >= powerSwitcher->getSwitchDelayMs()) { triggerEvent(MODE_TRANSITION_FAILED, PowerSwitchIF::SWITCH_TIMEOUT, 0); setMode(MODE_ERROR_ON); @@ -408,20 +418,22 @@ ReturnValue_t DeviceHandlerBase::isModeCombinationValid(Mode_t mode, Submode_t s ReturnValue_t DeviceHandlerBase::insertInCommandAndReplyMap( DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles, LocalPoolDataSetBase* replyDataSet, - size_t replyLen, bool periodic, bool hasDifferentReplyId, DeviceCommandId_t replyId) { + size_t replyLen, bool periodic, bool hasDifferentReplyId, DeviceCommandId_t replyId, + Countdown* countdown) { // No need to check, as we may try to insert multiple times. insertInCommandMap(deviceCommand, hasDifferentReplyId, replyId); if (hasDifferentReplyId) { - return insertInReplyMap(replyId, maxDelayCycles, replyDataSet, replyLen, periodic); + return insertInReplyMap(replyId, maxDelayCycles, replyDataSet, replyLen, periodic, countdown); } else { - return insertInReplyMap(deviceCommand, maxDelayCycles, replyDataSet, replyLen, periodic); + return insertInReplyMap(deviceCommand, maxDelayCycles, replyDataSet, replyLen, periodic, + countdown); } } ReturnValue_t DeviceHandlerBase::insertInReplyMap(DeviceCommandId_t replyId, uint16_t maxDelayCycles, LocalPoolDataSetBase* dataSet, size_t replyLen, - bool periodic) { + bool periodic, Countdown* countdown) { DeviceReplyInfo info; info.maxDelayCycles = maxDelayCycles; info.periodic = periodic; @@ -429,6 +441,7 @@ ReturnValue_t DeviceHandlerBase::insertInReplyMap(DeviceCommandId_t replyId, info.replyLen = replyLen; info.dataSet = dataSet; info.command = deviceCommandMap.end(); + info.countdown = countdown; auto resultPair = deviceReplyMap.emplace(replyId, info); if (resultPair.second) { return RETURN_OK; @@ -464,7 +477,8 @@ size_t DeviceHandlerBase::getNextReplyLength(DeviceCommandId_t commandId) { } DeviceReplyIter iter = deviceReplyMap.find(replyId); if (iter != deviceReplyMap.end()) { - if (iter->second.delayCycles != 0) { + if ((iter->second.delayCycles != 0 && iter->second.countdown == nullptr) || + (iter->second.active && iter->second.countdown != nullptr)) { return iter->second.replyLen; } } @@ -500,9 +514,19 @@ ReturnValue_t DeviceHandlerBase::updatePeriodicReply(bool enable, DeviceCommandI return COMMAND_NOT_SUPPORTED; } if (enable) { - info->delayCycles = info->maxDelayCycles; + info->active = true; + if (info->countdown != nullptr) { + info->delayCycles = info->maxDelayCycles; + } else { + info->countdown->resetTimer(); + } } else { - info->delayCycles = 0; + info->active = false; + if (info->countdown != nullptr) { + info->delayCycles = 0; + } else { + info->countdown->timeOut(); + } } } return HasReturnvaluesIF::RETURN_OK; @@ -808,17 +832,18 @@ void DeviceHandlerBase::handleReply(const uint8_t* receivedData, DeviceCommandId DeviceReplyInfo* info = &(iter->second); - if (info->delayCycles != 0) { + if ((info->delayCycles != 0 && info->countdown == nullptr) || + (info->active && info->countdown != nullptr)) { result = interpretDeviceReply(foundId, receivedData); if (result == IGNORE_REPLY_DATA) { return; } - if (info->periodic) { - info->delayCycles = info->maxDelayCycles; - } else { - info->delayCycles = 0; + if (info->active && info->countdown != nullptr) { + resetTimeoutControlledReply(info); + } else if (info->delayCycles != 0) { + resetDelayCyclesControlledReply(info); } if (result != RETURN_OK) { @@ -837,6 +862,24 @@ void DeviceHandlerBase::handleReply(const uint8_t* receivedData, DeviceCommandId } } +void DeviceHandlerBase::resetTimeoutControlledReply(DeviceReplyInfo* info) { + if (info->periodic) { + info->countdown->resetTimer(); + } else { + info->active = false; + info->countdown->timeOut(); + } +} + +void DeviceHandlerBase::resetDelayCyclesControlledReply(DeviceReplyInfo* info) { + if (info->periodic) { + info->delayCycles = info->maxDelayCycles; + } else { + info->delayCycles = 0; + info->active = false; + } +} + ReturnValue_t DeviceHandlerBase::getStorageData(store_address_t storageAddress, uint8_t** data, size_t* len) { size_t lenTmp; @@ -959,9 +1002,15 @@ ReturnValue_t DeviceHandlerBase::enableReplyInReplyMap(DeviceCommandMap::iterato } if (iter != deviceReplyMap.end()) { DeviceReplyInfo* info = &(iter->second); + // If a countdown has been set, the delay cycles will be ignored and the reply times out + // as soon as the countdown has expired info->delayCycles = info->maxDelayCycles; info->command = command; command->second.expectedReplies = expectedReplies; + if (info->countdown != nullptr) { + info->countdown->resetTimer(); + } + info->active = true; return RETURN_OK; } else { return NO_REPLY_EXPECTED; @@ -1196,7 +1245,8 @@ void DeviceHandlerBase::setParentQueue(MessageQueueId_t parentQueueId) { bool DeviceHandlerBase::isAwaitingReply() { std::map::iterator iter; for (iter = deviceReplyMap.begin(); iter != deviceReplyMap.end(); ++iter) { - if (iter->second.delayCycles != 0) { + if ((iter->second.delayCycles != 0 && iter->second.countdown == nullptr) || + (iter->second.active && iter->second.countdown != nullptr)) { return true; } } @@ -1351,6 +1401,13 @@ uint8_t DeviceHandlerBase::getReplyDelayCycles(DeviceCommandId_t deviceCommand) DeviceReplyMap::iterator iter = deviceReplyMap.find(deviceCommand); if (iter == deviceReplyMap.end()) { return 0; + } else if (iter->second.countdown != nullptr) { + // fake a useful return value for legacy code + if (iter->second.active) { + return 1; + } else { + return 0; + } } return iter->second.delayCycles; } diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.h b/src/fsfw/devicehandlers/DeviceHandlerBase.h index 84dcb8dc..e29e6596 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerBase.h +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.h @@ -448,6 +448,9 @@ class DeviceHandlerBase : public DeviceHandlerIF, * by the device repeatedly without request) or not. Default is aperiodic (0). * Please note that periodic replies are disabled by default. You can enable them with * #updatePeriodicReply + * @param countdown Instead of using maxDelayCycles to timeout a device reply it is also possible + * to provide a pointer to a Countdown object which will signal the timeout + * when expired * @return - @c RETURN_OK when the command was successfully inserted, * - @c RETURN_FAILED else. */ @@ -455,7 +458,8 @@ class DeviceHandlerBase : public DeviceHandlerIF, LocalPoolDataSetBase *replyDataSet = nullptr, size_t replyLen = 0, bool periodic = false, bool hasDifferentReplyId = false, - DeviceCommandId_t replyId = 0); + DeviceCommandId_t replyId = 0, + Countdown *countdown = nullptr); /** * @brief This is a helper method to insert replies in the reply map. * @param deviceCommand Identifier of the reply to add. @@ -465,12 +469,15 @@ class DeviceHandlerBase : public DeviceHandlerIF, * by the device repeatedly without request) or not. Default is aperiodic (0). * Please note that periodic replies are disabled by default. You can enable them with * #updatePeriodicReply + * @param countdown Instead of using maxDelayCycles to timeout a device reply it is also possible + * to provide a pointer to a Countdown object which will signal the timeout + * when expired * @return - @c RETURN_OK when the command was successfully inserted, * - @c RETURN_FAILED else. */ ReturnValue_t insertInReplyMap(DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles, LocalPoolDataSetBase *dataSet = nullptr, size_t replyLen = 0, - bool periodic = false); + bool periodic = false, Countdown *countdown = nullptr); /** * @brief A simple command to add a command to the commandList. @@ -783,6 +790,11 @@ class DeviceHandlerBase : public DeviceHandlerIF, LocalPoolDataSetBase *dataSet = nullptr; //! The command that expects this reply. DeviceCommandMap::iterator command; + //! Instead of using delayCycles to specify the maximum time to wait for the device reply, it + //! is also possible specify a countdown + Countdown *countdown = nullptr; + //! will be set to true when reply is enabled + bool active = false; }; using DeviceReplyMap = std::map; @@ -1244,6 +1256,17 @@ class DeviceHandlerBase : public DeviceHandlerIF, */ void doGetRead(void); + /** + * @brief Resets replies which use a timeout to detect missed replies. + */ + void resetTimeoutControlledReply(DeviceReplyInfo *info); + + /** + * @brief Resets replies which use a number of maximum delay cycles to detect + * missed replies. + */ + void resetDelayCyclesControlledReply(DeviceReplyInfo *info); + /** * Retrive data from the #IPCStore. * diff --git a/src/fsfw/events/EventManager.cpp b/src/fsfw/events/EventManager.cpp index aaa7d6c5..47270d2a 100644 --- a/src/fsfw/events/EventManager.cpp +++ b/src/fsfw/events/EventManager.cpp @@ -88,6 +88,11 @@ ReturnValue_t EventManager::subscribeToEventRange(MessageQueueId_t listener, Eve return result; } +ReturnValue_t EventManager::unsubscribeFromAllEvents(MessageQueueId_t listener, + object_id_t object) { + return unsubscribeFromEventRange(listener, 0, 0, true, object); +} + ReturnValue_t EventManager::unsubscribeFromEventRange(MessageQueueId_t listener, EventId_t idFrom, EventId_t idTo, bool idInverted, object_id_t reporterFrom, diff --git a/src/fsfw/events/EventManager.h b/src/fsfw/events/EventManager.h index f2d642ff..70245f5d 100644 --- a/src/fsfw/events/EventManager.h +++ b/src/fsfw/events/EventManager.h @@ -37,6 +37,7 @@ class EventManager : public EventManagerIF, public ExecutableObjectIF, public Sy EventId_t idTo = 0, bool idInverted = false, object_id_t reporterFrom = 0, object_id_t reporterTo = 0, bool reporterInverted = false); + ReturnValue_t unsubscribeFromAllEvents(MessageQueueId_t listener, object_id_t object); ReturnValue_t unsubscribeFromEventRange(MessageQueueId_t listener, EventId_t idFrom = 0, EventId_t idTo = 0, bool idInverted = false, object_id_t reporterFrom = 0, object_id_t reporterTo = 0, diff --git a/src/fsfw/events/EventManagerIF.h b/src/fsfw/events/EventManagerIF.h index 98051ba0..adb61f2b 100644 --- a/src/fsfw/events/EventManagerIF.h +++ b/src/fsfw/events/EventManagerIF.h @@ -20,6 +20,7 @@ class EventManagerIF { bool forwardAllButSelected = false) = 0; virtual ReturnValue_t subscribeToEvent(MessageQueueId_t listener, EventId_t event) = 0; virtual ReturnValue_t subscribeToAllEventsFrom(MessageQueueId_t listener, object_id_t object) = 0; + virtual ReturnValue_t unsubscribeFromAllEvents(MessageQueueId_t listener, object_id_t object) = 0; virtual ReturnValue_t subscribeToEventRange(MessageQueueId_t listener, EventId_t idFrom = 0, EventId_t idTo = 0, bool idInverted = false, object_id_t reporterFrom = 0, diff --git a/src/fsfw/fdir/FailureIsolationBase.cpp b/src/fsfw/fdir/FailureIsolationBase.cpp index fedef869..3e6d5dcf 100644 --- a/src/fsfw/fdir/FailureIsolationBase.cpp +++ b/src/fsfw/fdir/FailureIsolationBase.cpp @@ -14,6 +14,16 @@ FailureIsolationBase::FailureIsolationBase(object_id_t owner, object_id_t parent } FailureIsolationBase::~FailureIsolationBase() { + EventManagerIF* manager = ObjectManager::instance()->get(objects::EVENT_MANAGER); + if (manager == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "FailureIsolationBase::~FailureIsolationBase: Event Manager has not" + " been initialized!" + << std::endl; +#endif + return; + } + manager->unsubscribeFromAllEvents(eventQueue->getId(), ownerId); QueueFactory::instance()->deleteMessageQueue(eventQueue); } diff --git a/src/fsfw/fdir/FaultCounter.cpp b/src/fsfw/fdir/FaultCounter.cpp index e87cf613..4515e5b1 100644 --- a/src/fsfw/fdir/FaultCounter.cpp +++ b/src/fsfw/fdir/FaultCounter.cpp @@ -60,14 +60,14 @@ ReturnValue_t FaultCounter::getParameter(uint8_t domainId, uint8_t uniqueId, return INVALID_DOMAIN_ID; } - switch (uniqueId) { - case 0: + switch (static_cast(uniqueId)) { + case ParameterIds::FAILURE_THRESHOLD: parameterWrapper->set(failureThreshold); break; - case 1: + case ParameterIds::FAULT_COUNT: parameterWrapper->set(faultCount); break; - case 2: + case ParameterIds::TIMEOUT: parameterWrapper->set(timer.timeout); break; default: diff --git a/src/fsfw/fdir/FaultCounter.h b/src/fsfw/fdir/FaultCounter.h index 3b59885c..cca780d6 100644 --- a/src/fsfw/fdir/FaultCounter.h +++ b/src/fsfw/fdir/FaultCounter.h @@ -6,6 +6,8 @@ class FaultCounter : public HasParametersIF { public: + enum class ParameterIds { FAILURE_THRESHOLD, FAULT_COUNT, TIMEOUT }; + FaultCounter(); FaultCounter(uint32_t failureThreshold, uint32_t decrementAfterMs, uint8_t setParameterDomain = 0); @@ -25,7 +27,8 @@ class FaultCounter : public HasParametersIF { virtual ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueId, ParameterWrapper *parameterWrapper, - const ParameterWrapper *newValues, uint16_t startAtIndex); + const ParameterWrapper *newValues = nullptr, + uint16_t startAtIndex = 0); void setParameterDomain(uint8_t domain); diff --git a/src/fsfw/health/HealthHelper.cpp b/src/fsfw/health/HealthHelper.cpp index 4bef128c..0f51ddeb 100644 --- a/src/fsfw/health/HealthHelper.cpp +++ b/src/fsfw/health/HealthHelper.cpp @@ -5,7 +5,7 @@ HealthHelper::HealthHelper(HasHealthIF* owner, object_id_t objectId) : objectId(objectId), owner(owner) {} -HealthHelper::~HealthHelper() {} +HealthHelper::~HealthHelper() { healthTable->removeObject(objectId); } ReturnValue_t HealthHelper::handleHealthCommand(CommandMessage* message) { switch (message->getCommand()) { diff --git a/src/fsfw/health/HealthTable.cpp b/src/fsfw/health/HealthTable.cpp index ab4881f4..f4bda1c3 100644 --- a/src/fsfw/health/HealthTable.cpp +++ b/src/fsfw/health/HealthTable.cpp @@ -27,6 +27,15 @@ ReturnValue_t HealthTable::registerObject(object_id_t object, return HasReturnvaluesIF::RETURN_OK; } +ReturnValue_t HealthTable::removeObject(object_id_t object) { + mapIterator = healthMap.find(object); + if (mapIterator == healthMap.end()) { + return HasReturnvaluesIF::RETURN_FAILED; + } + healthMap.erase(mapIterator); + return HasReturnvaluesIF::RETURN_OK; +} + void HealthTable::setHealth(object_id_t object, HasHealthIF::HealthState newState) { MutexGuard(mutex, timeoutType, mutexTimeoutMs); HealthMap::iterator iter = healthMap.find(object); diff --git a/src/fsfw/health/HealthTable.h b/src/fsfw/health/HealthTable.h index 4718abc3..60e00f92 100644 --- a/src/fsfw/health/HealthTable.h +++ b/src/fsfw/health/HealthTable.h @@ -17,6 +17,7 @@ class HealthTable : public HealthTableIF, public SystemObject { /** HealthTableIF overrides */ virtual ReturnValue_t registerObject( object_id_t object, HasHealthIF::HealthState initilialState = HasHealthIF::HEALTHY) override; + ReturnValue_t removeObject(object_id_t object) override; virtual size_t getPrintSize() override; virtual void printAll(uint8_t* pointer, size_t maxSize) override; diff --git a/src/fsfw/health/HealthTableIF.h b/src/fsfw/health/HealthTableIF.h index 50266ac2..aab3f0eb 100644 --- a/src/fsfw/health/HealthTableIF.h +++ b/src/fsfw/health/HealthTableIF.h @@ -14,6 +14,8 @@ class HealthTableIF : public ManagesHealthIF { virtual ReturnValue_t registerObject( object_id_t object, HasHealthIF::HealthState initilialState = HasHealthIF::HEALTHY) = 0; + virtual ReturnValue_t removeObject(object_id_t objectId) = 0; + virtual size_t getPrintSize() = 0; virtual void printAll(uint8_t *pointer, size_t maxSize) = 0; diff --git a/src/fsfw/osal/linux/FixedTimeslotTask.cpp b/src/fsfw/osal/linux/FixedTimeslotTask.cpp index 775acea8..156413ea 100644 --- a/src/fsfw/osal/linux/FixedTimeslotTask.cpp +++ b/src/fsfw/osal/linux/FixedTimeslotTask.cpp @@ -54,7 +54,7 @@ ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) { // If the deadline was missed, the deadlineMissedFunc is called. if (!PosixThread::delayUntil(&lastWakeTime, interval)) { // No time left on timer -> we missed the deadline - if(dlmFunc != nullptr){ + if (dlmFunc != nullptr) { dlmFunc(); } } diff --git a/src/fsfw/osal/linux/MessageQueue.cpp b/src/fsfw/osal/linux/MessageQueue.cpp index 378f4e74..4ef7f756 100644 --- a/src/fsfw/osal/linux/MessageQueue.cpp +++ b/src/fsfw/osal/linux/MessageQueue.cpp @@ -290,10 +290,9 @@ ReturnValue_t MessageQueue::handleOpenError(mq_attr* attributes, uint32_t messag */ #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "MessageQueue::MessageQueue: Default MQ size " << defaultMqMaxMsg - << " is too small for requested size " << messageDepth << std::endl; + << " is too small for requested message depth " << messageDepth << std::endl; sif::error << "This error can be fixed by setting the maximum " - "allowed message size higher!" - << std::endl; + "allowed message depth higher" << std::endl; #else sif::printError( "MessageQueue::MessageQueue: Default MQ size %d is too small for" diff --git a/tests/src/fsfw_tests/unit/CMakeLists.txt b/tests/src/fsfw_tests/unit/CMakeLists.txt index b5143c3b..f54e1fc9 100644 --- a/tests/src/fsfw_tests/unit/CMakeLists.txt +++ b/tests/src/fsfw_tests/unit/CMakeLists.txt @@ -26,3 +26,4 @@ add_subdirectory(tmtcpacket) add_subdirectory(cfdp) add_subdirectory(hal) add_subdirectory(internalerror) +add_subdirectory(devicehandler) diff --git a/tests/src/fsfw_tests/unit/CatchFactory.cpp b/tests/src/fsfw_tests/unit/CatchFactory.cpp index 01018dfa..860a9bed 100644 --- a/tests/src/fsfw_tests/unit/CatchFactory.cpp +++ b/tests/src/fsfw_tests/unit/CatchFactory.cpp @@ -65,7 +65,7 @@ void Factory::setStaticFrameworkObjectIds() { VerificationReporter::messageReceiver = objects::PUS_SERVICE_1_VERIFICATION; DeviceHandlerBase::powerSwitcherId = objects::NO_OBJECT; - DeviceHandlerBase::rawDataReceiverId = objects::PUS_SERVICE_2_DEVICE_ACCESS; + DeviceHandlerBase::rawDataReceiverId = objects::NO_OBJECT; LocalDataPoolManager::defaultHkDestination = objects::HK_RECEIVER_MOCK; diff --git a/tests/src/fsfw_tests/unit/devicehandler/CMakeLists.txt b/tests/src/fsfw_tests/unit/devicehandler/CMakeLists.txt new file mode 100644 index 00000000..7ad5d316 --- /dev/null +++ b/tests/src/fsfw_tests/unit/devicehandler/CMakeLists.txt @@ -0,0 +1,8 @@ +target_sources(${FSFW_TEST_TGT} PRIVATE + CookieIFMock.cpp + ComIFMock.cpp + DeviceHandlerCommander.cpp + DeviceHandlerMock.cpp + DeviceFdirMock.cpp + TestDeviceHandlerBase.cpp +) diff --git a/tests/src/fsfw_tests/unit/devicehandler/ComIFMock.cpp b/tests/src/fsfw_tests/unit/devicehandler/ComIFMock.cpp new file mode 100644 index 00000000..4d985f94 --- /dev/null +++ b/tests/src/fsfw_tests/unit/devicehandler/ComIFMock.cpp @@ -0,0 +1,46 @@ +#include "ComIFMock.h" + +#include "DeviceHandlerMock.h" + +ComIFMock::ComIFMock(object_id_t objectId) : SystemObject(objectId) {} + +ComIFMock::~ComIFMock() {} + +ReturnValue_t ComIFMock::initializeInterface(CookieIF *cookie) { return RETURN_OK; } + +ReturnValue_t ComIFMock::sendMessage(CookieIF *cookie, const uint8_t *sendData, size_t sendLen) { + data = *sendData; + return RETURN_OK; +} + +ReturnValue_t ComIFMock::getSendSuccess(CookieIF *cookie) { return RETURN_OK; } + +ReturnValue_t ComIFMock::requestReceiveMessage(CookieIF *cookie, size_t requestLen) { + return RETURN_OK; +} + +ReturnValue_t ComIFMock::readReceivedMessage(CookieIF *cookie, uint8_t **buffer, size_t *size) { + switch (testCase) { + case TestCase::MISSED_REPLY: { + *size = 0; + return RETURN_OK; + } + case TestCase::SIMPLE_COMMAND_NOMINAL: { + *size = 1; + data = DeviceHandlerMock::SIMPLE_COMMAND_DATA; + *buffer = &data; + break; + } + case TestCase::PERIODIC_REPLY_NOMINAL: { + *size = 1; + data = DeviceHandlerMock::PERIODIC_REPLY_DATA; + *buffer = &data; + break; + } + default: + break; + } + return RETURN_OK; +} + +void ComIFMock::setTestCase(TestCase testCase_) { testCase = testCase_; } diff --git a/tests/src/fsfw_tests/unit/devicehandler/ComIFMock.h b/tests/src/fsfw_tests/unit/devicehandler/ComIFMock.h new file mode 100644 index 00000000..1463deb6 --- /dev/null +++ b/tests/src/fsfw_tests/unit/devicehandler/ComIFMock.h @@ -0,0 +1,37 @@ +#ifndef TESTS_SRC_FSFW_TESTS_UNIT_DEVICEHANDLER_COMIFMOCK_H_ +#define TESTS_SRC_FSFW_TESTS_UNIT_DEVICEHANDLER_COMIFMOCK_H_ + +#include +#include + +/** + * @brief The ComIFMock supports the simulation of various device communication error cases + * like incomplete or wrong replies and can be used to test the + * DeviceHandlerBase. + */ +class ComIFMock : public DeviceCommunicationIF, public SystemObject { + public: + enum class TestCase { SIMPLE_COMMAND_NOMINAL, PERIODIC_REPLY_NOMINAL, MISSED_REPLY }; + + ComIFMock(object_id_t objectId); + virtual ~ComIFMock(); + + virtual ReturnValue_t initializeInterface(CookieIF *cookie) override; + virtual ReturnValue_t sendMessage(CookieIF *cookie, const uint8_t *sendData, + size_t sendLen) override; + virtual ReturnValue_t getSendSuccess(CookieIF *cookie) override; + virtual ReturnValue_t requestReceiveMessage(CookieIF *cookie, size_t requestLen) override; + virtual ReturnValue_t readReceivedMessage(CookieIF *cookie, uint8_t **buffer, + size_t *size) override; + void setTestCase(TestCase testCase_); + + private: + TestCase testCase = TestCase::SIMPLE_COMMAND_NOMINAL; + + static const uint8_t SIMPLE_COMMAND_DATA = 1; + static const uint8_t PERIODIC_REPLY_DATA = 2; + + uint8_t data = 0; +}; + +#endif /* TESTS_SRC_FSFW_TESTS_UNIT_DEVICEHANDLER_COMIFMOCK_H_ */ diff --git a/tests/src/fsfw_tests/unit/devicehandler/CookieIFMock.cpp b/tests/src/fsfw_tests/unit/devicehandler/CookieIFMock.cpp new file mode 100644 index 00000000..e9b03a6c --- /dev/null +++ b/tests/src/fsfw_tests/unit/devicehandler/CookieIFMock.cpp @@ -0,0 +1,5 @@ +#include "CookieIFMock.h" + +CookieIFMock::CookieIFMock() {} + +CookieIFMock::~CookieIFMock() {} diff --git a/tests/src/fsfw_tests/unit/devicehandler/CookieIFMock.h b/tests/src/fsfw_tests/unit/devicehandler/CookieIFMock.h new file mode 100644 index 00000000..5c868932 --- /dev/null +++ b/tests/src/fsfw_tests/unit/devicehandler/CookieIFMock.h @@ -0,0 +1,12 @@ +#ifndef TESTS_SRC_FSFW_TESTS_UNIT_DEVICEHANDLER_COOKIEIFMOCK_H_ +#define TESTS_SRC_FSFW_TESTS_UNIT_DEVICEHANDLER_COOKIEIFMOCK_H_ + +#include "fsfw/devicehandlers/CookieIF.h" + +class CookieIFMock : public CookieIF { + public: + CookieIFMock(); + virtual ~CookieIFMock(); +}; + +#endif /* TESTS_SRC_FSFW_TESTS_UNIT_DEVICEHANDLER_COOKIEIFMOCK_H_ */ diff --git a/tests/src/fsfw_tests/unit/devicehandler/DeviceFdirMock.cpp b/tests/src/fsfw_tests/unit/devicehandler/DeviceFdirMock.cpp new file mode 100644 index 00000000..dfef7cd3 --- /dev/null +++ b/tests/src/fsfw_tests/unit/devicehandler/DeviceFdirMock.cpp @@ -0,0 +1,18 @@ +#include "DeviceFdirMock.h" + +#include + +DeviceFdirMock::DeviceFdirMock(object_id_t owner, object_id_t parent) + : DeviceHandlerFailureIsolation(owner, parent) {} + +DeviceFdirMock::~DeviceFdirMock() {} + +uint32_t DeviceFdirMock::getMissedReplyCount() { + ParameterWrapper parameterWrapper; + this->getParameter(MISSED_REPLY_DOMAIN_ID, + static_cast(FaultCounter::ParameterIds::FAULT_COUNT), + ¶meterWrapper, nullptr, 0); + uint32_t missedReplyCount = 0; + parameterWrapper.getElement(&missedReplyCount); + return missedReplyCount; +} diff --git a/tests/src/fsfw_tests/unit/devicehandler/DeviceFdirMock.h b/tests/src/fsfw_tests/unit/devicehandler/DeviceFdirMock.h new file mode 100644 index 00000000..b314fc98 --- /dev/null +++ b/tests/src/fsfw_tests/unit/devicehandler/DeviceFdirMock.h @@ -0,0 +1,18 @@ +#ifndef TESTS_SRC_FSFW_TESTS_UNIT_DEVICEHANDLER_DEVICEFDIRMOCK_H_ +#define TESTS_SRC_FSFW_TESTS_UNIT_DEVICEHANDLER_DEVICEFDIRMOCK_H_ + +#include "fsfw/devicehandlers/DeviceHandlerFailureIsolation.h" + +class DeviceFdirMock : public DeviceHandlerFailureIsolation { + public: + DeviceFdirMock(object_id_t owner, object_id_t parent); + virtual ~DeviceFdirMock(); + + uint32_t getMissedReplyCount(); + + private: + static const uint8_t STRANGE_REPLY_DOMAIN_ID = 0xF0; + static const uint8_t MISSED_REPLY_DOMAIN_ID = 0xF1; +}; + +#endif /* TESTS_SRC_FSFW_TESTS_UNIT_DEVICEHANDLER_DEVICEFDIRMOCK_H_ */ diff --git a/tests/src/fsfw_tests/unit/devicehandler/DeviceHandlerCommander.cpp b/tests/src/fsfw_tests/unit/devicehandler/DeviceHandlerCommander.cpp new file mode 100644 index 00000000..4540a388 --- /dev/null +++ b/tests/src/fsfw_tests/unit/devicehandler/DeviceHandlerCommander.cpp @@ -0,0 +1,64 @@ +#include "DeviceHandlerCommander.h" + +#include + +DeviceHandlerCommander::DeviceHandlerCommander(object_id_t objectId) + : SystemObject(objectId), commandActionHelper(this) { + auto mqArgs = MqArgs(this->getObjectId()); + commandQueue = QueueFactory::instance()->createMessageQueue( + QUEUE_SIZE, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs); +} + +DeviceHandlerCommander::~DeviceHandlerCommander() {} + +ReturnValue_t DeviceHandlerCommander::performOperation(uint8_t operationCode) { + readCommandQueue(); + return RETURN_OK; +} + +ReturnValue_t DeviceHandlerCommander::initialize() { + ReturnValue_t result = commandActionHelper.initialize(); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return HasReturnvaluesIF::RETURN_OK; +} + +MessageQueueIF* DeviceHandlerCommander::getCommandQueuePtr() { return commandQueue; } + +void DeviceHandlerCommander::stepSuccessfulReceived(ActionId_t actionId, uint8_t step) {} + +void DeviceHandlerCommander::stepFailedReceived(ActionId_t actionId, uint8_t step, + ReturnValue_t returnCode) {} + +void DeviceHandlerCommander::dataReceived(ActionId_t actionId, const uint8_t* data, uint32_t size) { +} + +void DeviceHandlerCommander::completionSuccessfulReceived(ActionId_t actionId) { + lastReplyReturnCode = RETURN_OK; +} + +void DeviceHandlerCommander::completionFailedReceived(ActionId_t actionId, + ReturnValue_t returnCode) { + lastReplyReturnCode = returnCode; +} + +void DeviceHandlerCommander::readCommandQueue() { + CommandMessage message; + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + for (result = commandQueue->receiveMessage(&message); result == HasReturnvaluesIF::RETURN_OK; + result = commandQueue->receiveMessage(&message)) { + result = commandActionHelper.handleReply(&message); + if (result == HasReturnvaluesIF::RETURN_OK) { + continue; + } + } +} + +ReturnValue_t DeviceHandlerCommander::sendCommand(object_id_t target, ActionId_t actionId) { + return commandActionHelper.commandAction(target, actionId, nullptr, 0); +} + +ReturnValue_t DeviceHandlerCommander::getReplyReturnCode() { return lastReplyReturnCode; } + +void DeviceHandlerCommander::resetReplyReturnCode() { lastReplyReturnCode = RETURN_FAILED; } diff --git a/tests/src/fsfw_tests/unit/devicehandler/DeviceHandlerCommander.h b/tests/src/fsfw_tests/unit/devicehandler/DeviceHandlerCommander.h new file mode 100644 index 00000000..82183baf --- /dev/null +++ b/tests/src/fsfw_tests/unit/devicehandler/DeviceHandlerCommander.h @@ -0,0 +1,50 @@ +#ifndef TESTS_SRC_FSFW_TESTS_UNIT_DEVICEHANDLER_DEVICEHANDLERCOMMANDER_H_ +#define TESTS_SRC_FSFW_TESTS_UNIT_DEVICEHANDLER_DEVICEHANDLERCOMMANDER_H_ + +#include "fsfw/action/CommandActionHelper.h" +#include "fsfw/action/CommandsActionsIF.h" +#include "fsfw/objectmanager/SystemObject.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include "fsfw/tasks/ExecutableObjectIF.h" + +class DeviceHandlerCommander : public ExecutableObjectIF, + public SystemObject, + public CommandsActionsIF, + public HasReturnvaluesIF { + public: + DeviceHandlerCommander(object_id_t objectId); + virtual ~DeviceHandlerCommander(); + + ReturnValue_t performOperation(uint8_t operationCode = 0); + ReturnValue_t initialize() override; + MessageQueueIF* getCommandQueuePtr() override; + void stepSuccessfulReceived(ActionId_t actionId, uint8_t step) override; + void stepFailedReceived(ActionId_t actionId, uint8_t step, ReturnValue_t returnCode) override; + void dataReceived(ActionId_t actionId, const uint8_t* data, uint32_t size) override; + void completionSuccessfulReceived(ActionId_t actionId) override; + void completionFailedReceived(ActionId_t actionId, ReturnValue_t returnCode) override; + + /** + * @brief Calling this function will send the command to the device handler object. + * + * @param target Object ID of the device handler + * @param actionId Action ID of the command to send + */ + ReturnValue_t sendCommand(object_id_t target, ActionId_t actionId); + + ReturnValue_t getReplyReturnCode(); + void resetReplyReturnCode(); + + private: + static const uint32_t QUEUE_SIZE = 20; + + MessageQueueIF* commandQueue = nullptr; + + CommandActionHelper commandActionHelper; + + ReturnValue_t lastReplyReturnCode = RETURN_FAILED; + + void readCommandQueue(); +}; + +#endif /* TESTS_SRC_FSFW_TESTS_UNIT_DEVICEHANDLER_DEVICEHANDLERCOMMANDER_H_ */ diff --git a/tests/src/fsfw_tests/unit/devicehandler/DeviceHandlerMock.cpp b/tests/src/fsfw_tests/unit/devicehandler/DeviceHandlerMock.cpp new file mode 100644 index 00000000..1e05f8f3 --- /dev/null +++ b/tests/src/fsfw_tests/unit/devicehandler/DeviceHandlerMock.cpp @@ -0,0 +1,103 @@ +#include "DeviceHandlerMock.h" + +#include + +DeviceHandlerMock::DeviceHandlerMock(object_id_t objectId, object_id_t deviceCommunication, + CookieIF *comCookie, FailureIsolationBase *fdirInstance) + : DeviceHandlerBase(objectId, deviceCommunication, comCookie, fdirInstance) { + mode = MODE_ON; +} + +DeviceHandlerMock::~DeviceHandlerMock() {} + +void DeviceHandlerMock::doStartUp() { setMode(_MODE_TO_ON); } + +void DeviceHandlerMock::doShutDown() { setMode(_MODE_POWER_DOWN); } + +ReturnValue_t DeviceHandlerMock::buildNormalDeviceCommand(DeviceCommandId_t *id) { + return NOTHING_TO_SEND; +} + +ReturnValue_t DeviceHandlerMock::buildTransitionDeviceCommand(DeviceCommandId_t *id) { + return NOTHING_TO_SEND; +} + +ReturnValue_t DeviceHandlerMock::buildCommandFromCommand(DeviceCommandId_t deviceCommand, + const uint8_t *commandData, + size_t commandDataLen) { + switch (deviceCommand) { + case SIMPLE_COMMAND: { + commandBuffer[0] = SIMPLE_COMMAND_DATA; + rawPacket = commandBuffer; + rawPacketLen = sizeof(SIMPLE_COMMAND_DATA); + break; + } + default: + WARN("DeviceHandlerMock::buildCommandFromCommand: Invalid device command"); + break; + } + return RETURN_OK; +} + +ReturnValue_t DeviceHandlerMock::scanForReply(const uint8_t *start, size_t len, + DeviceCommandId_t *foundId, size_t *foundLen) { + switch (*start) { + case SIMPLE_COMMAND_DATA: { + *foundId = SIMPLE_COMMAND; + *foundLen = sizeof(SIMPLE_COMMAND_DATA); + return RETURN_OK; + break; + } + case PERIODIC_REPLY_DATA: { + *foundId = PERIODIC_REPLY; + *foundLen = sizeof(PERIODIC_REPLY_DATA); + return RETURN_OK; + break; + } + default: + break; + } + return RETURN_FAILED; +} + +ReturnValue_t DeviceHandlerMock::interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) { + switch (id) { + case SIMPLE_COMMAND: + case PERIODIC_REPLY: { + periodicReplyReceived = true; + break; + } + default: + break; + } + return RETURN_OK; +} + +void DeviceHandlerMock::fillCommandAndReplyMap() { + insertInCommandAndReplyMap(SIMPLE_COMMAND, 0, nullptr, 0, false, false, 0, + &simpleCommandReplyTimeout); + insertInCommandAndReplyMap(PERIODIC_REPLY, 0, nullptr, 0, true, false, 0, + &periodicReplyCountdown); +} + +uint32_t DeviceHandlerMock::getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) { return 500; } + +void DeviceHandlerMock::changePeriodicReplyCountdown(uint32_t timeout) { + periodicReplyCountdown.setTimeout(timeout); +} + +void DeviceHandlerMock::changeSimpleCommandReplyCountdown(uint32_t timeout) { + simpleCommandReplyTimeout.setTimeout(timeout); +} + +void DeviceHandlerMock::resetPeriodicReplyState() { periodicReplyReceived = false; } + +bool DeviceHandlerMock::getPeriodicReplyReceived() { return periodicReplyReceived; } + +ReturnValue_t DeviceHandlerMock::enablePeriodicReply(DeviceCommandId_t replyId) { + return updatePeriodicReply(true, replyId); +} + +ReturnValue_t DeviceHandlerMock::disablePeriodicReply(DeviceCommandId_t replyId) { + return updatePeriodicReply(false, replyId); +} diff --git a/tests/src/fsfw_tests/unit/devicehandler/DeviceHandlerMock.h b/tests/src/fsfw_tests/unit/devicehandler/DeviceHandlerMock.h new file mode 100644 index 00000000..f5fcb4aa --- /dev/null +++ b/tests/src/fsfw_tests/unit/devicehandler/DeviceHandlerMock.h @@ -0,0 +1,46 @@ +#ifndef TESTS_SRC_FSFW_TESTS_UNIT_DEVICEHANDLER_DEVICEHANDLERMOCK_H_ +#define TESTS_SRC_FSFW_TESTS_UNIT_DEVICEHANDLER_DEVICEHANDLERMOCK_H_ + +#include + +class DeviceHandlerMock : public DeviceHandlerBase { + public: + static const DeviceCommandId_t SIMPLE_COMMAND = 1; + static const DeviceCommandId_t PERIODIC_REPLY = 2; + + static const uint8_t SIMPLE_COMMAND_DATA = 1; + static const uint8_t PERIODIC_REPLY_DATA = 2; + + DeviceHandlerMock(object_id_t objectId, object_id_t deviceCommunication, CookieIF *comCookie, + FailureIsolationBase *fdirInstance); + virtual ~DeviceHandlerMock(); + void changePeriodicReplyCountdown(uint32_t timeout); + void changeSimpleCommandReplyCountdown(uint32_t timeout); + void resetPeriodicReplyState(); + bool getPeriodicReplyReceived(); + ReturnValue_t enablePeriodicReply(DeviceCommandId_t replyId); + ReturnValue_t disablePeriodicReply(DeviceCommandId_t replyId); + + protected: + void doStartUp() override; + void doShutDown() override; + ReturnValue_t buildNormalDeviceCommand(DeviceCommandId_t *id) override; + ReturnValue_t buildTransitionDeviceCommand(DeviceCommandId_t *id) override; + ReturnValue_t buildCommandFromCommand(DeviceCommandId_t deviceCommand, const uint8_t *commandData, + size_t commandDataLen) override; + ReturnValue_t scanForReply(const uint8_t *start, size_t len, DeviceCommandId_t *foundId, + size_t *foundLen) override; + ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) override; + void fillCommandAndReplyMap() override; + uint32_t getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) override; + + private: + Countdown simpleCommandReplyTimeout = Countdown(1000); + Countdown periodicReplyCountdown = Countdown(1000); + + uint8_t commandBuffer[1]; + + bool periodicReplyReceived = false; +}; + +#endif /* TESTS_SRC_FSFW_TESTS_UNIT_DEVICEHANDLER_DEVICEHANDLERMOCK_H_ */ diff --git a/tests/src/fsfw_tests/unit/devicehandler/TestDeviceHandlerBase.cpp b/tests/src/fsfw_tests/unit/devicehandler/TestDeviceHandlerBase.cpp new file mode 100644 index 00000000..873329c3 --- /dev/null +++ b/tests/src/fsfw_tests/unit/devicehandler/TestDeviceHandlerBase.cpp @@ -0,0 +1,95 @@ +#include + +#include "ComIFMock.h" +#include "DeviceFdirMock.h" +#include "fsfw_tests/unit/devicehandler/CookieIFMock.h" +#include "fsfw_tests/unit/devicehandler/DeviceHandlerCommander.h" +#include "fsfw_tests/unit/devicehandler/DeviceHandlerMock.h" +#include "fsfw_tests/unit/testcfg/objects/systemObjectList.h" + +TEST_CASE("Device Handler Base", "[DeviceHandlerBase]") { + // Will be deleted with DHB destructor + CookieIFMock* cookieIFMock = new CookieIFMock; + ComIFMock comIF(objects::COM_IF_MOCK); + DeviceFdirMock deviceFdirMock(objects::DEVICE_HANDLER_MOCK, objects::NO_OBJECT); + DeviceHandlerMock deviceHandlerMock(objects::DEVICE_HANDLER_MOCK, objects::COM_IF_MOCK, + cookieIFMock, &deviceFdirMock); + ReturnValue_t result = deviceHandlerMock.initialize(); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + DeviceHandlerCommander deviceHandlerCommander(objects::DEVICE_HANDLER_COMMANDER); + result = deviceHandlerCommander.initialize(); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + + SECTION("Commanding nominal") { + comIF.setTestCase(ComIFMock::TestCase::SIMPLE_COMMAND_NOMINAL); + result = deviceHandlerCommander.sendCommand(objects::DEVICE_HANDLER_MOCK, + DeviceHandlerMock::SIMPLE_COMMAND); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + deviceHandlerMock.performOperation(DeviceHandlerIF::PERFORM_OPERATION); + deviceHandlerMock.performOperation(DeviceHandlerIF::SEND_WRITE); + deviceHandlerMock.performOperation(DeviceHandlerIF::GET_WRITE); + deviceHandlerMock.performOperation(DeviceHandlerIF::SEND_READ); + deviceHandlerMock.performOperation(DeviceHandlerIF::GET_READ); + deviceHandlerCommander.performOperation(); + result = deviceHandlerCommander.getReplyReturnCode(); + uint32_t missedReplies = deviceFdirMock.getMissedReplyCount(); + REQUIRE(missedReplies == 0); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + } + + SECTION("Commanding missed reply") { + comIF.setTestCase(ComIFMock::TestCase::MISSED_REPLY); + deviceHandlerCommander.resetReplyReturnCode(); + // Set the timeout to 0 to immediately timeout the reply + deviceHandlerMock.changeSimpleCommandReplyCountdown(0); + result = deviceHandlerCommander.sendCommand(objects::DEVICE_HANDLER_MOCK, + DeviceHandlerMock::SIMPLE_COMMAND); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + deviceHandlerMock.performOperation(DeviceHandlerIF::PERFORM_OPERATION); + deviceHandlerMock.performOperation(DeviceHandlerIF::SEND_WRITE); + deviceHandlerMock.performOperation(DeviceHandlerIF::GET_WRITE); + deviceHandlerMock.performOperation(DeviceHandlerIF::SEND_READ); + deviceHandlerMock.performOperation(DeviceHandlerIF::GET_READ); + deviceHandlerMock.performOperation(DeviceHandlerIF::PERFORM_OPERATION); + deviceHandlerCommander.performOperation(); + result = deviceHandlerCommander.getReplyReturnCode(); + REQUIRE(result == DeviceHandlerIF::TIMEOUT); + uint32_t missedReplies = deviceFdirMock.getMissedReplyCount(); + REQUIRE(missedReplies == 1); + } + + SECTION("Periodic reply nominal") { + comIF.setTestCase(ComIFMock::TestCase::PERIODIC_REPLY_NOMINAL); + deviceHandlerMock.enablePeriodicReply(DeviceHandlerMock::PERIODIC_REPLY); + deviceHandlerMock.performOperation(DeviceHandlerIF::PERFORM_OPERATION); + deviceHandlerMock.performOperation(DeviceHandlerIF::SEND_WRITE); + deviceHandlerMock.performOperation(DeviceHandlerIF::GET_WRITE); + deviceHandlerMock.performOperation(DeviceHandlerIF::SEND_READ); + deviceHandlerMock.performOperation(DeviceHandlerIF::GET_READ); + REQUIRE(deviceHandlerMock.getPeriodicReplyReceived() == true); + } + + SECTION("Missed periodic reply") { + comIF.setTestCase(ComIFMock::TestCase::MISSED_REPLY); + // Set the timeout to 0 to immediately timeout the reply + deviceHandlerMock.changePeriodicReplyCountdown(0); + deviceHandlerMock.enablePeriodicReply(DeviceHandlerMock::PERIODIC_REPLY); + deviceHandlerMock.performOperation(DeviceHandlerIF::PERFORM_OPERATION); + deviceHandlerMock.performOperation(DeviceHandlerIF::SEND_WRITE); + deviceHandlerMock.performOperation(DeviceHandlerIF::GET_WRITE); + deviceHandlerMock.performOperation(DeviceHandlerIF::SEND_READ); + deviceHandlerMock.performOperation(DeviceHandlerIF::GET_READ); + uint32_t missedReplies = deviceFdirMock.getMissedReplyCount(); + REQUIRE(missedReplies == 1); + // Test if disabling of periodic reply + deviceHandlerMock.disablePeriodicReply(DeviceHandlerMock::PERIODIC_REPLY); + deviceHandlerMock.performOperation(DeviceHandlerIF::PERFORM_OPERATION); + deviceHandlerMock.performOperation(DeviceHandlerIF::SEND_WRITE); + deviceHandlerMock.performOperation(DeviceHandlerIF::GET_WRITE); + deviceHandlerMock.performOperation(DeviceHandlerIF::SEND_READ); + deviceHandlerMock.performOperation(DeviceHandlerIF::GET_READ); + missedReplies = deviceFdirMock.getMissedReplyCount(); + // Should still be 1 because periodic reply is now disabled + REQUIRE(missedReplies == 1); + } +} diff --git a/tests/src/fsfw_tests/unit/hal/testCommandExecutor.cpp b/tests/src/fsfw_tests/unit/hal/testCommandExecutor.cpp index 09d31280..d34f67aa 100644 --- a/tests/src/fsfw_tests/unit/hal/testCommandExecutor.cpp +++ b/tests/src/fsfw_tests/unit/hal/testCommandExecutor.cpp @@ -4,12 +4,12 @@ #include #include -#include "tests/TestsConfig.h" #include "fsfw/container/DynamicFIFO.h" #include "fsfw/container/SimpleRingBuffer.h" #include "fsfw/platform.h" #include "fsfw/serviceinterface.h" #include "fsfw_hal/linux/CommandExecutor.h" +#include "tests/TestsConfig.h" #ifdef PLATFORM_UNIX diff --git a/tests/src/fsfw_tests/unit/storagemanager/TestNewAccessor.cpp b/tests/src/fsfw_tests/unit/storagemanager/TestNewAccessor.cpp index 9631de38..7b90c86e 100644 --- a/tests/src/fsfw_tests/unit/storagemanager/TestNewAccessor.cpp +++ b/tests/src/fsfw_tests/unit/storagemanager/TestNewAccessor.cpp @@ -157,7 +157,7 @@ TEST_CASE("New Accessor", "[NewAccessor]") { } } - SECTION("Operators"){ + SECTION("Operators") { result = SimplePool.addData(&testStoreId, testDataArray.data(), size); REQUIRE(result == retval::CATCH_OK); { @@ -173,13 +173,13 @@ TEST_CASE("New Accessor", "[NewAccessor]") { REQUIRE(result == HasReturnvaluesIF::RETURN_OK); CHECK(accessor2.getId() == testStoreId); CHECK(accessor2.size() == 10); - + std::array newData; // Expect data to be invalid so this must return RETURN_FAILED - result = accessor.getDataCopy(newData.data(),newData.size()); + result = accessor.getDataCopy(newData.data(), newData.size()); REQUIRE(result == HasReturnvaluesIF::RETURN_FAILED); - // Expect data to be too small - result = accessor2.getDataCopy(data.data(),data.size()); + // Expect data to be too small + result = accessor2.getDataCopy(data.data(), data.size()); REQUIRE(result == HasReturnvaluesIF::RETURN_FAILED); } } diff --git a/tests/src/fsfw_tests/unit/storagemanager/TestPool.cpp b/tests/src/fsfw_tests/unit/storagemanager/TestPool.cpp index ce1f8518..51130047 100644 --- a/tests/src/fsfw_tests/unit/storagemanager/TestPool.cpp +++ b/tests/src/fsfw_tests/unit/storagemanager/TestPool.cpp @@ -1,9 +1,9 @@ #include #include +#include #include #include -#include #include "fsfw_tests/unit/CatchDefinitions.h" diff --git a/tests/src/fsfw_tests/unit/testcfg/objects/systemObjectList.h b/tests/src/fsfw_tests/unit/testcfg/objects/systemObjectList.h index 3fcd8368..17b980e9 100644 --- a/tests/src/fsfw_tests/unit/testcfg/objects/systemObjectList.h +++ b/tests/src/fsfw_tests/unit/testcfg/objects/systemObjectList.h @@ -1,30 +1,34 @@ -#ifndef HOSTED_CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_ -#define HOSTED_CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_ - -#include - -#include "fsfw/objectmanager/frameworkObjects.h" - -// 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, - - UDP_BRIDGE = 15, - UDP_POLLING_TASK = 16, - - TEST_ECHO_COM_IF = 20, - TEST_DEVICE = 21, - - HK_RECEIVER_MOCK = 22, - TEST_LOCAL_POOL_OWNER_BASE = 25, - - SHARED_SET_ID = 26, - - DUMMY_POWER_SWITCHER = 27 -}; -} - -#endif /* BSP_CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_ */ +#ifndef HOSTED_CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_ +#define HOSTED_CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_ + +#include + +#include "fsfw/objectmanager/frameworkObjects.h" + +// 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, + + UDP_BRIDGE = 15, + UDP_POLLING_TASK = 16, + + TEST_ECHO_COM_IF = 20, + TEST_DEVICE = 21, + + HK_RECEIVER_MOCK = 22, + TEST_LOCAL_POOL_OWNER_BASE = 25, + + SHARED_SET_ID = 26, + + DUMMY_POWER_SWITCHER = 28, + + DEVICE_HANDLER_MOCK = 29, + COM_IF_MOCK = 30, + DEVICE_HANDLER_COMMANDER = 40, +}; +} + +#endif /* BSP_CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_ */