diff --git a/CHANGELOG.md b/CHANGELOG.md index 335c0f7bb..bfa2b763b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,17 @@ and this project adheres to [Semantic Versioning](http://semver.org/). # [unreleased] +# [v5.0.0] + +## Removed + +- Removed the `HkSwitchHelper`. This module should not be needed anymore, now that the local + datapools have been implemented + +## Additions + +- Linux HAL: Add wiretapping option for I2C. Enabled with `FSFW_HAL_I2C_WIRETAPPING` defined to 1 + # [v4.0.0] ## Additions diff --git a/hal/src/fsfw_hal/linux/i2c/I2cComIF.cpp b/hal/src/fsfw_hal/linux/i2c/I2cComIF.cpp index dc23542d8..4f53dc1f7 100644 --- a/hal/src/fsfw_hal/linux/i2c/I2cComIF.cpp +++ b/hal/src/fsfw_hal/linux/i2c/I2cComIF.cpp @@ -1,4 +1,13 @@ -#include "fsfw_hal/linux/i2c/I2cComIF.h" +#include "I2cComIF.h" + +#include "fsfw/FSFW.h" +#include "fsfw/serviceinterface.h" +#include "fsfw_hal/linux/UnixFileGuard.h" +#include "fsfw_hal/linux/utility.h" + +#if FSFW_HAL_I2C_WIRETAPPING == 1 +#include "fsfw/globalfunctions/arrayprinter.h" +#endif #include #include @@ -8,11 +17,6 @@ #include -#include "fsfw/FSFW.h" -#include "fsfw/serviceinterface.h" -#include "fsfw_hal/linux/UnixFileGuard.h" -#include "fsfw_hal/linux/utility.h" - I2cComIF::I2cComIF(object_id_t objectId) : SystemObject(objectId) {} I2cComIF::~I2cComIF() {} @@ -112,6 +116,11 @@ ReturnValue_t I2cComIF::sendMessage(CookieIF* cookie, const uint8_t* sendData, s #endif return HasReturnvaluesIF::RETURN_FAILED; } + +#if FSFW_HAL_I2C_WIRETAPPING == 1 + sif::info << "Sent I2C data to bus " << deviceFile << ":" << std::endl; + arrayprinter::print(sendData, sendLen); +#endif return HasReturnvaluesIF::RETURN_OK; } @@ -176,6 +185,11 @@ ReturnValue_t I2cComIF::requestReceiveMessage(CookieIF* cookie, size_t requestLe return HasReturnvaluesIF::RETURN_FAILED; } +#if FSFW_HAL_I2C_WIRETAPPING == 1 + sif::info << "I2C read bytes from bus " << deviceFile << ":" << std::endl; + arrayprinter::print(replyBuffer, requestLen); +#endif + i2cDeviceMapIter->second.replyLen = requestLen; return HasReturnvaluesIF::RETURN_OK; } diff --git a/scripts/helper.py b/scripts/helper.py index 68693c40f..4dff908df 100755 --- a/scripts/helper.py +++ b/scripts/helper.py @@ -97,11 +97,11 @@ def handle_docs_type(args, build_dir_list: list): build_directory = determine_build_dir(build_dir_list) os.chdir(build_directory) if args.build: - os.system("cmake --build . -j") + cmd_runner("cmake --build . -j") if args.open: if not os.path.isfile("docs/sphinx/index.html"): # try again.. - os.system("cmake --build . -j") + cmd_runner("cmake --build . -j") if not os.path.isfile("docs/sphinx/index.html"): print( "No Sphinx documentation file detected. " @@ -143,25 +143,21 @@ def handle_tests_type(args, build_dir_list: list): if which("valgrind") is None: print("Please install valgrind first") sys.exit(1) - if os.path.split(os.getcwd())[1] != UNITTEST_FOLDER_NAME: - # If we are in a different directory we try to switch into it but - # this might fail - os.chdir(UNITTEST_FOLDER_NAME) - os.system("valgrind --leak-check=full ./fsfw-tests") + cmd_runner("valgrind --leak-check=full ./fsfw-tests") os.chdir("..") def create_tests_build_cfg(): os.mkdir(UNITTEST_FOLDER_NAME) os.chdir(UNITTEST_FOLDER_NAME) - os.system("cmake -DFSFW_OSAL=host -DFSFW_BUILD_UNITTESTS=ON ..") + cmd_runner("cmake -DFSFW_OSAL=host -DFSFW_BUILD_UNITTESTS=ON ..") os.chdir("..") def create_docs_build_cfg(): os.mkdir(DOCS_FOLDER_NAME) os.chdir(DOCS_FOLDER_NAME) - os.system("cmake -DFSFW_OSAL=host -DFSFW_BUILD_DOCS=ON ..") + cmd_runner("cmake -DFSFW_OSAL=host -DFSFW_BUILD_DOCS=ON ..") os.chdir("..") @@ -184,7 +180,7 @@ def check_for_cmake_build_dir(build_dir_list: list) -> list: def perform_lcov_operation(directory: str, chdir: bool): if chdir: os.chdir(directory) - os.system("cmake --build . -- fsfw-tests_coverage -j") + cmd_runner("cmake --build . -- fsfw-tests_coverage -j") def determine_build_dir(build_dir_list: List[str]): @@ -206,5 +202,10 @@ def determine_build_dir(build_dir_list: List[str]): return build_directory +def cmd_runner(cmd: str): + print(f"Executing command: {cmd}") + os.system(cmd) + + if __name__ == "__main__": main() diff --git a/src/fsfw/FSFW.h.in b/src/fsfw/FSFW.h.in index 88ad10cf3..28e0c0bfa 100644 --- a/src/fsfw/FSFW.h.in +++ b/src/fsfw/FSFW.h.in @@ -69,4 +69,9 @@ #define FSFW_HAL_LIS3MDL_MGM_DEBUG 0 #endif /* FSFW_HAL_LIS3MDL_MGM_DEBUG */ +// Can be used for low-level debugging of the I2C bus +#ifndef FSFW_HAL_I2C_WIRETAPPING +#define FSFW_HAL_I2C_WIRETAPPING 0 +#endif + #endif /* FSFW_FSFW_H_ */ diff --git a/src/fsfw/controller/ControllerBase.h b/src/fsfw/controller/ControllerBase.h index db75982c8..7032f8171 100644 --- a/src/fsfw/controller/ControllerBase.h +++ b/src/fsfw/controller/ControllerBase.h @@ -1,7 +1,6 @@ #ifndef FSFW_CONTROLLER_CONTROLLERBASE_H_ #define FSFW_CONTROLLER_CONTROLLERBASE_H_ -#include "fsfw/datapool/HkSwitchHelper.h" #include "fsfw/health/HasHealthIF.h" #include "fsfw/health/HealthHelper.h" #include "fsfw/modes/HasModesIF.h" diff --git a/src/fsfw/datapool/CMakeLists.txt b/src/fsfw/datapool/CMakeLists.txt index 0d53e1ba1..be4606aaa 100644 --- a/src/fsfw/datapool/CMakeLists.txt +++ b/src/fsfw/datapool/CMakeLists.txt @@ -1,6 +1,4 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - HkSwitchHelper.cpp - PoolDataSetBase.cpp - PoolEntry.cpp +target_sources(${LIB_FSFW_NAME} PRIVATE + PoolDataSetBase.cpp + PoolEntry.cpp ) \ No newline at end of file diff --git a/src/fsfw/datapool/HkSwitchHelper.cpp b/src/fsfw/datapool/HkSwitchHelper.cpp deleted file mode 100644 index 7f6ffd17f..000000000 --- a/src/fsfw/datapool/HkSwitchHelper.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include "fsfw/datapool/HkSwitchHelper.h" - -#include "fsfw/ipc/QueueFactory.h" - -HkSwitchHelper::HkSwitchHelper(EventReportingProxyIF* eventProxy) - : commandActionHelper(this), eventProxy(eventProxy) { - actionQueue = QueueFactory::instance()->createMessageQueue(); -} - -HkSwitchHelper::~HkSwitchHelper() { QueueFactory::instance()->deleteMessageQueue(actionQueue); } - -ReturnValue_t HkSwitchHelper::initialize() { - ReturnValue_t result = commandActionHelper.initialize(); - - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - return result; -} - -ReturnValue_t HkSwitchHelper::performOperation(uint8_t operationCode) { - CommandMessage command; - while (actionQueue->receiveMessage(&command) == HasReturnvaluesIF::RETURN_OK) { - ReturnValue_t result = commandActionHelper.handleReply(&command); - if (result == HasReturnvaluesIF::RETURN_OK) { - continue; - } - command.setToUnknownCommand(); - actionQueue->reply(&command); - } - - return HasReturnvaluesIF::RETURN_OK; -} - -void HkSwitchHelper::stepSuccessfulReceived(ActionId_t actionId, uint8_t step) {} - -void HkSwitchHelper::stepFailedReceived(ActionId_t actionId, uint8_t step, - ReturnValue_t returnCode) { - eventProxy->forwardEvent(SWITCHING_TM_FAILED, returnCode, actionId); -} - -void HkSwitchHelper::dataReceived(ActionId_t actionId, const uint8_t* data, uint32_t size) {} - -void HkSwitchHelper::completionSuccessfulReceived(ActionId_t actionId) {} - -void HkSwitchHelper::completionFailedReceived(ActionId_t actionId, ReturnValue_t returnCode) { - eventProxy->forwardEvent(SWITCHING_TM_FAILED, returnCode, actionId); -} - -ReturnValue_t HkSwitchHelper::switchHK(SerializeIF* sids, bool enable) { - // ActionId_t action = HKService::DISABLE_HK; - // if (enable) { - // action = HKService::ENABLE_HK; - // } - // - // ReturnValue_t result = commandActionHelper.commandAction( - // objects::PUS_HK_SERVICE, action, sids); - // - // if (result != HasReturnvaluesIF::RETURN_OK) { - // eventProxy->forwardEvent(SWITCHING_TM_FAILED, result); - // } - // return result; - return HasReturnvaluesIF::RETURN_OK; -} - -MessageQueueIF* HkSwitchHelper::getCommandQueuePtr() { return actionQueue; } diff --git a/src/fsfw/datapool/HkSwitchHelper.h b/src/fsfw/datapool/HkSwitchHelper.h deleted file mode 100644 index a0becd81b..000000000 --- a/src/fsfw/datapool/HkSwitchHelper.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef FRAMEWORK_DATAPOOL_HKSWITCHHELPER_H_ -#define FRAMEWORK_DATAPOOL_HKSWITCHHELPER_H_ - -#include "fsfw/action/CommandsActionsIF.h" -#include "fsfw/events/EventReportingProxyIF.h" -#include "fsfw/tasks/ExecutableObjectIF.h" - -// TODO this class violations separation between mission and framework -// but it is only a transitional solution until the Datapool is -// implemented decentrally - -class HkSwitchHelper : public ExecutableObjectIF, public CommandsActionsIF { - public: - static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::HK; - static const Event SWITCHING_TM_FAILED = - MAKE_EVENT(1, severity::LOW); //!< Commanding the HK Service failed, p1: error code, p2 - //!< action: 0 disable / 1 enable - - HkSwitchHelper(EventReportingProxyIF* eventProxy); - virtual ~HkSwitchHelper(); - - ReturnValue_t initialize(); - - virtual ReturnValue_t performOperation(uint8_t operationCode = 0); - - ReturnValue_t switchHK(SerializeIF* sids, bool enable); - - virtual void setTaskIF(PeriodicTaskIF* task_){}; - - protected: - virtual void stepSuccessfulReceived(ActionId_t actionId, uint8_t step); - virtual void stepFailedReceived(ActionId_t actionId, uint8_t step, ReturnValue_t returnCode); - virtual void dataReceived(ActionId_t actionId, const uint8_t* data, uint32_t size); - virtual void completionSuccessfulReceived(ActionId_t actionId); - virtual void completionFailedReceived(ActionId_t actionId, ReturnValue_t returnCode); - virtual MessageQueueIF* getCommandQueuePtr(); - - private: - CommandActionHelper commandActionHelper; - MessageQueueIF* actionQueue; - EventReportingProxyIF* eventProxy; -}; - -#endif /* FRAMEWORK_DATAPOOL_HKSWITCHHELPER_H_ */ diff --git a/src/fsfw/datapoollocal/LocalDataPoolManager.cpp b/src/fsfw/datapoollocal/LocalDataPoolManager.cpp index 9057de31b..acfa23c55 100644 --- a/src/fsfw/datapoollocal/LocalDataPoolManager.cpp +++ b/src/fsfw/datapoollocal/LocalDataPoolManager.cpp @@ -84,8 +84,8 @@ ReturnValue_t LocalDataPoolManager::initializeHousekeepingPoolEntriesOnce() { return result; } - printWarningOrError(sif::OutputTypes::OUT_WARNING, "initialize", HasReturnvaluesIF::RETURN_FAILED, - "The map should only be initialized once"); + printWarningOrError(sif::OutputTypes::OUT_WARNING, "initializeHousekeepingPoolEntriesOnce", + HasReturnvaluesIF::RETURN_FAILED, "The map should only be initialized once"); return HasReturnvaluesIF::RETURN_OK; } diff --git a/src/fsfw/internalerror/InternalErrorReporter.cpp b/src/fsfw/internalerror/InternalErrorReporter.cpp index e7088e2cf..fa16ec3f6 100644 --- a/src/fsfw/internalerror/InternalErrorReporter.cpp +++ b/src/fsfw/internalerror/InternalErrorReporter.cpp @@ -57,6 +57,9 @@ ReturnValue_t InternalErrorReporter::performOperation(uint8_t opCode) { internalErrorDataset.storeHits.value += newStoreHits; internalErrorDataset.tmHits.value += newTmHits; internalErrorDataset.setValidity(true, true); + if ((newQueueHits != 0) or (newStoreHits != 0) or (newTmHits != 0)) { + internalErrorDataset.setChanged(true); + } } } @@ -77,14 +80,6 @@ uint32_t InternalErrorReporter::getAndResetQueueHits() { return value; } -uint32_t InternalErrorReporter::getQueueHits() { - uint32_t value; - mutex->lockMutex(timeoutType, timeoutMs); - value = queueHits; - mutex->unlockMutex(); - return value; -} - void InternalErrorReporter::incrementQueueHits() { mutex->lockMutex(timeoutType, timeoutMs); queueHits++; @@ -100,14 +95,6 @@ uint32_t InternalErrorReporter::getAndResetTmHits() { return value; } -uint32_t InternalErrorReporter::getTmHits() { - uint32_t value; - mutex->lockMutex(timeoutType, timeoutMs); - value = tmHits; - mutex->unlockMutex(); - return value; -} - void InternalErrorReporter::incrementTmHits() { mutex->lockMutex(timeoutType, timeoutMs); tmHits++; @@ -125,14 +112,6 @@ uint32_t InternalErrorReporter::getAndResetStoreHits() { return value; } -uint32_t InternalErrorReporter::getStoreHits() { - uint32_t value; - mutex->lockMutex(timeoutType, timeoutMs); - value = storeHits; - mutex->unlockMutex(); - return value; -} - void InternalErrorReporter::incrementStoreHits() { mutex->lockMutex(timeoutType, timeoutMs); storeHits++; diff --git a/src/fsfw/internalerror/InternalErrorReporter.h b/src/fsfw/internalerror/InternalErrorReporter.h index 987111396..549be4bdc 100644 --- a/src/fsfw/internalerror/InternalErrorReporter.h +++ b/src/fsfw/internalerror/InternalErrorReporter.h @@ -46,11 +46,11 @@ class InternalErrorReporter : public SystemObject, virtual ReturnValue_t initializeAfterTaskCreation() override; virtual ReturnValue_t performOperation(uint8_t opCode) override; - virtual void queueMessageNotSent(); + virtual void queueMessageNotSent() override; - virtual void lostTm(); + virtual void lostTm() override; - virtual void storeFull(); + virtual void storeFull() override; virtual void setTaskIF(PeriodicTaskIF* task) override; @@ -74,15 +74,12 @@ class InternalErrorReporter : public SystemObject, uint32_t storeHits = 0; uint32_t getAndResetQueueHits(); - uint32_t getQueueHits(); void incrementQueueHits(); uint32_t getAndResetTmHits(); - uint32_t getTmHits(); void incrementTmHits(); uint32_t getAndResetStoreHits(); - uint32_t getStoreHits(); void incrementStoreHits(); }; diff --git a/src/fsfw/internalerror/InternalErrorReporterIF.h b/src/fsfw/internalerror/InternalErrorReporterIF.h index 9eb8e7d7e..61bb52e7b 100644 --- a/src/fsfw/internalerror/InternalErrorReporterIF.h +++ b/src/fsfw/internalerror/InternalErrorReporterIF.h @@ -1,22 +1,34 @@ #ifndef INTERNALERRORREPORTERIF_H_ #define INTERNALERRORREPORTERIF_H_ +/** + * @brief Interface which is used to report internal errors like full message queues or stores. + * @details + * This interface smust be used for the InteralErrorReporter object. + * It should be used to indicate that there was a Problem with Queues or Stores. + * + * It can be used to report missing Telemetry which could not be sent due to a internal problem. + * + */ class InternalErrorReporterIF { public: virtual ~InternalErrorReporterIF() {} - /** - * Thread safe + * @brief Function to be called if a message queue could not be sent. + * @details OSAL Implementations should call this function to indicate that + * a message was lost. + * + * Implementations are required to be Thread safe */ virtual void queueMessageNotSent() = 0; - /** - * Thread safe + * @brief Function to be called if Telemetry could not be sent + * @details Implementations must be Thread safe */ virtual void lostTm() = 0; - /** - * Thread safe + * @brief Function to be called if a onboard storage is full + * @details Implementations must be Thread safe */ virtual void storeFull() = 0; }; diff --git a/src/fsfw/osal/host/MessageQueue.cpp b/src/fsfw/osal/host/MessageQueue.cpp index db66b6715..d328fb820 100644 --- a/src/fsfw/osal/host/MessageQueue.cpp +++ b/src/fsfw/osal/host/MessageQueue.cpp @@ -125,6 +125,13 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, memcpy(targetQueue->messageQueue.back().data(), message->getBuffer(), message->getMaximumMessageSize()); } else { + if (not ignoreFault) { + InternalErrorReporterIF* internalErrorReporter = + ObjectManager::instance()->get(objects::INTERNAL_ERROR_REPORTER); + if (internalErrorReporter != nullptr) { + internalErrorReporter->queueMessageNotSent(); + } + } return MessageQueueIF::FULL; } return HasReturnvaluesIF::RETURN_OK; diff --git a/tests/src/fsfw_tests/unit/CMakeLists.txt b/tests/src/fsfw_tests/unit/CMakeLists.txt index fc73f7b50..a83e2f7f8 100644 --- a/tests/src/fsfw_tests/unit/CMakeLists.txt +++ b/tests/src/fsfw_tests/unit/CMakeLists.txt @@ -23,3 +23,4 @@ add_subdirectory(timemanager) add_subdirectory(tmtcpacket) add_subdirectory(cfdp) add_subdirectory(hal) +add_subdirectory(internalerror) diff --git a/tests/src/fsfw_tests/unit/internalerror/CMakeLists.txt b/tests/src/fsfw_tests/unit/internalerror/CMakeLists.txt new file mode 100644 index 000000000..d49ce0067 --- /dev/null +++ b/tests/src/fsfw_tests/unit/internalerror/CMakeLists.txt @@ -0,0 +1,3 @@ +target_sources(${FSFW_TEST_TGT} PRIVATE + TestInternalErrorReporter.cpp +) diff --git a/tests/src/fsfw_tests/unit/internalerror/TestInternalErrorReporter.cpp b/tests/src/fsfw_tests/unit/internalerror/TestInternalErrorReporter.cpp new file mode 100644 index 000000000..92c3ff22d --- /dev/null +++ b/tests/src/fsfw_tests/unit/internalerror/TestInternalErrorReporter.cpp @@ -0,0 +1,118 @@ +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "fsfw/action/ActionMessage.h" +#include "fsfw/ipc/CommandMessage.h" +#include "fsfw/ipc/MessageQueueMessage.h" +#include "fsfw/objectmanager/frameworkObjects.h" +#include "fsfw_tests/unit/CatchDefinitions.h" +#include "fsfw_tests/unit/mocks/PeriodicTaskIFMock.h" + +TEST_CASE("Internal Error Reporter", "[TestInternalError]") { + PeriodicTaskMock task(10); + ObjectManagerIF* manager = ObjectManager::instance(); + if (manager == nullptr) { + FAIL(); + } + InternalErrorReporter* internalErrorReporter = dynamic_cast( + ObjectManager::instance()->get(objects::INTERNAL_ERROR_REPORTER)); + if (internalErrorReporter == nullptr) { + FAIL(); + } + task.addComponent(objects::INTERNAL_ERROR_REPORTER); + MessageQueueIF* testQueue = QueueFactory::instance()->createMessageQueue(1); + MessageQueueIF* hkQueue = QueueFactory::instance()->createMessageQueue(1); + internalErrorReporter->getSubscriptionInterface()->subscribeForSetUpdateMessage( + InternalErrorDataset::ERROR_SET_ID, objects::NO_OBJECT, hkQueue->getId(), true); + StorageManagerIF* ipcStore = ObjectManager::instance()->get(objects::IPC_STORE); + SECTION("MessageQueueFull") { + CommandMessage message; + ActionMessage::setCompletionReply(&message, 10, true); + auto result = hkQueue->sendMessage(testQueue->getId(), &message); + REQUIRE(result == retval::CATCH_OK); + uint32_t queueHits = 0; + uint32_t lostTm = 0; + uint32_t storeHits = 0; + /* We don't know if another test caused a queue Hit so we will enforce one, + then remeber the queueHit count and force another hit */ + internalErrorReporter->queueMessageNotSent(); + internalErrorReporter->performOperation(0); + { + CommandMessage hkMessage; + result = hkQueue->receiveMessage(&hkMessage); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(hkMessage.getCommand() == HousekeepingMessage::UPDATE_SNAPSHOT_SET); + store_address_t storeAddress; + gp_id_t gpid = + HousekeepingMessage::getUpdateSnapshotVariableCommand(&hkMessage, &storeAddress); + REQUIRE(gpid.objectId == objects::INTERNAL_ERROR_REPORTER); + // We need the object ID of the reporter here (NO_OBJECT) + InternalErrorDataset dataset(objects::INTERNAL_ERROR_REPORTER); + CCSDSTime::CDS_short time; + ConstAccessorPair data = ipcStore->getData(storeAddress); + REQUIRE(data.first == HasReturnvaluesIF::RETURN_OK); + HousekeepingSnapshot hkSnapshot(&time, &dataset); + const uint8_t* buffer = data.second.data(); + size_t size = data.second.size(); + result = hkSnapshot.deSerialize(&buffer, &size, SerializeIF::Endianness::MACHINE); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + // Remember the amount of queueHits before to see the increase + queueHits = dataset.queueHits.value; + lostTm = dataset.tmHits.value; + storeHits = dataset.storeHits.value; + } + result = hkQueue->sendMessage(testQueue->getId(), &message); + REQUIRE(result == MessageQueueIF::FULL); + internalErrorReporter->lostTm(); + internalErrorReporter->storeFull(); + { + internalErrorReporter->performOperation(0); + CommandMessage hkMessage; + result = hkQueue->receiveMessage(&hkMessage); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(hkMessage.getCommand() == HousekeepingMessage::UPDATE_SNAPSHOT_SET); + store_address_t storeAddress; + gp_id_t gpid = + HousekeepingMessage::getUpdateSnapshotVariableCommand(&hkMessage, &storeAddress); + REQUIRE(gpid.objectId == objects::INTERNAL_ERROR_REPORTER); + + ConstAccessorPair data = ipcStore->getData(storeAddress); + REQUIRE(data.first == HasReturnvaluesIF::RETURN_OK); + CCSDSTime::CDS_short time; + // We need the object ID of the reporter here (NO_OBJECT) + InternalErrorDataset dataset(objects::INTERNAL_ERROR_REPORTER); + HousekeepingSnapshot hkSnapshot(&time, &dataset); + const uint8_t* buffer = data.second.data(); + size_t size = data.second.size(); + result = hkSnapshot.deSerialize(&buffer, &size, SerializeIF::Endianness::MACHINE); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + // Test that we had one more queueHit + REQUIRE(dataset.queueHits.value == (queueHits + 1)); + REQUIRE(dataset.tmHits.value == (lostTm + 1)); + REQUIRE(dataset.storeHits.value == (storeHits + 1)); + } + // Complete Coverage + internalErrorReporter->setDiagnosticPrintout(true); + internalErrorReporter->setMutexTimeout(MutexIF::TimeoutType::BLOCKING, 0); + { + // Message Queue Id + MessageQueueId_t id = internalErrorReporter->getCommandQueue(); + REQUIRE(id != MessageQueueIF::NO_QUEUE); + CommandMessage message; + sid_t sid(objects::INTERNAL_ERROR_REPORTER, InternalErrorDataset::ERROR_SET_ID); + HousekeepingMessage::setToggleReportingCommand(&message, sid, true, false); + result = hkQueue->sendMessage(id, &message); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + internalErrorReporter->performOperation(0); + } + } + QueueFactory::instance()->deleteMessageQueue(testQueue); + QueueFactory::instance()->deleteMessageQueue(hkQueue); +} \ No newline at end of file diff --git a/tests/src/fsfw_tests/unit/mocks/PeriodicTaskIFMock.h b/tests/src/fsfw_tests/unit/mocks/PeriodicTaskIFMock.h new file mode 100644 index 000000000..ebd9a2e70 --- /dev/null +++ b/tests/src/fsfw_tests/unit/mocks/PeriodicTaskIFMock.h @@ -0,0 +1,37 @@ +#ifndef FSFW_UNITTEST_TESTS_MOCKS_PERIODICTASKMOCK_H_ +#define FSFW_UNITTEST_TESTS_MOCKS_PERIODICTASKMOCK_H_ + +#include +#include + +class PeriodicTaskMock : public PeriodicTaskIF { + public: + PeriodicTaskMock(uint32_t period = 5) : period(period) {} + /** + * @brief A virtual destructor as it is mandatory for interfaces. + */ + virtual ~PeriodicTaskMock() {} + /** + * @brief With the startTask method, a created task can be started + * for the first time. + */ + virtual ReturnValue_t startTask() override { return HasReturnvaluesIF::RETURN_OK; }; + + virtual ReturnValue_t addComponent(object_id_t object) override { + ExecutableObjectIF* executableObject = + ObjectManager::instance()->get(objects::INTERNAL_ERROR_REPORTER); + if (executableObject == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + executableObject->setTaskIF(this); + executableObject->initializeAfterTaskCreation(); + return HasReturnvaluesIF::RETURN_OK; + }; + + virtual ReturnValue_t sleepFor(uint32_t ms) override { return HasReturnvaluesIF::RETURN_OK; }; + + virtual uint32_t getPeriodMs() const override { return period; }; + uint32_t period; +}; + +#endif // FSFW_UNITTEST_TESTS_MOCKS_PERIODICTASKMOCK_H_ \ No newline at end of file diff --git a/tests/src/fsfw_tests/unit/osal/TestMessageQueue.cpp b/tests/src/fsfw_tests/unit/osal/TestMessageQueue.cpp index 232ffb94b..11c0739b1 100644 --- a/tests/src/fsfw_tests/unit/osal/TestMessageQueue.cpp +++ b/tests/src/fsfw_tests/unit/osal/TestMessageQueue.cpp @@ -35,4 +35,25 @@ TEST_CASE("MessageQueue Basic Test", "[TestMq]") { senderId = testReceiverMq->getLastPartner(); CHECK(senderId == testSenderMqId); } + SECTION("Test Full") { + auto result = testSenderMq->sendMessage(testReceiverMqId, &testMessage); + REQUIRE(result == retval::CATCH_OK); + result = testSenderMq->sendMessage(testReceiverMqId, &testMessage); + REQUIRE(result == MessageQueueIF::FULL); + // We try another message + result = testSenderMq->sendMessage(testReceiverMqId, &testMessage); + REQUIRE(result == MessageQueueIF::FULL); + MessageQueueMessage recvMessage; + result = testReceiverMq->receiveMessage(&recvMessage); + REQUIRE(result == retval::CATCH_OK); + CHECK(recvMessage.getData()[0] == 42); + result = testSenderMq->sendMessage(testReceiverMqId, &testMessage); + REQUIRE(result == retval::CATCH_OK); + result = testReceiverMq->receiveMessage(&recvMessage); + REQUIRE(result == retval::CATCH_OK); + CHECK(recvMessage.getData()[0] == 42); + } + // We have to clear MQs ourself ATM + QueueFactory::instance()->deleteMessageQueue(testSenderMq); + QueueFactory::instance()->deleteMessageQueue(testReceiverMq); }