diff --git a/CHANGELOG.md b/CHANGELOG.md index f3eb6942..9685b37d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - `oneShotAction` flag in the `TestTask` class is not static anymore - HAL Linux Uart: Baudrate and bits per word are enums now, avoiding misconfigurations PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/585 +- IPC Message Queue Handling: Allow passing an optional `MqArgs` argument into the MessageQueue + creation call. It allows passing context information and an arbitrary user argument into + the message queue. Also streamlined and simplified `MessageQueue` implementation for all OSALs + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/583 ## Removed @@ -37,6 +41,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Dedicated Version class and constant `fsfw::FSFW_VERSION` containing version information inside `fsfw/version.h` PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/559 +- Added ETL dependency and improved library dependency management + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/592 + +## Fixed + +- Small bugfix in STM32 HAL for SPI + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/599 # [v4.0.0] diff --git a/CMakeLists.txt b/CMakeLists.txt index 7ef11493..d8ca812e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,22 @@ set(FSFW_REVISION 0) # Add the cmake folder so the FindSphinx module is found set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) +set(FSFW_ETL_LIB_MAJOR_VERSION 20 CACHE STRING + "ETL library major version requirement" +) +set(FSFW_ETL_LIB_VERSION ${FSFW_ETL_LIB_MAJOR_VERSION}.27.2 CACHE STRING + "ETL library exact version requirement" +) + +set(FSFW_CATCH2_LIB_MAJOR_VERSION 3 CACHE STRING + "Catch2 library major version requirement" +) +set(FSFW_CATCH2_LIB_VERSION v${FSFW_CATCH2_LIB_MAJOR_VERSION}.0.0-preview4 CACHE STRING + "Catch2 library exact version requirement" +) + +set(FSFW_ETL_LIB_NAME etl) + option(FSFW_GENERATE_SECTIONS "Generate function and data sections. Required to remove unused code" ON ) @@ -48,7 +64,7 @@ add_library(${LIB_FSFW_NAME}) if(FSFW_BUILD_UNITTESTS) message(STATUS "Building the FSFW unittests in addition to the static library") # Check whether the user has already installed Catch2 first - find_package(Catch2 3 QUIET) + find_package(Catch2 ${FSFW_CATCH2_LIB_MAJOR_VERSION}) # Not installed, so use FetchContent to download and provide Catch2 if(NOT Catch2_FOUND) message(STATUS "Catch2 installation not found. Downloading Catch2 library with FetchContent") @@ -57,7 +73,7 @@ if(FSFW_BUILD_UNITTESTS) FetchContent_Declare( Catch2 GIT_REPOSITORY https://github.com/catchorg/Catch2.git - GIT_TAG v3.0.0-preview4 + GIT_TAG ${FSFW_CATCH2_LIB_VERSION} ) FetchContent_MakeAvailable(Catch2) @@ -89,6 +105,27 @@ if(FSFW_BUILD_UNITTESTS) endif() endif() +message(STATUS "Finding and/or providing ETL library") + +# Check whether the user has already installed ETL first +find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} QUIET) +# Not installed, so use FetchContent to download and provide etl +if(NOT ${FSFW_ETL_LIB_NAME}_FOUND) + message(STATUS + "No ETL installation was found with find_package. Installing and providing " + "etl with FindPackage" + ) + include(FetchContent) + + FetchContent_Declare( + ${FSFW_ETL_LIB_NAME} + GIT_REPOSITORY https://github.com/ETLCPP/etl + GIT_TAG ${FSFW_ETL_LIB_VERSION} + ) + + FetchContent_MakeAvailable(etl) +endif() + set(FSFW_CORE_INC_PATH "inc") set_property(CACHE FSFW_OSAL PROPERTY STRINGS host linux rtems freertos) @@ -350,6 +387,7 @@ target_compile_options(${LIB_FSFW_NAME} PRIVATE ) target_link_libraries(${LIB_FSFW_NAME} PRIVATE + ${FSFW_ETL_LIB_NAME} ${FSFW_ADDITIONAL_LINK_LIBS} ) diff --git a/README.md b/README.md index dff87b2e..99c842af 100644 --- a/README.md +++ b/README.md @@ -11,9 +11,15 @@ with Airbus Defence and Space GmbH. ## Quick facts -The framework is designed for systems, which communicate with external devices, perform control loops, receive telecommands and send telemetry, and need to maintain a high level of availability. Therefore, a mode and health system provides control over the states of the software and the controlled devices. In addition, a simple mechanism of event based fault detection, isolation and recovery is implemented as well. +The framework is designed for systems, which communicate with external devices, perform control loops, +receive telecommands and send telemetry, and need to maintain a high level of availability. Therefore, +a mode and health system provides control over the states of the software and the controlled devices. +In addition, a simple mechanism of event based fault detection, isolation and recovery is implemented as well. -The FSFW provides abstraction layers for operating systems to provide a uniform operating system abstraction layer (OSAL). Some components of this OSAL are required internally by the FSFW but is also very useful for developers to implement the same application logic on different operating systems with a uniform interface. +The FSFW provides abstraction layers for operating systems to provide a uniform operating system +abstraction layer (OSAL). Some components of this OSAL are required internally by the FSFW but is +also very useful for developers to implement the same application logic on different operating +systems with a uniform interface. Currently, the FSFW provides the following OSALs: @@ -45,6 +51,28 @@ A template configuration folder was provided and can be copied into the project a starting point. The [configuration section](docs/README-config.md#top) provides more specific information about the possible options. +## Prerequisites + +The Embedded Template Library (etl) is a dependency of the FSFW which is automatically +installed and provided by the build system unless the correction version was installed. +The current recommended version can be found inside the fsfw `CMakeLists.txt` file or by using +`ccmake` and looking up the `FSFW_ETL_LIB_MAJOR_VERSION` variable. + +You can install the ETL library like this. On Linux, it might be necessary to add `sudo` before +the install call: + +```cpp +git clone https://github.com/ETLCPP/etl +cd etl +git checkout +mkdir build && cd build +cmake .. +cmake --install . +``` + +It is recommended to install `20.27.2` or newer for the package version handling of +ETL to work. + ## Adding the library The following steps show how to add and use FSFW components. It is still recommended to @@ -83,6 +111,19 @@ The FSFW also has unittests which use the [Catch2 library](https://github.com/ca These are built by setting the CMake option `FSFW_BUILD_UNITTESTS` to `ON` or `TRUE` from your project `CMakeLists.txt` file or from the command line. +You can install the Catch2 library, which prevents the build system to avoid re-downloading +the dependency if the unit tests are completely rebuilt. The current recommended version +can be found inside the fsfw `CMakeLists.txt` file or by using `ccmake` and looking up +the `FSFW_CATCH2_LIB_VERSION` variable. + +```sh +git clone https://github.com/catchorg/Catch2.git +cd Catch2 +git checkout +cmake -Bbuild -H. -DBUILD_TESTING=OFF +sudo cmake --build build/ --target install +``` + The fsfw-tests binary will be built as part of the static library and dropped alongside it. If the unittests are built, the library and the tests will be built with coverage information by default. This can be disabled by setting the `FSFW_TESTS_COV_GEN` option to `OFF` or `FALSE`. diff --git a/docs/getting_started.rst b/docs/getting_started.rst index 34547211..01724b3a 100644 --- a/docs/getting_started.rst +++ b/docs/getting_started.rst @@ -19,6 +19,29 @@ A template configuration folder was provided and can be copied into the project a starting point. The [configuration section](docs/README-config.md#top) provides more specific information about the possible options. +Prerequisites +------------------- + +The Embedded Template Library (etl) is a dependency of the FSFW which is automatically +installed and provided by the build system unless the correction version was installed. +The current recommended version can be found inside the fsfw ``CMakeLists.txt`` file or by using +``ccmake`` and looking up the ``FSFW_ETL_LIB_MAJOR_VERSION`` variable. + +You can install the ETL library like this. On Linux, it might be necessary to add ``sudo`` before +the install call: + +.. code-block:: console + + git clone https://github.com/ETLCPP/etl + cd etl + git checkout + mkdir build && cd build + cmake .. + cmake --install . + +It is recommended to install ``20.27.2`` or newer for the package version handling of +ETL to work. + Adding the library ------------------- @@ -60,6 +83,20 @@ The FSFW also has unittests which use the `Catch2 library`_. These are built by setting the CMake option ``FSFW_BUILD_UNITTESTS`` to ``ON`` or `TRUE` from your project `CMakeLists.txt` file or from the command line. +You can install the Catch2 library, which prevents the build system to avoid re-downloading +the dependency if the unit tests are completely rebuilt. The current recommended version +can be found inside the fsfw ``CMakeLists.txt`` file or by using ``ccmake`` and looking up +the ``FSFW_CATCH2_LIB_VERSION`` variable. + +.. code-block:: console + + git clone https://github.com/catchorg/Catch2.git + cd Catch2 + git checkout + cmake -Bbuild -H. -DBUILD_TESTING=OFF + sudo cmake --build build/ --target install + + The fsfw-tests binary will be built as part of the static library and dropped alongside it. If the unittests are built, the library and the tests will be built with coverage information by default. This can be disabled by setting the `FSFW_TESTS_COV_GEN` option to `OFF` or `FALSE`. diff --git a/hal/src/fsfw_hal/stm32h7/spi/mspInit.h b/hal/src/fsfw_hal/stm32h7/spi/mspInit.h index 00c68017..f0658fb9 100644 --- a/hal/src/fsfw_hal/stm32h7/spi/mspInit.h +++ b/hal/src/fsfw_hal/stm32h7/spi/mspInit.h @@ -21,7 +21,7 @@ using mspCb = void (*)(void); namespace spi { struct MspCfgBase { - MspCfgBase(); + MspCfgBase() {} MspCfgBase(stm32h7::GpioCfg sck, stm32h7::GpioCfg mosi, stm32h7::GpioCfg miso, mspCb cleanupCb = nullptr, mspCb setupCb = nullptr) : sck(sck), mosi(mosi), miso(miso), cleanupCb(cleanupCb), setupCb(setupCb) {} diff --git a/src/fsfw/datapoollocal/LocalDataPoolManager.cpp b/src/fsfw/datapoollocal/LocalDataPoolManager.cpp index acfa23c5..6053bd43 100644 --- a/src/fsfw/datapoollocal/LocalDataPoolManager.cpp +++ b/src/fsfw/datapoollocal/LocalDataPoolManager.cpp @@ -787,6 +787,10 @@ ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid, bool i // Serialize set packet into store. size_t size = 0; result = setPacket.serialize(&storePtr, &size, expectedSize, SerializeIF::Endianness::BIG); + if(result != HasReturnvaluesIF::RETURN_OK) { + ipcStore->deleteData(storeId); + return result; + } if (expectedSize != size) { printWarningOrError(sif::OutputTypes::OUT_WARNING, "generateSetStructurePacket", HasReturnvaluesIF::RETURN_FAILED, @@ -801,7 +805,10 @@ ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid, bool i HousekeepingMessage::setHkStuctureReportReply(&reply, sid, storeId); } - hkQueue->reply(&reply); + result = hkQueue->reply(&reply); + if(result != HasReturnvaluesIF::RETURN_OK) { + ipcStore->deleteData(storeId); + } return result; } diff --git a/src/fsfw/ipc/CMakeLists.txt b/src/fsfw/ipc/CMakeLists.txt index 6a3afe33..3bfe510d 100644 --- a/src/fsfw/ipc/CMakeLists.txt +++ b/src/fsfw/ipc/CMakeLists.txt @@ -1,6 +1,6 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - CommandMessage.cpp - CommandMessageCleaner.cpp - MessageQueueMessage.cpp +target_sources(${LIB_FSFW_NAME} PRIVATE + CommandMessage.cpp + CommandMessageCleaner.cpp + MessageQueueMessage.cpp + MessageQueueBase.cpp ) \ No newline at end of file diff --git a/src/fsfw/ipc/MessageQueueBase.cpp b/src/fsfw/ipc/MessageQueueBase.cpp new file mode 100644 index 00000000..1b0934ff --- /dev/null +++ b/src/fsfw/ipc/MessageQueueBase.cpp @@ -0,0 +1,64 @@ +#include "MessageQueueBase.h" + +MessageQueueBase::MessageQueueBase(MessageQueueId_t id, MessageQueueId_t defaultDest, + MqArgs* args): id(id) { + this->defaultDest = defaultDest; + if(args != nullptr) { + this->args = *args; + } +} + +MessageQueueBase::~MessageQueueBase() {} + +ReturnValue_t MessageQueueBase::sendToDefault(MessageQueueMessageIF* message) { + return sendToDefaultFrom(message, this->getId(), false); +} + +ReturnValue_t MessageQueueBase::reply(MessageQueueMessageIF* message) { + if (this->last != MessageQueueIF::NO_QUEUE) { + return sendMessageFrom(this->last, message, this->getId()); + } else { + return NO_REPLY_PARTNER; + } +} + +ReturnValue_t MessageQueueBase::receiveMessage(MessageQueueMessageIF* message, + MessageQueueId_t* receivedFrom) { + ReturnValue_t status = this->receiveMessage(message); + *receivedFrom = this->last; + return status; +} + +MessageQueueId_t MessageQueueBase::getLastPartner() const { + return last; +} + +MessageQueueId_t MessageQueueBase::getId() const { + return id; +} + +MqArgs& MessageQueueBase::getMqArgs() { + return args; +} + +void MessageQueueBase::setDefaultDestination(MessageQueueId_t defaultDestination) { + this->defaultDest = defaultDestination; +} + +MessageQueueId_t MessageQueueBase::getDefaultDestination() const { + return defaultDest; +} + +bool MessageQueueBase::isDefaultDestinationSet() const { + return (defaultDest != NO_QUEUE); +} + +ReturnValue_t MessageQueueBase::sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message, + bool ignoreFault) { + return sendMessageFrom(sendTo, message, this->getId(), false); +} + +ReturnValue_t MessageQueueBase::sendToDefaultFrom(MessageQueueMessageIF* message, + MessageQueueId_t sentFrom, bool ignoreFault) { + return sendMessageFrom(defaultDest, message, sentFrom, ignoreFault); +} diff --git a/src/fsfw/ipc/MessageQueueBase.h b/src/fsfw/ipc/MessageQueueBase.h new file mode 100644 index 00000000..8313f69a --- /dev/null +++ b/src/fsfw/ipc/MessageQueueBase.h @@ -0,0 +1,41 @@ +#ifndef FSFW_SRC_FSFW_IPC_MESSAGEQUEUEBASE_H_ +#define FSFW_SRC_FSFW_IPC_MESSAGEQUEUEBASE_H_ + +#include +#include + +class MessageQueueBase: public MessageQueueIF { +public: + MessageQueueBase(MessageQueueId_t id, MessageQueueId_t defaultDest, MqArgs* mqArgs); + virtual ~MessageQueueBase(); + + // Default implementations for MessageQueueIF where possible + virtual MessageQueueId_t getLastPartner() const override; + virtual MessageQueueId_t getId() const override; + virtual MqArgs& getMqArgs() override; + virtual void setDefaultDestination(MessageQueueId_t defaultDestination) override; + virtual MessageQueueId_t getDefaultDestination() const override; + virtual bool isDefaultDestinationSet() const override; + virtual ReturnValue_t sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message, + bool ignoreFault) override; + virtual ReturnValue_t sendToDefault(MessageQueueMessageIF* message) override; + virtual ReturnValue_t reply(MessageQueueMessageIF* message) override; + virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message, + MessageQueueId_t* receivedFrom) override; + virtual ReturnValue_t sendToDefaultFrom(MessageQueueMessageIF* message, + MessageQueueId_t sentFrom, bool ignoreFault = false) override; + + // OSAL specific, forward the abstract function + virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message) = 0; + virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message, + MessageQueueId_t sentFrom, bool ignoreFault = false) = 0; +protected: + MessageQueueId_t id = MessageQueueIF::NO_QUEUE; + MessageQueueId_t last = MessageQueueIF::NO_QUEUE; + MessageQueueId_t defaultDest = MessageQueueIF::NO_QUEUE; + MqArgs args = {}; +}; + + + +#endif /* FSFW_SRC_FSFW_IPC_MESSAGEQUEUEBASE_H_ */ diff --git a/src/fsfw/ipc/MessageQueueIF.h b/src/fsfw/ipc/MessageQueueIF.h index 9aef58b7..d7b6889b 100644 --- a/src/fsfw/ipc/MessageQueueIF.h +++ b/src/fsfw/ipc/MessageQueueIF.h @@ -1,6 +1,7 @@ #ifndef FSFW_IPC_MESSAGEQUEUEIF_H_ #define FSFW_IPC_MESSAGEQUEUEIF_H_ +#include #include #include "../returnvalues/HasReturnvaluesIF.h" @@ -44,8 +45,7 @@ class MessageQueueIF { virtual ReturnValue_t reply(MessageQueueMessageIF* message) = 0; /** - * @brief This function reads available messages from the message queue - * and returns the sender. + * @brief This function reads available messages from the message queue and returns the sender. * @details * It works identically to the other receiveMessage call, but in addition * returns the sender's queue id. @@ -78,19 +78,16 @@ class MessageQueueIF { */ virtual ReturnValue_t flush(uint32_t* count) = 0; /** - * @brief This method returns the message queue - * id of the last communication partner. + * @brief This method returns the message queue ID of the last communication partner. */ virtual MessageQueueId_t getLastPartner() const = 0; /** - * @brief This method returns the message queue - * id of this class's message queue. + * @brief This method returns the message queue ID of this class's message queue. */ virtual MessageQueueId_t getId() const = 0; /** - * @brief With the sendMessage call, a queue message - * is sent to a receiving queue. + * @brief With the sendMessage call, a queue message is sent to a receiving queue. * @details * This method takes the message provided, adds the sentFrom information * and passes it on to the destination provided with an operating system @@ -129,8 +126,7 @@ class MessageQueueIF { bool ignoreFault = false) = 0; /** - * @brief The sendToDefaultFrom method sends a queue message - * to the default destination. + * @brief The sendToDefaultFrom method sends a queue message to the default destination. * @details * In all other aspects, it works identical to the sendMessage method. * @param message @@ -164,6 +160,8 @@ class MessageQueueIF { virtual MessageQueueId_t getDefaultDestination() const = 0; virtual bool isDefaultDestinationSet() const = 0; + + virtual MqArgs& getMqArgs() = 0; }; #endif /* FSFW_IPC_MESSAGEQUEUEIF_H_ */ diff --git a/src/fsfw/ipc/QueueFactory.h b/src/fsfw/ipc/QueueFactory.h index 864c456d..8069d836 100644 --- a/src/fsfw/ipc/QueueFactory.h +++ b/src/fsfw/ipc/QueueFactory.h @@ -5,6 +5,7 @@ #include "MessageQueueIF.h" #include "MessageQueueMessage.h" +#include "definitions.h" /** * Creates message queues. @@ -22,7 +23,8 @@ class QueueFactory { static QueueFactory* instance(); MessageQueueIF* createMessageQueue(uint32_t messageDepth = 3, - size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE); + size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE, + MqArgs* args = nullptr); void deleteMessageQueue(MessageQueueIF* queue); diff --git a/src/fsfw/ipc/definitions.h b/src/fsfw/ipc/definitions.h new file mode 100644 index 00000000..150502bb --- /dev/null +++ b/src/fsfw/ipc/definitions.h @@ -0,0 +1,14 @@ +#ifndef FSFW_SRC_FSFW_IPC_DEFINITIONS_H_ +#define FSFW_SRC_FSFW_IPC_DEFINITIONS_H_ + +#include +#include + +struct MqArgs { + MqArgs(){}; + MqArgs(object_id_t objectId, void* args = nullptr) : objectId(objectId), args(args) {} + object_id_t objectId = objects::NO_OBJECT; + void* args = nullptr; +}; + +#endif /* FSFW_SRC_FSFW_IPC_DEFINITIONS_H_ */ diff --git a/src/fsfw/osal/freertos/MessageQueue.cpp b/src/fsfw/osal/freertos/MessageQueue.cpp index a8333fe5..d1a7f691 100644 --- a/src/fsfw/osal/freertos/MessageQueue.cpp +++ b/src/fsfw/osal/freertos/MessageQueue.cpp @@ -4,8 +4,9 @@ #include "fsfw/osal/freertos/QueueMapManager.h" #include "fsfw/serviceinterface/ServiceInterface.h" -MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize) - : maxMessageSize(maxMessageSize) { +MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize, MqArgs* args) + : MessageQueueBase(MessageQueueIF::NO_QUEUE, MessageQueueIF::NO_QUEUE, args), + maxMessageSize(maxMessageSize) { handle = xQueueCreate(messageDepth, maxMessageSize); if (handle == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 @@ -15,10 +16,10 @@ MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize) #else sif::printError("MessageQueue::MessageQueue: Creation failed\n"); sif::printError("Specified Message Depth: %d\n", messageDepth); - sif::printError("Specified MAximum Message Size: %d\n", maxMessageSize); + sif::printError("Specified Maximum Message Size: %d\n", maxMessageSize); #endif } - QueueMapManager::instance()->addMessageQueue(handle, &queueId); + QueueMapManager::instance()->addMessageQueue(handle, &id); } MessageQueue::~MessageQueue() { @@ -29,28 +30,6 @@ MessageQueue::~MessageQueue() { void MessageQueue::switchSystemContext(CallContext callContext) { this->callContext = callContext; } -ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message, - bool ignoreFault) { - return sendMessageFrom(sendTo, message, this->getId(), ignoreFault); -} - -ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessageIF* message) { - return sendToDefaultFrom(message, this->getId()); -} - -ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message, - MessageQueueId_t sentFrom, bool ignoreFault) { - return sendMessageFrom(defaultDestination, message, sentFrom, ignoreFault); -} - -ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) { - if (this->lastPartner != MessageQueueIF::NO_QUEUE) { - return sendMessageFrom(this->lastPartner, message, this->getId()); - } else { - return NO_REPLY_PARTNER; - } -} - ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message, MessageQueueId_t sentFrom, bool ignoreFault) { return sendMessageFromMessageQueue(sendTo, message, sentFrom, ignoreFault, callContext); @@ -72,27 +51,16 @@ ReturnValue_t MessageQueue::handleSendResult(BaseType_t result, bool ignoreFault return HasReturnvaluesIF::RETURN_OK; } -ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message, - MessageQueueId_t* receivedFrom) { - ReturnValue_t status = this->receiveMessage(message); - if (status == HasReturnvaluesIF::RETURN_OK) { - *receivedFrom = this->lastPartner; - } - return status; -} - ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) { BaseType_t result = xQueueReceive(handle, reinterpret_cast(message->getBuffer()), 0); if (result == pdPASS) { - this->lastPartner = message->getSender(); + this->last = message->getSender(); return HasReturnvaluesIF::RETURN_OK; } else { return MessageQueueIF::EMPTY; } } -MessageQueueId_t MessageQueue::getLastPartner() const { return lastPartner; } - ReturnValue_t MessageQueue::flush(uint32_t* count) { // TODO FreeRTOS does not support flushing partially // Is always successful @@ -100,17 +68,6 @@ ReturnValue_t MessageQueue::flush(uint32_t* count) { return HasReturnvaluesIF::RETURN_OK; } -MessageQueueId_t MessageQueue::getId() const { return queueId; } - -void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) { - defaultDestinationSet = true; - this->defaultDestination = defaultDestination; -} - -MessageQueueId_t MessageQueue::getDefaultDestination() const { return defaultDestination; } - -bool MessageQueue::isDefaultDestinationSet() const { return defaultDestinationSet; } - // static core function to send messages. ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, MessageQueueMessageIF* message, diff --git a/src/fsfw/osal/freertos/MessageQueue.h b/src/fsfw/osal/freertos/MessageQueue.h index 1cb343d1..00dfea68 100644 --- a/src/fsfw/osal/freertos/MessageQueue.h +++ b/src/fsfw/osal/freertos/MessageQueue.h @@ -1,12 +1,14 @@ #ifndef FSFW_OSAL_FREERTOS_MESSAGEQUEUE_H_ #define FSFW_OSAL_FREERTOS_MESSAGEQUEUE_H_ +#include #include "FreeRTOS.h" #include "TaskManagement.h" #include "fsfw/internalerror/InternalErrorReporterIF.h" #include "fsfw/ipc/MessageQueueIF.h" #include "fsfw/ipc/MessageQueueMessage.h" #include "fsfw/ipc/MessageQueueMessageIF.h" +#include "fsfw/ipc/definitions.h" #include "queue.h" /** @@ -32,7 +34,7 @@ * @ingroup osal * @ingroup message_queue */ -class MessageQueue : public MessageQueueIF { +class MessageQueue : public MessageQueueBase { friend class MessageQueueSenderIF; public: @@ -53,7 +55,8 @@ class MessageQueue : public MessageQueueIF { * This should be left default. */ MessageQueue(size_t messageDepth = 3, - size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE); + size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE, + MqArgs* args = nullptr); /** Copying message queues forbidden */ MessageQueue(const MessageQueue&) = delete; @@ -73,40 +76,15 @@ class MessageQueue : public MessageQueueIF { */ void switchSystemContext(CallContext callContext); - /** MessageQueueIF implementation */ - ReturnValue_t sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message, - bool ignoreFault = false) override; + QueueHandle_t getNativeQueueHandle(); - ReturnValue_t sendToDefault(MessageQueueMessageIF* message) override; - - ReturnValue_t reply(MessageQueueMessageIF* message) override; + // Implement non-generic MessageQueueIF functions not handled by MessageQueueBase virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false) override; - - virtual ReturnValue_t sendToDefaultFrom(MessageQueueMessageIF* message, - MessageQueueId_t sentFrom = NO_QUEUE, - bool ignoreFault = false) override; - - ReturnValue_t receiveMessage(MessageQueueMessageIF* message, - MessageQueueId_t* receivedFrom) override; - ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override; - ReturnValue_t flush(uint32_t* count) override; - MessageQueueId_t getLastPartner() const override; - - MessageQueueId_t getId() const override; - - void setDefaultDestination(MessageQueueId_t defaultDestination) override; - - MessageQueueId_t getDefaultDestination() const override; - - bool isDefaultDestinationSet() const override; - - QueueHandle_t getNativeQueueHandle(); - protected: /** * @brief Implementation to be called from any send Call within @@ -136,12 +114,8 @@ class MessageQueue : public MessageQueueIF { static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault); private: - bool defaultDestinationSet = false; QueueHandle_t handle; - MessageQueueId_t queueId = MessageQueueIF::NO_QUEUE; - MessageQueueId_t defaultDestination = MessageQueueIF::NO_QUEUE; - MessageQueueId_t lastPartner = MessageQueueIF::NO_QUEUE; const size_t maxMessageSize; //! Stores the current system context CallContext callContext = CallContext::TASK; diff --git a/src/fsfw/osal/freertos/QueueFactory.cpp b/src/fsfw/osal/freertos/QueueFactory.cpp index f4941481..8424123c 100644 --- a/src/fsfw/osal/freertos/QueueFactory.cpp +++ b/src/fsfw/osal/freertos/QueueFactory.cpp @@ -22,8 +22,9 @@ QueueFactory::QueueFactory() {} QueueFactory::~QueueFactory() {} -MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize) { - return new MessageQueue(messageDepth, maxMessageSize); +MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize, + MqArgs* args) { + return new MessageQueue(messageDepth, maxMessageSize, args); } void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { delete queue; } diff --git a/src/fsfw/osal/host/MessageQueue.cpp b/src/fsfw/osal/host/MessageQueue.cpp index d328fb82..d0a12850 100644 --- a/src/fsfw/osal/host/MessageQueue.cpp +++ b/src/fsfw/osal/host/MessageQueue.cpp @@ -8,10 +8,12 @@ #include "fsfw/osal/host/QueueMapManager.h" #include "fsfw/serviceinterface/ServiceInterface.h" -MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize) - : messageSize(maxMessageSize), messageDepth(messageDepth) { +MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize, MqArgs* args) + : MessageQueueBase(MessageQueueIF::NO_QUEUE, MessageQueueIF::NO_QUEUE, args), + messageSize(maxMessageSize), + messageDepth(messageDepth) { queueLock = MutexFactory::instance()->createMutex(); - auto result = QueueMapManager::instance()->addMessageQueue(this, &mqId); + auto result = QueueMapManager::instance()->addMessageQueue(this, &id); if (result != HasReturnvaluesIF::RETURN_OK) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "MessageQueue::MessageQueue: Could not be created" << std::endl; @@ -23,42 +25,11 @@ MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize) MessageQueue::~MessageQueue() { MutexFactory::instance()->deleteMutex(queueLock); } -ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message, - bool ignoreFault) { - return sendMessageFrom(sendTo, message, this->getId(), ignoreFault); -} - -ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessageIF* message) { - return sendToDefaultFrom(message, this->getId()); -} - -ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message, - MessageQueueId_t sentFrom, bool ignoreFault) { - return sendMessageFrom(defaultDestination, message, sentFrom, ignoreFault); -} - -ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) { - if (this->lastPartner != MessageQueueIF::NO_QUEUE) { - return sendMessageFrom(this->lastPartner, message, this->getId()); - } else { - return MessageQueueIF::NO_REPLY_PARTNER; - } -} - ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message, MessageQueueId_t sentFrom, bool ignoreFault) { return sendMessageFromMessageQueue(sendTo, message, sentFrom, ignoreFault); } -ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message, - MessageQueueId_t* receivedFrom) { - ReturnValue_t status = this->receiveMessage(message); - if (status == HasReturnvaluesIF::RETURN_OK) { - *receivedFrom = this->lastPartner; - } - return status; -} - ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) { if (messageQueue.empty()) { return MessageQueueIF::EMPTY; @@ -68,12 +39,10 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) { message->getBuffer()); messageQueue.pop(); // The last partner is the first uint32_t field in the message - this->lastPartner = message->getSender(); + this->last = message->getSender(); return HasReturnvaluesIF::RETURN_OK; } -MessageQueueId_t MessageQueue::getLastPartner() const { return lastPartner; } - ReturnValue_t MessageQueue::flush(uint32_t* count) { *count = messageQueue.size(); // Clears the queue. @@ -81,17 +50,6 @@ ReturnValue_t MessageQueue::flush(uint32_t* count) { return HasReturnvaluesIF::RETURN_OK; } -MessageQueueId_t MessageQueue::getId() const { return mqId; } - -void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) { - defaultDestinationSet = true; - this->defaultDestination = defaultDestination; -} - -MessageQueueId_t MessageQueue::getDefaultDestination() const { return defaultDestination; } - -bool MessageQueue::isDefaultDestinationSet() const { return defaultDestinationSet; } - // static core function to send messages. ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, MessageQueueMessageIF* message, diff --git a/src/fsfw/osal/host/MessageQueue.h b/src/fsfw/osal/host/MessageQueue.h index 49375bb5..bb4f26a1 100644 --- a/src/fsfw/osal/host/MessageQueue.h +++ b/src/fsfw/osal/host/MessageQueue.h @@ -1,15 +1,17 @@ #ifndef FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_ #define FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_ -#include -#include - +#include "fsfw/ipc/MessageQueueBase.h" #include "fsfw/internalerror/InternalErrorReporterIF.h" #include "fsfw/ipc/MessageQueueIF.h" #include "fsfw/ipc/MessageQueueMessage.h" #include "fsfw/ipc/MutexIF.h" +#include "fsfw/ipc/definitions.h" #include "fsfw/timemanager/Clock.h" +#include +#include + /** * @brief This class manages sending and receiving of * message queue messages. @@ -33,7 +35,7 @@ * @ingroup osal * @ingroup message_queue */ -class MessageQueue : public MessageQueueIF { +class MessageQueue : public MessageQueueBase { friend class MessageQueueSenderIF; public: @@ -54,7 +56,8 @@ class MessageQueue : public MessageQueueIF { * This should be left default. */ MessageQueue(size_t messageDepth = 3, - size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE); + size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE, + MqArgs* args = nullptr); /** Copying message queues forbidden */ MessageQueue(const MessageQueue&) = delete; @@ -67,121 +70,12 @@ class MessageQueue : public MessageQueueIF { */ virtual ~MessageQueue(); - /** - * @brief This operation sends a message to the given destination. - * @details It directly uses the sendMessage call of the MessageQueueSender - * parent, but passes its queue id as "sentFrom" parameter. - * @param sendTo This parameter specifies the message queue id of the - * destination message queue. - * @param message A pointer to a previously created message, which is sent. - * @param ignoreFault If set to true, the internal software fault counter - * is not incremented if queue is full. - */ - ReturnValue_t sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message, - bool ignoreFault = false) override; - /** - * @brief This operation sends a message to the default destination. - * @details As in the sendMessage method, this function uses the - * sendToDefault call of the MessageQueueSender parent class and adds its - * queue id as "sentFrom" information. - * @param message A pointer to a previously created message, which is sent. - */ - ReturnValue_t sendToDefault(MessageQueueMessageIF* message) override; - /** - * @brief This operation sends a message to the last communication partner. - * @details This operation simplifies answering an incoming message by using - * the stored lastPartner information as destination. If there was no - * message received yet (i.e. lastPartner is zero), an error code is returned. - * @param message A pointer to a previously created message, which is sent. - */ - ReturnValue_t reply(MessageQueueMessageIF* message) override; - - /** - * @brief With the sendMessage call, a queue message is sent to a - * receiving queue. - * @details - * This method takes the message provided, adds the sentFrom information and - * passes it on to the destination provided with an operating system call. - * The OS's return value is returned. - * @param sendTo This parameter specifies the message queue id to send - * the message to. - * @param message This is a pointer to a previously created message, - * which is sent. - * @param sentFrom The sentFrom information can be set to inject the - * sender's queue id into the message. This variable is set to zero by - * default. - * @param ignoreFault If set to true, the internal software fault counter - * is not incremented if queue is full. - */ + // Implement non-generic MessageQueueIF functions not handled by MessageQueueBase virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false) override; - - /** - * @brief The sendToDefault method sends a queue message to the default - * destination. - * @details - * In all other aspects, it works identical to the sendMessage method. - * @param message This is a pointer to a previously created message, - * which is sent. - * @param sentFrom The sentFrom information can be set to inject the - * sender's queue id into the message. This variable is set to zero by - * default. - */ - virtual ReturnValue_t sendToDefaultFrom(MessageQueueMessageIF* message, - MessageQueueId_t sentFrom = NO_QUEUE, - bool ignoreFault = false) override; - - /** - * @brief This function reads available messages from the message queue - * and returns the sender. - * @details - * It works identically to the other receiveMessage call, but in addition - * returns the sender's queue id. - * @param message A pointer to a message in which the received data is stored. - * @param receivedFrom A pointer to a queue id in which the sender's id is stored. - */ - ReturnValue_t receiveMessage(MessageQueueMessageIF* message, - MessageQueueId_t* receivedFrom) override; - - /** - * @brief This function reads available messages from the message queue. - * @details - * If data is available it is stored in the passed message pointer. - * The message's original content is overwritten and the sendFrom - * information is stored in the lastPartner attribute. Else, the lastPartner - * information remains untouched, the message's content is cleared and the - * function returns immediately. - * @param message A pointer to a message in which the received data is stored. - */ ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override; - /** - * Deletes all pending messages in the queue. - * @param count The number of flushed messages. - * @return RETURN_OK on success. - */ ReturnValue_t flush(uint32_t* count) override; - /** - * @brief This method returns the message queue id of the last - * communication partner. - */ - MessageQueueId_t getLastPartner() const override; - /** - * @brief This method returns the message queue id of this class's - * message queue. - */ - MessageQueueId_t getId() const override; - - /** - * @brief This method is a simple setter for the default destination. - */ - void setDefaultDestination(MessageQueueId_t defaultDestination) override; - /** - * @brief This method is a simple getter for the default destination. - */ - MessageQueueId_t getDefaultDestination() const override; - - bool isDefaultDestinationSet() const override; ReturnValue_t lockQueue(MutexIF::TimeoutType timeoutType, dur_millis_t lockTimeout); ReturnValue_t unlockQueue(); @@ -211,23 +105,14 @@ class MessageQueue : public MessageQueueIF { MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false); - // static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault); - private: std::queue> messageQueue; - /** - * @brief The class stores the queue id it got assigned. - * If initialization fails, the queue id is set to zero. - */ - MessageQueueId_t mqId = MessageQueueIF::NO_QUEUE; size_t messageSize = 0; size_t messageDepth = 0; MutexIF* queueLock; - bool defaultDestinationSet = false; MessageQueueId_t defaultDestination = MessageQueueIF::NO_QUEUE; - MessageQueueId_t lastPartner = MessageQueueIF::NO_QUEUE; }; #endif /* FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_ */ diff --git a/src/fsfw/osal/host/QueueFactory.cpp b/src/fsfw/osal/host/QueueFactory.cpp index 3c63e6c9..732892ca 100644 --- a/src/fsfw/osal/host/QueueFactory.cpp +++ b/src/fsfw/osal/host/QueueFactory.cpp @@ -27,12 +27,13 @@ QueueFactory::QueueFactory() {} QueueFactory::~QueueFactory() {} -MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize) { +MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize, + MqArgs* args) { // A thread-safe queue can be implemented by using a combination // of std::queue and std::mutex. This uses dynamic memory allocation // which could be alleviated by using a custom allocator, external library // (etl::queue) or simply using std::queue, we're on a host machine anyway. - return new MessageQueue(messageDepth, maxMessageSize); + return new MessageQueue(messageDepth, maxMessageSize, args); } void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { delete queue; } diff --git a/src/fsfw/osal/linux/CMakeLists.txt b/src/fsfw/osal/linux/CMakeLists.txt index dcdade67..679b2931 100644 --- a/src/fsfw/osal/linux/CMakeLists.txt +++ b/src/fsfw/osal/linux/CMakeLists.txt @@ -1,29 +1,29 @@ target_sources(${LIB_FSFW_NAME} PRIVATE Clock.cpp - BinarySemaphore.cpp - CountingSemaphore.cpp - FixedTimeslotTask.cpp - InternalErrorCodes.cpp - MessageQueue.cpp - Mutex.cpp - MutexFactory.cpp - PeriodicPosixTask.cpp - PosixThread.cpp - QueueFactory.cpp - SemaphoreFactory.cpp - TaskFactory.cpp - tcpipHelpers.cpp - unixUtility.cpp + BinarySemaphore.cpp + CountingSemaphore.cpp + FixedTimeslotTask.cpp + InternalErrorCodes.cpp + MessageQueue.cpp + Mutex.cpp + MutexFactory.cpp + PeriodicPosixTask.cpp + PosixThread.cpp + QueueFactory.cpp + SemaphoreFactory.cpp + TaskFactory.cpp + tcpipHelpers.cpp + unixUtility.cpp ) find_package(Threads REQUIRED) target_link_libraries(${LIB_FSFW_NAME} PRIVATE - ${CMAKE_THREAD_LIBS_INIT} - rt + ${CMAKE_THREAD_LIBS_INIT} + rt ) target_link_libraries(${LIB_FSFW_NAME} INTERFACE - ${CMAKE_THREAD_LIBS_INIT} + ${CMAKE_THREAD_LIBS_INIT} ) diff --git a/src/fsfw/osal/linux/MessageQueue.cpp b/src/fsfw/osal/linux/MessageQueue.cpp index f876ec6e..378f4e74 100644 --- a/src/fsfw/osal/linux/MessageQueue.cpp +++ b/src/fsfw/osal/linux/MessageQueue.cpp @@ -11,13 +11,10 @@ #include "fsfw/osal/linux/unixUtility.h" #include "fsfw/serviceinterface/ServiceInterface.h" -MessageQueue::MessageQueue(uint32_t messageDepth, size_t maxMessageSize) - : id(MessageQueueIF::NO_QUEUE), - lastPartner(MessageQueueIF::NO_QUEUE), - defaultDestination(MessageQueueIF::NO_QUEUE), +MessageQueue::MessageQueue(uint32_t messageDepth, size_t maxMessageSize, MqArgs* args) + : MessageQueueBase(MessageQueueIF::NO_QUEUE, MessageQueueIF::NO_QUEUE, args), maxMessageSize(maxMessageSize) { mq_attr attributes; - this->id = 0; // Set attributes attributes.mq_curmsgs = 0; attributes.mq_maxmsg = messageDepth; @@ -50,30 +47,6 @@ MessageQueue::~MessageQueue() { } } -ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message, - bool ignoreFault) { - return sendMessageFrom(sendTo, message, this->getId(), false); -} - -ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessageIF* message) { - return sendToDefaultFrom(message, this->getId()); -} - -ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) { - if (this->lastPartner != 0) { - return sendMessageFrom(this->lastPartner, message, this->getId()); - } else { - return NO_REPLY_PARTNER; - } -} - -ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message, - MessageQueueId_t* receivedFrom) { - ReturnValue_t status = this->receiveMessage(message); - *receivedFrom = this->lastPartner; - return status; -} - ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) { if (message == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 @@ -96,7 +69,7 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) { int status = mq_receive(id, reinterpret_cast(message->getBuffer()), message->getMaximumMessageSize(), &messagePriority); if (status > 0) { - this->lastPartner = message->getSender(); + this->last = message->getSender(); // Check size of incoming message. if (message->getMessageSize() < message->getMinimumMessageSize()) { return HasReturnvaluesIF::RETURN_FAILED; @@ -164,8 +137,6 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) { } } -MessageQueueId_t MessageQueue::getLastPartner() const { return this->lastPartner; } - ReturnValue_t MessageQueue::flush(uint32_t* count) { mq_attr attrib; int status = mq_getattr(id, &attrib); @@ -212,26 +183,11 @@ ReturnValue_t MessageQueue::flush(uint32_t* count) { return HasReturnvaluesIF::RETURN_OK; } -MessageQueueId_t MessageQueue::getId() const { return this->id; } - -void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) { - this->defaultDestination = defaultDestination; -} - -ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message, - MessageQueueId_t sentFrom, bool ignoreFault) { - return sendMessageFrom(defaultDestination, message, sentFrom, ignoreFault); -} - ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message, MessageQueueId_t sentFrom, bool ignoreFault) { return sendMessageFromMessageQueue(sendTo, message, sentFrom, ignoreFault); } -MessageQueueId_t MessageQueue::getDefaultDestination() const { return this->defaultDestination; } - -bool MessageQueue::isDefaultDestinationSet() const { return (defaultDestination != NO_QUEUE); } - uint16_t MessageQueue::queueCounter = 0; ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, @@ -240,9 +196,9 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, bool ignoreFault) { if (message == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "MessageQueue::sendMessageFromMessageQueue: Message is nullptr!" << std::endl; + sif::error << "MessageQueue::sendMessageFromMessageQueue: Message is nullptr" << std::endl; #else - sif::printError("MessageQueue::sendMessageFromMessageQueue: Message is nullptr!\n"); + sif::printError("MessageQueue::sendMessageFromMessageQueue: Message is nullptr\n"); #endif return HasReturnvaluesIF::RETURN_FAILED; } @@ -256,7 +212,7 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, if (!ignoreFault) { InternalErrorReporterIF* internalErrorReporter = ObjectManager::instance()->get(objects::INTERNAL_ERROR_REPORTER); - if (internalErrorReporter != NULL) { + if (internalErrorReporter != nullptr) { internalErrorReporter->queueMessageNotSent(); } } diff --git a/src/fsfw/osal/linux/MessageQueue.h b/src/fsfw/osal/linux/MessageQueue.h index dbf6555e..8614d101 100644 --- a/src/fsfw/osal/linux/MessageQueue.h +++ b/src/fsfw/osal/linux/MessageQueue.h @@ -1,11 +1,13 @@ #ifndef FSFW_OSAL_LINUX_MESSAGEQUEUE_H_ #define FSFW_OSAL_LINUX_MESSAGEQUEUE_H_ +#include #include #include "fsfw/internalerror/InternalErrorReporterIF.h" #include "fsfw/ipc/MessageQueueIF.h" #include "fsfw/ipc/MessageQueueMessage.h" +#include "fsfw/ipc/definitions.h" /** * @brief This class manages sending and receiving of message queue messages. * @@ -25,7 +27,7 @@ * makes use of the operating system calls provided. * @ingroup message_queue */ -class MessageQueue : public MessageQueueIF { +class MessageQueue : public MessageQueueBase { friend class MessageQueueSenderIF; public: @@ -42,104 +44,25 @@ class MessageQueue : public MessageQueueIF { * This should be left default. */ MessageQueue(uint32_t messageDepth = 3, - size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE); + size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE, + MqArgs* args = nullptr); + + /** Copying message queues forbidden */ + MessageQueue(const MessageQueue&) = delete; + MessageQueue& operator=(const MessageQueue&) = delete; + /** * @brief The destructor deletes the formerly created message queue. * @details This is accomplished by using the delete call provided by the operating system. */ virtual ~MessageQueue(); - /** - * @brief This operation sends a message to the given destination. - * @details It directly uses the sendMessage call of the MessageQueueSender parent, but passes - * its queue id as "sentFrom" parameter. - * @param sendTo This parameter specifies the message queue id of the destination message - * queue. - * @param message A pointer to a previously created message, which is sent. - * @param ignoreFault If set to true, the internal software fault counter is not incremented if - * queue is full. - */ - virtual ReturnValue_t sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message, - bool ignoreFault = false); - /** - * @brief This operation sends a message to the default destination. - * @details As in the sendMessage method, this function uses the sendToDefault call of the - * MessageQueueSender parent class and adds its queue id as "sentFrom" - * information. - * @param message A pointer to a previously created message, which is sent. - */ - virtual ReturnValue_t sendToDefault(MessageQueueMessageIF* message); - /** - * @brief This operation sends a message to the last communication partner. - * @details This operation simplifies answering an incoming message by using the stored - * lastParnter information as destination. If there was no message received yet - * (i.e. lastPartner is zero), an error code is returned. - * @param message A pointer to a previously created message, which is sent. - */ - ReturnValue_t reply(MessageQueueMessageIF* message); - /** - * @brief This function reads available messages from the message queue and returns the - * sender. - * @details It works identically to the other receiveMessage call, but in addition returns the - * sender's queue id. - * @param message A pointer to a message in which the received data is stored. - * @param receivedFrom A pointer to a queue id in which the sender's id is stored. - */ - ReturnValue_t receiveMessage(MessageQueueMessageIF* message, MessageQueueId_t* receivedFrom); - - /** - * @brief This function reads available messages from the message queue. - * @details If data is available it is stored in the passed message pointer. The message's - * original content is overwritten and the sendFrom information is stored in - * the lastPartner attribute. Else, the lastPartner information remains untouched, the message's - * content is cleared and the function returns immediately. - * @param message A pointer to a message in which the received data is stored. - */ - ReturnValue_t receiveMessage(MessageQueueMessageIF* message); - /** - * Deletes all pending messages in the queue. - * @param count The number of flushed messages. - * @return RETURN_OK on success. - */ - ReturnValue_t flush(uint32_t* count); - /** - * @brief This method returns the message queue id of the last communication partner. - */ - MessageQueueId_t getLastPartner() const; - /** - * @brief This method returns the message queue id of this class's message queue. - */ - MessageQueueId_t getId() const; - /** - * \brief With the sendMessage call, a queue message is sent to a receiving queue. - * \param sendTo This parameter specifies the message queue id to send the message to. - * \param message This is a pointer to a previously created message, which is sent. - * \param sentFrom The sentFrom information can be set to inject the sender's queue id into the - * message. This variable is set to zero by default. \param ignoreFault If set to true, the - * internal software fault counter is not incremented if queue is full. - */ - virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message, - MessageQueueId_t sentFrom, bool ignoreFault = false); - /** - * \brief The sendToDefault method sends a queue message to the default destination. - * \details In all other aspects, it works identical to the sendMessage method. - * \param message This is a pointer to a previously created message, which is sent. - * \param sentFrom The sentFrom information can be set to inject the sender's queue id into the - * message. This variable is set to zero by default. - */ - virtual ReturnValue_t sendToDefaultFrom(MessageQueueMessageIF* message, - MessageQueueId_t sentFrom = NO_QUEUE, - bool ignoreFault = false); - /** - * \brief This method is a simple setter for the default destination. - */ - void setDefaultDestination(MessageQueueId_t defaultDestination); - /** - * \brief This method is a simple getter for the default destination. - */ - MessageQueueId_t getDefaultDestination() const; - - bool isDefaultDestinationSet() const; + // Implement non-generic MessageQueueIF functions not handled by MessageQueueBase + ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override; + ReturnValue_t flush(uint32_t* count) override; + ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message, + MessageQueueId_t sentFrom, + bool ignoreFault = false) override; protected: /** @@ -158,31 +81,10 @@ class MessageQueue : public MessageQueueIF { bool ignoreFault = false); private: - /** - * @brief The class stores the queue id it got assigned from the operating system in this - * attribute. If initialization fails, the queue id is set to zero. - */ - MessageQueueId_t id; - /** - * @brief In this attribute, the queue id of the last communication partner is stored - * to allow for replying. - */ - MessageQueueId_t lastPartner; - /** - * @brief The message queue's name -a user specific information for the operating system- is - * generated automatically with the help of this static counter. - */ - /** - * \brief This attribute stores a default destination to send messages to. - * \details It is stored to simplify sending to always-the-same receiver. The attribute may - * be set in the constructor or by a setter call to setDefaultDestination. - */ - MessageQueueId_t defaultDestination; - /** * The name of the message queue, stored for unlinking */ - char name[16]; + char name[16] = {}; static uint16_t queueCounter; const size_t maxMessageSize; diff --git a/src/fsfw/osal/linux/QueueFactory.cpp b/src/fsfw/osal/linux/QueueFactory.cpp index d1b1cfdb..24ace1ae 100644 --- a/src/fsfw/osal/linux/QueueFactory.cpp +++ b/src/fsfw/osal/linux/QueueFactory.cpp @@ -28,8 +28,9 @@ QueueFactory::QueueFactory() {} QueueFactory::~QueueFactory() {} -MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize) { - return new MessageQueue(messageDepth, maxMessageSize); +MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize, + MqArgs* args) { + return new MessageQueue(messageDepth, maxMessageSize, args); } void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { delete queue; } diff --git a/src/fsfw/osal/rtems/MessageQueue.cpp b/src/fsfw/osal/rtems/MessageQueue.cpp index e45679d5..f52f1852 100644 --- a/src/fsfw/osal/rtems/MessageQueue.cpp +++ b/src/fsfw/osal/rtems/MessageQueue.cpp @@ -6,8 +6,9 @@ #include "fsfw/osal/rtems/RtemsBasic.h" #include "fsfw/serviceinterface/ServiceInterface.h" -MessageQueue::MessageQueue(size_t message_depth, size_t max_message_size) - : id(0), lastPartner(0), defaultDestination(NO_QUEUE), internalErrorReporter(nullptr) { +MessageQueue::MessageQueue(size_t message_depth, size_t max_message_size, MqArgs* args) + : MessageQueueBase(MessageQueueIF::NO_QUEUE, MessageQueueIF::NO_QUEUE, args), + internalErrorReporter(nullptr) { rtems_name name = ('Q' << 24) + (queueCounter++ << 8); rtems_status_code status = rtems_message_queue_create(name, message_depth, max_message_size, 0, &(this->id)); @@ -16,43 +17,19 @@ MessageQueue::MessageQueue(size_t message_depth, size_t max_message_size) sif::error << "MessageQueue::MessageQueue: Creating Queue " << std::hex << name << std::dec << " failed with status:" << (uint32_t)status << std::endl; #endif - this->id = 0; + this->id = MessageQueueIF::NO_QUEUE; } } MessageQueue::~MessageQueue() { rtems_message_queue_delete(id); } -ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message, - bool ignoreFault) { - return sendMessageFrom(sendTo, message, this->getId(), ignoreFault); -} - -ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessageIF* message) { - return sendToDefaultFrom(message, this->getId()); -} - -ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) { - if (this->lastPartner != 0) { - return sendMessage(this->lastPartner, message, this->getId()); - } else { - return NO_REPLY_PARTNER; - } -} - -ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message, - MessageQueueId_t* receivedFrom) { - ReturnValue_t status = this->receiveMessage(message); - *receivedFrom = this->lastPartner; - return status; -} - ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) { size_t size = 0; rtems_status_code status = rtems_message_queue_receive(id, message->getBuffer(), &size, RTEMS_NO_WAIT, 1); if (status == RTEMS_SUCCESSFUL) { message->setMessageSize(size); - this->lastPartner = message->getSender(); + this->last = message->getSender(); // Check size of incoming message. if (message->getMessageSize() < message->getMinimumMessageSize()) { return HasReturnvaluesIF::RETURN_FAILED; @@ -65,19 +42,11 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) { return convertReturnCode(status); } -MessageQueueId_t MessageQueue::getLastPartner() const { return this->lastPartner; } - ReturnValue_t MessageQueue::flush(uint32_t* count) { rtems_status_code status = rtems_message_queue_flush(id, count); return convertReturnCode(status); } -MessageQueueId_t MessageQueue::getId() const { return this->id; } - -void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) { - this->defaultDestination = defaultDestination; -} - ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message, MessageQueueId_t sentFrom, bool ignoreFault) { message->setSender(sentFrom); @@ -103,15 +72,6 @@ ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueu return returnCode; } -ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message, - MessageQueueId_t sentFrom, bool ignoreFault) { - return sendMessageFrom(defaultDestination, message, sentFrom, ignoreFault); -} - -MessageQueueId_t MessageQueue::getDefaultDestination() const { return this->defaultDestination; } - -bool MessageQueue::isDefaultDestinationSet() const { return (defaultDestination != NO_QUEUE); } - ReturnValue_t MessageQueue::convertReturnCode(rtems_status_code inValue) { switch (inValue) { case RTEMS_SUCCESSFUL: diff --git a/src/fsfw/osal/rtems/MessageQueue.h b/src/fsfw/osal/rtems/MessageQueue.h index 89aae2ad..4648fdfa 100644 --- a/src/fsfw/osal/rtems/MessageQueue.h +++ b/src/fsfw/osal/rtems/MessageQueue.h @@ -1,10 +1,12 @@ #ifndef FSFW_OSAL_RTEMS_MESSAGEQUEUE_H_ #define FSFW_OSAL_RTEMS_MESSAGEQUEUE_H_ +#include #include "RtemsBasic.h" #include "fsfw/internalerror/InternalErrorReporterIF.h" #include "fsfw/ipc/MessageQueueIF.h" #include "fsfw/ipc/MessageQueueMessage.h" +#include "fsfw/ipc/definitions.h" /** * @brief This class manages sending and receiving of message queue messages. @@ -19,7 +21,7 @@ *as well as sending and receiving messages, the class makes use of the operating system calls *provided. \ingroup message_queue */ -class MessageQueue : public MessageQueueIF { +class MessageQueue : public MessageQueueBase { public: /** * @brief The constructor initializes and configures the message queue. @@ -34,131 +36,26 @@ class MessageQueue : public MessageQueueIF { * This should be left default. */ MessageQueue(size_t message_depth = 3, - size_t max_message_size = MessageQueueMessage::MAX_MESSAGE_SIZE); + size_t max_message_size = MessageQueueMessage::MAX_MESSAGE_SIZE, + MqArgs* args = nullptr); + + /** Copying message queues forbidden */ + MessageQueue(const MessageQueue&) = delete; + MessageQueue& operator=(const MessageQueue&) = delete; + /** * @brief The destructor deletes the formerly created message queue. * @details This is accomplished by using the delete call provided by the operating system. */ virtual ~MessageQueue(); - /** - * @brief This operation sends a message to the given destination. - * @details It directly uses the sendMessage call of the MessageQueueSender parent, but passes - * its queue id as "sentFrom" parameter. - * @param sendTo This parameter specifies the message queue id of the destination message - * queue. - * @param message A pointer to a previously created message, which is sent. - * @param ignoreFault If set to true, the internal software fault counter is not incremented if - * queue is full. - */ - ReturnValue_t sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message, - bool ignoreFault = false); - /** - * @brief This operation sends a message to the default destination. - * @details As in the sendMessage method, this function uses the sendToDefault call of the - * MessageQueueSender parent class and adds its queue id as "sentFrom" - * information. - * @param message A pointer to a previously created message, which is sent. - */ - ReturnValue_t sendToDefault(MessageQueueMessageIF* message); - /** - * @brief This operation sends a message to the last communication partner. - * @details This operation simplifies answering an incoming message by using the stored - * lastParnter information as destination. If there was no message received yet - * (i.e. lastPartner is zero), an error code is returned. - * @param message A pointer to a previously created message, which is sent. - */ - ReturnValue_t reply(MessageQueueMessageIF* message); - /** - * @brief This function reads available messages from the message queue and returns the - * sender. - * @details It works identically to the other receiveMessage call, but in addition returns the - * sender's queue id. - * @param message A pointer to a message in which the received data is stored. - * @param receivedFrom A pointer to a queue id in which the sender's id is stored. - */ - ReturnValue_t receiveMessage(MessageQueueMessageIF* message, MessageQueueId_t* receivedFrom); - - /** - * @brief This function reads available messages from the message queue. - * @details If data is available it is stored in the passed message pointer. The message's - * original content is overwritten and the sendFrom information is stored in - * the lastPartner attribute. Else, the lastPartner information remains untouched, the message's - * content is cleared and the function returns immediately. - * @param message A pointer to a message in which the received data is stored. - */ - ReturnValue_t receiveMessage(MessageQueueMessageIF* message); - /** - * Deletes all pending messages in the queue. - * @param count The number of flushed messages. - * @return RETURN_OK on success. - */ - ReturnValue_t flush(uint32_t* count); - /** - * @brief This method returns the message queue id of the last communication partner. - */ - MessageQueueId_t getLastPartner() const; - /** - * @brief This method returns the message queue id of this class's message queue. - */ - MessageQueueId_t getId() const; - /** - * \brief With the sendMessage call, a queue message is sent to a receiving queue. - * \details This method takes the message provided, adds the sentFrom information and passes - * it on to the destination provided with an operating system call. The OS's - * return value is returned. - * \param sendTo This parameter specifies the message queue id to send the message to. - * \param message This is a pointer to a previously created message, which is sent. - * \param sentFrom The sentFrom information can be set to inject the sender's queue id into the - * message. This variable is set to zero by default. \param ignoreFault If set to true, the - * internal software fault counter is not incremented if queue is full. - */ - virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message, + // Implement non-generic MessageQueueIF functions not handled by MessageQueueBase + ReturnValue_t flush(uint32_t* count) override; + ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message, MessageQueueId_t sentFrom = NO_QUEUE, - bool ignoreFault = false); - /** - * \brief The sendToDefault method sends a queue message to the default destination. - * \details In all other aspects, it works identical to the sendMessage method. - * \param message This is a pointer to a previously created message, which is sent. - * \param sentFrom The sentFrom information can be set to inject the sender's queue id into the - * message. This variable is set to zero by default. - */ - virtual ReturnValue_t sendToDefaultFrom(MessageQueueMessageIF* message, - MessageQueueId_t sentFrom = NO_QUEUE, - bool ignoreFault = false); - /** - * \brief This method is a simple setter for the default destination. - */ - void setDefaultDestination(MessageQueueId_t defaultDestination); - /** - * \brief This method is a simple getter for the default destination. - */ - MessageQueueId_t getDefaultDestination() const; - - bool isDefaultDestinationSet() const; + bool ignoreFault = false) override; private: - /** - * @brief The class stores the queue id it got assigned from the operating system in this - * attribute. If initialization fails, the queue id is set to zero. - */ - MessageQueueId_t id; - /** - * @brief In this attribute, the queue id of the last communication partner is stored - * to allow for replying. - */ - MessageQueueId_t lastPartner; - /** - * @brief The message queue's name -a user specific information for the operating system- is - * generated automatically with the help of this static counter. - */ - /** - * \brief This attribute stores a default destination to send messages to. - * \details It is stored to simplify sending to always-the-same receiver. The attribute may - * be set in the constructor or by a setter call to setDefaultDestination. - */ - MessageQueueId_t defaultDestination; - /** * \brief This attribute stores a reference to the internal error reporter for reporting full * queues. \details In the event of a full destination queue, the reporter will be notified. The diff --git a/src/fsfw/osal/rtems/QueueFactory.cpp b/src/fsfw/osal/rtems/QueueFactory.cpp index 3d517f60..2519f444 100644 --- a/src/fsfw/osal/rtems/QueueFactory.cpp +++ b/src/fsfw/osal/rtems/QueueFactory.cpp @@ -49,8 +49,9 @@ QueueFactory::QueueFactory() {} QueueFactory::~QueueFactory() {} -MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize) { - return new MessageQueue(messageDepth, maxMessageSize); +MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize, + MqArgs* args) { + return new MessageQueue(messageDepth, maxMessageSize, args); } void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { delete queue; } diff --git a/tests/src/fsfw_tests/unit/datapoollocal/LocalPoolManagerTest.cpp b/tests/src/fsfw_tests/unit/datapoollocal/LocalPoolManagerTest.cpp index 07762595..f2a5c18a 100644 --- a/tests/src/fsfw_tests/unit/datapoollocal/LocalPoolManagerTest.cpp +++ b/tests/src/fsfw_tests/unit/datapoollocal/LocalPoolManagerTest.cpp @@ -21,8 +21,10 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") { REQUIRE(poolOwner->initializeHkManager() == retval::CATCH_OK); REQUIRE(poolOwner->initializeHkManagerAfterTaskCreation() == retval::CATCH_OK); - MessageQueueMockBase* mqMock = poolOwner->getMockQueueHandle(); - REQUIRE(mqMock != nullptr); + MessageQueueMockBase* poolOwnerMock = poolOwner->getMockQueueHandle(); + REQUIRE(poolOwnerMock != nullptr); + + // MessageQueueIF* hkCommander = QueueFactory::instance()->createMessageQueue(); CommandMessage messageSent; uint8_t messagesSent = 0; @@ -41,9 +43,9 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") { poolOwner->dataset.setChanged(true); /* Now the update message should be generated. */ REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); - REQUIRE(mqMock->wasMessageSent() == true); + REQUIRE(poolOwnerMock->wasMessageSent() == true); - REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK); + REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == retval::CATCH_OK); CHECK(messageSent.getCommand() == static_cast(HousekeepingMessage::UPDATE_NOTIFICATION_SET)); @@ -53,9 +55,9 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") { poolOwner->dataset.setChanged(true); REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); - REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true); CHECK(messagesSent == 1); - REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK); + REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == retval::CATCH_OK); CHECK(messageSent.getCommand() == static_cast(HousekeepingMessage::UPDATE_NOTIFICATION_SET)); @@ -63,15 +65,15 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") { REQUIRE(poolOwner->subscribeWrapperSetUpdateHk() == retval::CATCH_OK); poolOwner->dataset.setChanged(true); REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); - REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true); CHECK(messagesSent == 2); /* first message sent should be the update notification, considering the internal list is a vector checked in insertion order. */ - REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK); + REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == retval::CATCH_OK); CHECK(messageSent.getCommand() == static_cast(HousekeepingMessage::UPDATE_NOTIFICATION_SET)); - REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK); + REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == retval::CATCH_OK); CHECK(messageSent.getCommand() == static_cast(HousekeepingMessage::HK_REPORT)); /* Clear message to avoid memory leak, our mock won't do it for us (yet) */ CommandMessageCleaner::clearCommandMessage(&messageSent); @@ -99,9 +101,9 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") { /* Trigger generation of snapshot */ REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); - REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true); CHECK(messagesSent == 1); - REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK); + REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == retval::CATCH_OK); /* Check that snapshot was generated */ CHECK(messageSent.getCommand() == static_cast(HousekeepingMessage::UPDATE_SNAPSHOT_SET)); /* Now we deserialize the snapshot into a new dataset instance */ @@ -162,12 +164,12 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") { REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); /* Check update snapshot was sent. */ - REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true); CHECK(messagesSent == 1); /* Should have been reset. */ CHECK(poolVar->hasChanged() == false); - REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK); + REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == retval::CATCH_OK); CHECK(messageSent.getCommand() == static_cast(HousekeepingMessage::UPDATE_SNAPSHOT_VARIABLE)); /* Now we deserialize the snapshot into a new dataset instance */ @@ -209,11 +211,11 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") { REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); /* Check update notification was sent. */ - REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true); CHECK(messagesSent == 1); /* Should have been reset. */ CHECK(poolVar->hasChanged() == false); - REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK); + REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == retval::CATCH_OK); CHECK(messageSent.getCommand() == static_cast(HousekeepingMessage::UPDATE_NOTIFICATION_VARIABLE)); /* Now subscribe for the dataset update (HK and update) again with subscription interface */ @@ -225,26 +227,26 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") { poolOwner->dataset.setChanged(true); REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); /* Now two messages should be sent. */ - REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true); CHECK(messagesSent == 2); - mqMock->clearMessages(true); + poolOwnerMock->clearMessages(true); poolOwner->dataset.setChanged(true); poolVar->setChanged(true); REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); /* Now three messages should be sent. */ - REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true); CHECK(messagesSent == 3); - REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK); + REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == retval::CATCH_OK); CHECK(messageSent.getCommand() == static_cast(HousekeepingMessage::UPDATE_NOTIFICATION_VARIABLE)); - REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK); + REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == retval::CATCH_OK); CHECK(messageSent.getCommand() == static_cast(HousekeepingMessage::UPDATE_NOTIFICATION_SET)); - REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK); + REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == retval::CATCH_OK); CHECK(messageSent.getCommand() == static_cast(HousekeepingMessage::HK_REPORT)); CommandMessageCleaner::clearCommandMessage(&messageSent); - REQUIRE(mqMock->receiveMessage(&messageSent) == static_cast(MessageQueueIF::EMPTY)); + REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == static_cast(MessageQueueIF::EMPTY)); } SECTION("PeriodicHKAndMessaging") { @@ -255,38 +257,38 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") { REQUIRE(poolOwner->subscribePeriodicHk(true) == retval::CATCH_OK); REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); /* Now HK packet should be sent as message immediately. */ - REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true); CHECK(messagesSent == 1); - CHECK(mqMock->popMessage() == retval::CATCH_OK); + CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK); LocalPoolDataSetBase* setHandle = poolOwner->getDataSetHandle(lpool::testSid); REQUIRE(setHandle != nullptr); CHECK(poolOwner->poolManager.generateHousekeepingPacket(lpool::testSid, setHandle, false) == retval::CATCH_OK); - REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true); CHECK(messagesSent == 1); - CHECK(mqMock->popMessage() == retval::CATCH_OK); + CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK); CHECK(setHandle->getReportingEnabled() == true); CommandMessage hkCmd; HousekeepingMessage::setToggleReportingCommand(&hkCmd, lpool::testSid, false, false); CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK); CHECK(setHandle->getReportingEnabled() == false); - REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true); CHECK(messagesSent == 1); - CHECK(mqMock->popMessage() == retval::CATCH_OK); + CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK); HousekeepingMessage::setToggleReportingCommand(&hkCmd, lpool::testSid, true, false); CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK); CHECK(setHandle->getReportingEnabled() == true); - REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); - CHECK(mqMock->popMessage() == retval::CATCH_OK); + REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true); + CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK); HousekeepingMessage::setToggleReportingCommand(&hkCmd, lpool::testSid, false, false); CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK); CHECK(setHandle->getReportingEnabled() == false); - REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); - CHECK(mqMock->popMessage() == retval::CATCH_OK); + REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true); + CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK); HousekeepingMessage::setCollectionIntervalModificationCommand(&hkCmd, lpool::testSid, 0.4, false); @@ -294,23 +296,23 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") { /* For non-diagnostics and a specified minimum frequency of 0.2 seconds, the resulting collection interval should be 1.0 second */ CHECK(poolOwner->dataset.getCollectionInterval() == 1.0); - REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true); CHECK(messagesSent == 1); - CHECK(mqMock->popMessage() == retval::CATCH_OK); + CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK); HousekeepingMessage::setStructureReportingCommand(&hkCmd, lpool::testSid, false); REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK); /* Now HK packet should be sent as message. */ - REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true); CHECK(messagesSent == 1); - CHECK(mqMock->popMessage() == retval::CATCH_OK); + CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK); HousekeepingMessage::setOneShotReportCommand(&hkCmd, lpool::testSid, false); CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK); - REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true); CHECK(messagesSent == 1); - CHECK(mqMock->popMessage() == retval::CATCH_OK); + CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK); HousekeepingMessage::setUpdateNotificationSetCommand(&hkCmd, lpool::testSid); sid_t sidToCheck; @@ -326,62 +328,62 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") { CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == static_cast(LocalDataPoolManager::WRONG_HK_PACKET_TYPE)); /* We still expect a failure message being sent */ - REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true); CHECK(messagesSent == 1); - CHECK(mqMock->popMessage() == retval::CATCH_OK); + CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK); HousekeepingMessage::setCollectionIntervalModificationCommand(&hkCmd, lpool::testSid, 0.4, false); CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == static_cast(LocalDataPoolManager::WRONG_HK_PACKET_TYPE)); - REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true); CHECK(messagesSent == 1); - CHECK(mqMock->popMessage() == retval::CATCH_OK); + CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK); HousekeepingMessage::setStructureReportingCommand(&hkCmd, lpool::testSid, false); CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == static_cast(LocalDataPoolManager::WRONG_HK_PACKET_TYPE)); - REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true); CHECK(messagesSent == 1); - CHECK(mqMock->popMessage() == retval::CATCH_OK); + CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK); HousekeepingMessage::setStructureReportingCommand(&hkCmd, lpool::testSid, true); CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK); - REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true); CHECK(messagesSent == 1); - CHECK(mqMock->popMessage() == retval::CATCH_OK); + CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK); HousekeepingMessage::setCollectionIntervalModificationCommand(&hkCmd, lpool::testSid, 0.4, true); CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK); - REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true); CHECK(messagesSent == 1); - CHECK(mqMock->popMessage() == retval::CATCH_OK); + CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK); HousekeepingMessage::setToggleReportingCommand(&hkCmd, lpool::testSid, true, true); CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK); - REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true); CHECK(messagesSent == 1); - CHECK(mqMock->popMessage() == retval::CATCH_OK); + CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK); HousekeepingMessage::setToggleReportingCommand(&hkCmd, lpool::testSid, false, true); CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK); - REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true); CHECK(messagesSent == 1); - CHECK(mqMock->popMessage() == retval::CATCH_OK); + CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK); HousekeepingMessage::setOneShotReportCommand(&hkCmd, lpool::testSid, false); CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == static_cast(LocalDataPoolManager::WRONG_HK_PACKET_TYPE)); - REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true); CHECK(messagesSent == 1); - CHECK(mqMock->popMessage() == retval::CATCH_OK); + CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK); HousekeepingMessage::setOneShotReportCommand(&hkCmd, lpool::testSid, true); CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK); - REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true); CHECK(messagesSent == 1); - CHECK(mqMock->popMessage() == retval::CATCH_OK); + CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK); HousekeepingMessage::setUpdateNotificationVariableCommand(&hkCmd, lpool::uint8VarGpid); gp_id_t gpidToCheck; @@ -407,5 +409,5 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") { /* we need to reset the subscription list because the pool owner is a global object. */ CHECK(poolOwner->reset() == retval::CATCH_OK); - mqMock->clearMessages(true); + poolOwnerMock->clearMessages(true); } diff --git a/tests/src/fsfw_tests/unit/mocks/MessageQueueMockBase.h b/tests/src/fsfw_tests/unit/mocks/MessageQueueMockBase.h index f60c7402..c3d08a86 100644 --- a/tests/src/fsfw_tests/unit/mocks/MessageQueueMockBase.h +++ b/tests/src/fsfw_tests/unit/mocks/MessageQueueMockBase.h @@ -4,16 +4,18 @@ #include #include +#include "fsfw/ipc/MessageQueueBase.h" #include "fsfw/ipc/CommandMessage.h" #include "fsfw/ipc/MessageQueueIF.h" #include "fsfw/ipc/MessageQueueMessage.h" #include "fsfw_tests/unit/CatchDefinitions.h" -class MessageQueueMockBase : public MessageQueueIF { +class MessageQueueMockBase : public MessageQueueBase { public: - MessageQueueId_t myQueueId = tconst::testQueueId; + MessageQueueMockBase() + : MessageQueueBase(MessageQueueIF::NO_QUEUE, MessageQueueIF::NO_QUEUE, nullptr) {} + uint8_t messageSentCounter = 0; - bool defaultDestSet = false; bool messageSent = false; bool wasMessageSent(uint8_t* messageSentCounter = nullptr, bool resetCounter = true) { @@ -38,53 +40,30 @@ class MessageQueueMockBase : public MessageQueueIF { return receiveMessage(&message); } - virtual ReturnValue_t reply(MessageQueueMessageIF* message) { - return sendMessage(myQueueId, message); - }; - virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message, - MessageQueueId_t* receivedFrom) { - return receiveMessage(message); - } - - virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message) { + virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override { if (messagesSentQueue.empty()) { return MessageQueueIF::EMPTY; } - + this->last = message->getSender(); std::memcpy(message->getBuffer(), messagesSentQueue.front().getBuffer(), message->getMessageSize()); messagesSentQueue.pop(); return HasReturnvaluesIF::RETURN_OK; } virtual ReturnValue_t flush(uint32_t* count) { return HasReturnvaluesIF::RETURN_OK; } - virtual MessageQueueId_t getLastPartner() const { return myQueueId; } - virtual MessageQueueId_t getId() const { return myQueueId; } virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message, - MessageQueueId_t sentFrom, bool ignoreFault = false) { - return sendMessage(sendTo, message); - } - virtual ReturnValue_t sendToDefaultFrom(MessageQueueMessageIF* message, MessageQueueId_t sentFrom, - bool ignoreFault = false) { - return sendMessage(myQueueId, message); - } - virtual ReturnValue_t sendToDefault(MessageQueueMessageIF* message) { - return sendMessage(myQueueId, message); - } - virtual ReturnValue_t sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message, - bool ignoreFault = false) override { + MessageQueueId_t sentFrom, + bool ignoreFault = false) override { messageSent = true; messageSentCounter++; MessageQueueMessage& messageRef = *(dynamic_cast(message)); messagesSentQueue.push(messageRef); 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; } + virtual ReturnValue_t reply(MessageQueueMessageIF* message) override { + return sendMessageFrom(MessageQueueIF::NO_QUEUE, message, this->getId(), false); + } void clearMessages(bool clearCommandMessages = true) { while (not messagesSentQueue.empty()) {