diff --git a/CHANGELOG.md b/CHANGELOG.md index 80338446..f12aa90e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,13 +8,43 @@ and this project adheres to [Semantic Versioning](http://semver.org/). # [unreleased] -# [v6.0.0] +## Fixes + +- PUS Health Service: Size check for set health command. +- PUS Health Service: Perform operation completion for announce health command. + +# [v6.0.0] 2023-02-10 ## Fixes +- Mode Service: Add allowed subservice + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/739 +- `CService200ModeManagement`: Various bugfixes which lead to now execution complete being generated + on mode announcements, duplicate mode reply generated on announce commands, and the mode read + subservice not working properly. + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/736 +- Memory leak fixes for the TCP/IP TMTC bridge. + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/737 +- `Service9TimeManagement`: Fix the time dump at the `SET_TIME` subservice: Include clock timeval + seconds instead of uptime. + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/726 +- HAL MGM3100 Handler: Use axis specific gain/scaling factors. Previously, + only the X scaling factor was used. + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/724 +- HAL MGM3100 Handler: Z value was previously calculated with bytes of the X value. + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/733 +- DHB `setNormalDatapoolEntriesInvalid`: The default implementation did not set the validity + to false correctly because the `read` and `write` calls were missing. + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/728 +- PUS TMTC creator module: Sequence flags were set to continuation segment (0b00) instead + of the correct unsegmented flags (0b11) as specified in the standard. + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/727 +- TC Scheduler Service 11: Add size and CRC check for contained TC. + Bug: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/issues/719 + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/720 - Only delete health table entry in `HealthHelper` destructor if health table was set. - PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/710/files + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/710 - I2C Bugfixes: Do not keep iterator as member and fix some incorrect handling with the iterator. Also properly reset the reply size for successfull transfers and erroneous transfers. PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/700 @@ -24,22 +54,82 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - `TcpTmTcServer.cpp`: The server was actually not able to handle CCSDS packets which were clumped together. This has been fixed now. PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/673 +- `CServiceHealthCommanding`: Add announce all health info implementation + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/725 +- various fixes related to linux Unittests and memory leaks + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/715 +- small fix to allow teardown handling + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/713 +- fix compiler warning for fixed array list copy ctor + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/704 +- missing include + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/703 +- defaultconfig did not build anymore + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/702 +- hotfix + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/699 +- small fix for helper + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/698 +- missing retval conv + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/697 +- DHB Countdown Bug + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/693 +- doc corrections + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/687 +- better error printout + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/686 +- include correction + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/683 +- better warning for missing include paths + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/676 +- Service 11 regression + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/670 ## Added +- Empty constructor for `CdsShortTimeStamper` which does not do an object manager registration. + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/730 +- `Service9TimeManagement`: Add `DUMP_TIME` (129) subservice. +- `TcpTmTcServer`: Allow setting the `SO_REUSEADDR` and `SO_REUSEPORT` + option on the TCP server. CTOR prototype has changed and expects an explicit + TCP configuration struct to be passed. + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/722 - `DleParser` helper class to parse DLE encoded packets from a byte stream. PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/711 - `UioMapper` is able to resolve symlinks now. PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/709 - Add new `UnsignedByteField` class PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/660 +- publish documentation for development and master branch + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/681 +- Add Linux HAL options + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/663 +- Expand SerializeIF + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/656 +- PUS Service 11: Additional Safety Check + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/666 +- improvements for auto-formatter script + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/665 +- provide a weak print char impl + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/674 + +## Removed + +- now that doc server is up, remove markdown files + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/688 +- remove bsp specific code + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/679 ## Changes +- `CService201HealthCommanding` renamed to `CServiceHealthCommanding`, + service ID customizable now. `CServiceHealthCommanding` expects configuration struct + `HealthServiceCfg` now + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/725 - `AcceptsTelemetryIF`: `getReportReceptionQueue` is const now PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/712 - Moved some container returnvalues to dedicated header and namespace - to they can be used without template specification. + so they can be used without template specification. PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/707 - Remove default secondary header argument for `uint16_t getTcSpacePacketIdFromApid(uint16_t apid, bool secondaryHeaderFlag)` and @@ -69,18 +159,41 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - `DeviceHandlerBase`: New signature of `handleDeviceTm` which expects a `const SerializeIF&` and additional helper variant which expects `const uint8_t*` PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/671 -- Move some generic `StorageManagerIF` implementations from `LocalPool` to - interface itself so it can be re-used more easily. Also add new - abstract function `bool hasDataAtId(store_address_t storeId) const`. - PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/685 - Improvements for `AcceptsTelemetryIF` and `AcceptsTelecommandsIF`: - Make functions `const` where it makes sense - Add `const char* getName const` abstract function PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/684 -- Move some generic `StorageManagerIF` implementations from `LocalPool` to - interface itself so it can be re-used more easily. Also add new - abstract function `bool hasDataAtId(store_address_t storeId) const`. - PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/685 +- Generic TMTC Bridge Update + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/734 +- comment tweak to event parser can read everything + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/732 +- CMakeLists file updates + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/731 +- improve srv20 error messages + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/723 +- I2C Linux: remove duplicate printout + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/718 +- printout handling improvements + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/717 +- vec getter, reset for content + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/716 +- updates for source sequence counter + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/714 +- SP reader getPacketData is const now + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/708 +- refactoring of serial drivers for linux + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/705 +- Local Pool Update Remove Add Data Ignore Fault Argument + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/701 +- Switch to new documentation server + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/694 +- Windows Tweaks + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/691 +- Refactor Local Pool API + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/667 +- group MGM data in local pool vectors + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/664 + ## CFDP @@ -100,7 +213,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). implementation without an extra component PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/682 -# [v5.0.0] 25.07.2022 +# [v5.0.0] 2022-07-25 ## Changes diff --git a/CMakeLists.txt b/CMakeLists.txt index 8308f523..5eddde7f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,7 +13,7 @@ list(APPEND CMAKE_MODULE_PATH # Version file handling # # ############################################################################## -set(FSFW_VERSION_IF_GIT_FAILS 5) +set(FSFW_VERSION_IF_GIT_FAILS 6) set(FSFW_SUBVERSION_IF_GIT_FAILS 0) set(FSFW_REVISION_IF_GIT_FAILS 0) @@ -153,12 +153,12 @@ if(FSFW_BUILD_TESTS) "${MSG_PREFIX} Building the FSFW unittests in addition to the static library" ) # Check whether the user has already installed Catch2 first - find_package(Catch2 ${FSFW_CATCH2_LIB_MAJOR_VERSION}) + find_package(Catch2 ${FSFW_CATCH2_LIB_MAJOR_VERSION} QUIET) # Not installed, so use FetchContent to download and provide Catch2 if(NOT Catch2_FOUND) message( STATUS - "${MSG_PREFIX} Catch2 installation not found. Downloading Catch2 library with FetchContent" + "${MSG_PREFIX} Catch2 installation not found. Downloading Catch2 library with FetchContent." ) include(FetchContent) @@ -201,8 +201,8 @@ find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} QUIET) if(NOT ${FSFW_ETL_LIB_NAME}_FOUND) message( STATUS - "${MSG_PREFIX} No ETL installation was found with find_package. Installing and providing " - "etl with FindPackage") + "${MSG_PREFIX} ETL installation not found. Downloading ETL with FetchContent." + ) include(FetchContent) FetchContent_Declare( diff --git a/automation/Jenkinsfile b/automation/Jenkinsfile index 27136606..64c32237 100644 --- a/automation/Jenkinsfile +++ b/automation/Jenkinsfile @@ -1,45 +1,87 @@ pipeline { environment { - BUILDDIR = 'cmake-build-tests' + BUILDDIR_HOST = 'cmake-build-tests-host' + BUILDDIR_LINUX = 'cmake-build-tests-linux' DOCDDIR = 'cmake-build-documentation' } agent { docker { image 'fsfw-ci:d6' - args '--network host' + args '--network host --sysctl fs.mqueue.msg_max=100' } } stages { - stage('Clean') { - steps { - sh 'rm -rf $BUILDDIR' - } - } - stage('Configure') { - steps { - dir(BUILDDIR) { - sh 'cmake -DFSFW_OSAL=host -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..' + stage('Host') { + stages{ + stage('Clean') { + steps { + sh 'rm -rf $BUILDDIR_HOST' + } + } + stage('Configure') { + steps { + dir(BUILDDIR_HOST) { + sh 'cmake -DFSFW_OSAL=host -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..' + } + } + } + stage('Build') { + steps { + dir(BUILDDIR_HOST) { + sh 'cmake --build . -j4' + } + } + } + stage('Unittests') { + steps { + dir(BUILDDIR_HOST) { + sh 'cmake --build . -- fsfw-tests_coverage -j4' + } + } + } + stage('Valgrind') { + steps { + dir(BUILDDIR_HOST) { + sh 'valgrind --leak-check=full --error-exitcode=1 ./fsfw-tests' + } + } } } } - stage('Build') { - steps { - dir(BUILDDIR) { - sh 'cmake --build . -j4' + stage('Linux') { + stages{ + stage('Clean') { + steps { + sh 'rm -rf $BUILDDIR_LINUX' + } } - } - } - stage('Unittests') { - steps { - dir(BUILDDIR) { - sh 'cmake --build . -- fsfw-tests_coverage -j4' + stage('Configure') { + steps { + dir(BUILDDIR_LINUX) { + sh 'cmake -DFSFW_OSAL=linux -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..' + } + } } - } - } - stage('Valgrind') { - steps { - dir(BUILDDIR) { - sh 'valgrind --leak-check=full --error-exitcode=1 ./fsfw-tests' + stage('Build') { + steps { + dir(BUILDDIR_LINUX) { + sh 'cmake --build . -j4' + } + } + } + stage('Unittests') { + steps { + dir(BUILDDIR_LINUX) { + sh 'cmake --build . -- fsfw-tests_coverage -j4' + } + } + } + stage('Valgrind') { + steps { + dir(BUILDDIR_LINUX) { + sh 'valgrind --leak-check=full --error-exitcode=1 ./fsfw-tests' + } + } } } } diff --git a/scripts/check_release.py b/scripts/check_release.py new file mode 100755 index 00000000..eb5c89f9 --- /dev/null +++ b/scripts/check_release.py @@ -0,0 +1,110 @@ +#! /bin/python + + +import argparse +import json +import urllib.request +import re +from pathlib import Path + +def main() -> None: + parser = argparse.ArgumentParser( + description="List undocumented PRs" + ) + parser.add_argument("-v", "--version", type=str, required=True) + args = parser.parse_args() + + match = re.search("([0-9]+\.[0-9]+\.[0-9]+)", args.version) + + if not match: + print("invalid version") + exit(1) + + version = "v" + match.group(1) + + print("looking for milestone for " + version + " ...") + + + with urllib.request.urlopen("https://egit.irs.uni-stuttgart.de/api/v1/repos/fsfw/fsfw/milestones?name=" + version) as milestone_json: + milestones = json.load(milestone_json) + if (len(milestones) == 0): + print("did not find any milestone") + exit(1) + if (len(milestones) > 1): + print("found multiple milestons") + milestone_title = milestones[0]['title'] + milestone = str(milestones[0]['id']) + print("Using Milestone \""+ milestone_title + "\" with id " + milestone) + + milestone_prs = [] + + page = 1 + last_count = 1; + while last_count != 0: + with urllib.request.urlopen("https://egit.irs.uni-stuttgart.de/api/v1/repos/fsfw/fsfw/pulls?state=closed&milestone=" + str(milestone) + "&limit=100&page=" + str(page)) as pull_requests_json: + pull_requests = json.load(pull_requests_json) + for pr in pull_requests: + milestone_prs.append({'number': str(pr['number']), 'title' : pr['title']}) + page += 1 + last_count = len(pull_requests) + + print("Found " + str(len(milestone_prs)) + " closed PRs in Milestone") + + print("looking for CHANGELOG.md ...") + + path = Path(".") + + files = list(path.glob("CHANGELOG.md")) + + if (len(files) != 1): + files = list(path.glob("../CHANGELOG.md")) + + if (len(files) != 1): + print("did not find CHANGELOG.md. Run script in either root directory or scripts subfolder.") + exit(1) + + print("Scanning CHANGELOG.md ...") + + changelog_prs = [] + + with open(files[0]) as changelog: + line = changelog.readline() + while (line): + #print("line: " + line) + match = re.search("\#.+(v[0-9]+\.[0-9]+\.[0-9]+)", line) + if (match): + if match.group(1) == version: + #print("found version") + line = changelog.readline() + continue + else: + #print("done with " + match.group(1)) + break + + match = re.search("PR: https://egit\.irs\.uni-stuttgart\.de/fsfw/fsfw/pulls/([0-9]+)", line) + if match: + changelog_prs.append(match.group(1)) + + line = changelog.readline() + + print("Found " + str(len(changelog_prs)) + " PRs in CHANGELOG.md") + + print("") + + copy_array = changelog_prs.copy() + print("PRs in CHANGELOG.md that are not in Milestone:") + for pr in milestone_prs: + if pr['number'] in copy_array: + copy_array.remove(pr['number']) + for pr in copy_array: + print("https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/" + pr) + + print("") + + print("PRs in milestone that are not in CHANGELOG.md:") + + for pr in milestone_prs: + if pr['number'] not in changelog_prs: + print("- " + pr['title'] + "\n PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/" + pr['number']) + +main() diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp index 60966501..bc528128 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp @@ -1,5 +1,6 @@ #include "fsfw/devicehandlers/DeviceHandlerBase.h" +#include "fsfw/datapool/PoolReadGuard.h" #include "fsfw/datapoollocal/LocalPoolVariable.h" #include "fsfw/devicehandlers/AcceptsDeviceResponsesIF.h" #include "fsfw/devicehandlers/DeviceTmReportingWrapper.h" @@ -1508,7 +1509,10 @@ DeviceCommandId_t DeviceHandlerBase::getPendingCommand() const { void DeviceHandlerBase::setNormalDatapoolEntriesInvalid() { for (const auto& reply : deviceReplyMap) { if (reply.second.dataSet != nullptr) { - reply.second.dataSet->setValidity(false, true); + PoolReadGuard pg(reply.second.dataSet); + if (pg.getReadResult() == returnvalue::OK) { + reply.second.dataSet->setValidity(false, true); + } } } } diff --git a/src/fsfw/events/EventManager.cpp b/src/fsfw/events/EventManager.cpp index f4466817..8bd26282 100644 --- a/src/fsfw/events/EventManager.cpp +++ b/src/fsfw/events/EventManager.cpp @@ -23,6 +23,7 @@ EventManager::EventManager(object_id_t setObjectId) } EventManager::~EventManager() { + listenerList.clear(); QueueFactory::instance()->deleteMessageQueue(eventReportQueue); MutexFactory::instance()->deleteMutex(mutex); } @@ -61,9 +62,14 @@ ReturnValue_t EventManager::registerListener(MessageQueueId_t listener, if (!result.second) { return returnvalue::FAILED; } + return returnvalue::OK; } +ReturnValue_t EventManager::unregisterListener(MessageQueueId_t listener) { + return listenerList.erase(listener) == 1 ? returnvalue::OK : returnvalue::FAILED; +} + ReturnValue_t EventManager::subscribeToEvent(MessageQueueId_t listener, EventId_t event) { return subscribeToEventRange(listener, event); } diff --git a/src/fsfw/events/EventManager.h b/src/fsfw/events/EventManager.h index 70245f5d..0e6dace0 100644 --- a/src/fsfw/events/EventManager.h +++ b/src/fsfw/events/EventManager.h @@ -31,6 +31,7 @@ class EventManager : public EventManagerIF, public ExecutableObjectIF, public Sy MessageQueueId_t getEventReportQueue(); ReturnValue_t registerListener(MessageQueueId_t listener, bool forwardAllButSelected = false); + ReturnValue_t unregisterListener(MessageQueueId_t listener) override; ReturnValue_t subscribeToEvent(MessageQueueId_t listener, EventId_t event); ReturnValue_t subscribeToAllEventsFrom(MessageQueueId_t listener, object_id_t object); ReturnValue_t subscribeToEventRange(MessageQueueId_t listener, EventId_t idFrom = 0, diff --git a/src/fsfw/events/EventManagerIF.h b/src/fsfw/events/EventManagerIF.h index adb61f2b..12014090 100644 --- a/src/fsfw/events/EventManagerIF.h +++ b/src/fsfw/events/EventManagerIF.h @@ -18,6 +18,7 @@ class EventManagerIF { virtual ReturnValue_t registerListener(MessageQueueId_t listener, bool forwardAllButSelected = false) = 0; + virtual ReturnValue_t unregisterListener(MessageQueueId_t listener) = 0; virtual ReturnValue_t subscribeToEvent(MessageQueueId_t listener, EventId_t event) = 0; virtual ReturnValue_t subscribeToAllEventsFrom(MessageQueueId_t listener, object_id_t object) = 0; virtual ReturnValue_t unsubscribeFromAllEvents(MessageQueueId_t listener, object_id_t object) = 0; diff --git a/src/fsfw/fdir/FailureIsolationBase.cpp b/src/fsfw/fdir/FailureIsolationBase.cpp index 28df16d8..0d3b0214 100644 --- a/src/fsfw/fdir/FailureIsolationBase.cpp +++ b/src/fsfw/fdir/FailureIsolationBase.cpp @@ -23,7 +23,7 @@ FailureIsolationBase::~FailureIsolationBase() { #endif return; } - manager->unsubscribeFromAllEvents(eventQueue->getId(), ownerId); + manager->unregisterListener(eventQueue->getId()); QueueFactory::instance()->deleteMessageQueue(eventQueue); } diff --git a/src/fsfw/globalfunctions/matching/MatchTree.h b/src/fsfw/globalfunctions/matching/MatchTree.h index 0c31cf2a..69f660d3 100644 --- a/src/fsfw/globalfunctions/matching/MatchTree.h +++ b/src/fsfw/globalfunctions/matching/MatchTree.h @@ -24,7 +24,7 @@ class MatchTree : public SerializeableMatcherIF, public BinaryTree>(root.element), maxDepth(maxDepth) {} MatchTree() : BinaryTree>(), maxDepth(-1) {} - virtual ~MatchTree() {} + virtual ~MatchTree() { clear(); } virtual bool match(T number) override { return matchesTree(number); } bool matchesTree(T number) { iterator iter = this->begin(); @@ -176,6 +176,45 @@ class MatchTree : public SerializeableMatcherIF, public BinaryTree>::rootNode; + + if (localRoot == nullptr) { + return; + } + + Node* node = localRoot->left; + + while (true) { + if (node->left != nullptr) { + node = node->left; + continue; + } + if (node->right != nullptr) { + node = node->right; + continue; + } + if (node->parent == nullptr) { + // this is the root node with no children + if (node->value != nullptr) { + cleanUpElement(iterator(node)); + } + return; + } + // leaf + { + Node* parent = node->parent; + if (parent->left == node) { + parent->left = nullptr; + } else { + parent->right = nullptr; + } + cleanUpElement(iterator(node)); + node = parent; + } + } + } + virtual ReturnValue_t cleanUpElement(iterator position) { return returnvalue::OK; } bool matchSubtree(iterator iter, T number) { diff --git a/src/fsfw/health/HasHealthIF.h b/src/fsfw/health/HasHealthIF.h index 77a1c12f..16666bbc 100644 --- a/src/fsfw/health/HasHealthIF.h +++ b/src/fsfw/health/HasHealthIF.h @@ -16,26 +16,24 @@ class HasHealthIF { }; static const uint8_t INTERFACE_ID = CLASS_ID::HAS_HEALTH_IF; - static const ReturnValue_t OBJECT_NOT_HEALTHY = MAKE_RETURN_CODE(1); - static const ReturnValue_t INVALID_HEALTH_STATE = MAKE_RETURN_CODE(2); + static constexpr ReturnValue_t OBJECT_NOT_HEALTHY = returnvalue::makeCode(INTERFACE_ID, 1); + static constexpr ReturnValue_t INVALID_HEALTH_STATE = returnvalue::makeCode(INTERFACE_ID, 2); + static constexpr ReturnValue_t IS_EXTERNALLY_CONTROLLED = returnvalue::makeCode(INTERFACE_ID, 3); static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SYSTEM_MANAGER_1; + //! P1: New Health, P2: Old Health static const Event HEALTH_INFO = MAKE_EVENT(6, severity::INFO); static const Event CHILD_CHANGED_HEALTH = MAKE_EVENT(7, severity::INFO); static const Event CHILD_PROBLEMS = MAKE_EVENT(8, severity::LOW); - static const Event OVERWRITING_HEALTH = - MAKE_EVENT(9, severity::LOW); //!< Assembly overwrites health information of children to keep - //!< satellite alive. - static const Event TRYING_RECOVERY = - MAKE_EVENT(10, severity::MEDIUM); //!< Someone starts a recovery of a component (typically - //!< power-cycle). No parameters. - static const Event RECOVERY_STEP = - MAKE_EVENT(11, severity::MEDIUM); //!< Recovery is ongoing. Comes twice during recovery. P1: - //!< 0 for the first, 1 for the second event. P2: 0 - static const Event RECOVERY_DONE = MAKE_EVENT( - 12, - severity::MEDIUM); //!< Recovery was completed. Not necessarily successful. No parameters. - + //! Assembly overwrites health information of children to keep satellite alive. + static const Event OVERWRITING_HEALTH = MAKE_EVENT(9, severity::LOW); + //! Someone starts a recovery of a component (typically power-cycle). No parameters. + static const Event TRYING_RECOVERY = MAKE_EVENT(10, severity::MEDIUM); + //! Recovery is ongoing. Comes twice during recovery. + //! P1: 0 for the first, 1 for the second event. P2: 0 + static const Event RECOVERY_STEP = MAKE_EVENT(11, severity::MEDIUM); + //! Recovery was completed. Not necessarily successful. No parameters. + static const Event RECOVERY_DONE = MAKE_EVENT(12, severity::MEDIUM); virtual ~HasHealthIF() {} virtual MessageQueueId_t getCommandQueue() const = 0; diff --git a/src/fsfw/health/HealthTable.cpp b/src/fsfw/health/HealthTable.cpp index 5fb45fb9..3fcf7f77 100644 --- a/src/fsfw/health/HealthTable.cpp +++ b/src/fsfw/health/HealthTable.cpp @@ -6,8 +6,6 @@ HealthTable::HealthTable(object_id_t objectid) : SystemObject(objectid) { mutex = MutexFactory::instance()->createMutex(); - ; - mapIterator = healthMap.begin(); } diff --git a/src/fsfw/health/HealthTable.h b/src/fsfw/health/HealthTable.h index 076228c1..7b42dfba 100644 --- a/src/fsfw/health/HealthTable.h +++ b/src/fsfw/health/HealthTable.h @@ -8,6 +8,8 @@ #include "HealthTableIF.h" class HealthTable : public HealthTableIF, public SystemObject { + friend class CServiceHealthCommanding; + public: explicit HealthTable(object_id_t objectid); ~HealthTable() override; diff --git a/src/fsfw/internalerror/InternalErrorReporter.cpp b/src/fsfw/internalerror/InternalErrorReporter.cpp index b3b77366..fb2dc8a6 100644 --- a/src/fsfw/internalerror/InternalErrorReporter.cpp +++ b/src/fsfw/internalerror/InternalErrorReporter.cpp @@ -7,14 +7,17 @@ InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth) : SystemObject(setObjectId), - commandQueue(QueueFactory::instance()->createMessageQueue(messageQueueDepth)), poolManager(this, commandQueue), internalErrorSid(setObjectId, InternalErrorDataset::ERROR_SET_ID), internalErrorDataset(this) { + commandQueue = QueueFactory::instance()->createMessageQueue(messageQueueDepth); mutex = MutexFactory::instance()->createMutex(); } -InternalErrorReporter::~InternalErrorReporter() { MutexFactory::instance()->deleteMutex(mutex); } +InternalErrorReporter::~InternalErrorReporter() { + MutexFactory::instance()->deleteMutex(mutex); + QueueFactory::instance()->deleteMessageQueue(commandQueue); +} void InternalErrorReporter::setDiagnosticPrintout(bool enable) { this->diagnosticPrintout = enable; diff --git a/src/fsfw/modes/ModeMessage.cpp b/src/fsfw/modes/ModeMessage.cpp index ecc52c94..fbfb71aa 100644 --- a/src/fsfw/modes/ModeMessage.cpp +++ b/src/fsfw/modes/ModeMessage.cpp @@ -24,3 +24,19 @@ void ModeMessage::setCantReachMode(CommandMessage* message, ReturnValue_t reason message->setParameter(reason); message->setParameter2(0); } + +void ModeMessage::setModeAnnounceMessage(CommandMessage& message, bool recursive) { + Command_t cmd; + if (recursive) { + cmd = CMD_MODE_ANNOUNCE_RECURSIVELY; + } else { + cmd = CMD_MODE_ANNOUNCE; + } + message.setCommand(cmd); +} + +void ModeMessage::setCmdModeMessage(CommandMessage& message, Mode_t mode, Submode_t submode) { + setModeMessage(&message, CMD_MODE_COMMAND, mode, submode); +} + +void ModeMessage::setModeReadMessage(CommandMessage& message) { message.setCommand(CMD_MODE_READ); } diff --git a/src/fsfw/modes/ModeMessage.h b/src/fsfw/modes/ModeMessage.h index 84429e84..c00e6c9e 100644 --- a/src/fsfw/modes/ModeMessage.h +++ b/src/fsfw/modes/ModeMessage.h @@ -45,6 +45,9 @@ class ModeMessage { static void setModeMessage(CommandMessage* message, Command_t command, Mode_t mode, Submode_t submode); + static void setCmdModeMessage(CommandMessage& message, Mode_t mode, Submode_t submode); + static void setModeAnnounceMessage(CommandMessage& message, bool recursive); + static void setModeReadMessage(CommandMessage& message); static void setCantReachMode(CommandMessage* message, ReturnValue_t reason); static void clear(CommandMessage* message); }; diff --git a/src/fsfw/objectmanager/ObjectManager.cpp b/src/fsfw/objectmanager/ObjectManager.cpp index ddf5ab80..29c1b2fc 100644 --- a/src/fsfw/objectmanager/ObjectManager.cpp +++ b/src/fsfw/objectmanager/ObjectManager.cpp @@ -23,9 +23,17 @@ void ObjectManager::setObjectFactoryFunction(produce_function_t objFactoryFunc, ObjectManager::ObjectManager() = default; +void ObjectManager::clear() { + if (objManagerInstance != nullptr) { + delete objManagerInstance; + objManagerInstance = nullptr; + } +} + ObjectManager::~ObjectManager() { - for (auto const& iter : objectList) { - delete iter.second; + teardown = true; + for (auto iter = objectList.begin(); iter != objectList.end(); iter = objectList.erase(iter)) { + delete iter->second; } } @@ -53,6 +61,12 @@ ReturnValue_t ObjectManager::insert(object_id_t id, SystemObjectIF* object) { } ReturnValue_t ObjectManager::remove(object_id_t id) { + // this function is called during destruction of System Objects + // disabeld for teardown to avoid iterator invalidation and + // double free + if (teardown) { + return returnvalue::OK; + } if (this->getSystemObject(id) != nullptr) { this->objectList.erase(id); #if FSFW_CPP_OSTREAM_ENABLED == 1 diff --git a/src/fsfw/objectmanager/ObjectManager.h b/src/fsfw/objectmanager/ObjectManager.h index e0e74792..355f5d0a 100644 --- a/src/fsfw/objectmanager/ObjectManager.h +++ b/src/fsfw/objectmanager/ObjectManager.h @@ -24,12 +24,17 @@ class ObjectManager : public ObjectManagerIF { using produce_function_t = void (*)(void* args); /** - * Returns the single instance of TaskFactory. + * Returns the single instance of ObjectManager. * The implementation of #instance is found in its subclasses. * Thus, we choose link-time variability of the instance. */ static ObjectManager* instance(); + /** + * Deletes the single instance of ObjectManager + */ + static void clear(); + void setObjectFactoryFunction(produce_function_t prodFunc, void* args); template @@ -66,6 +71,9 @@ class ObjectManager : public ObjectManagerIF { */ std::map objectList; static ObjectManager* objManagerInstance; + // used when the OM itself is deleted to modify behaviour of remove() + // to avoid iterator invalidation and double free + bool teardown = false; }; // Documentation can be found in the class method declaration above diff --git a/src/fsfw/osal/CMakeLists.txt b/src/fsfw/osal/CMakeLists.txt index 50fd6102..6ccea974 100644 --- a/src/fsfw/osal/CMakeLists.txt +++ b/src/fsfw/osal/CMakeLists.txt @@ -1,10 +1,13 @@ # Check the OS_FSFW variable if(FSFW_OSAL MATCHES "freertos") add_subdirectory(freertos) + set(FSFW_OSAL_FREERTOS 1) elseif(FSFW_OSAL MATCHES "rtems") add_subdirectory(rtems) + set(FSFW_OSAL_RTEMS 1) elseif(FSFW_OSAL MATCHES "linux") add_subdirectory(linux) + set(FSFW_OSAL_LINUX 1) elseif(FSFW_OSAL MATCHES "host") add_subdirectory(host) if(WIN32) @@ -13,16 +16,20 @@ elseif(FSFW_OSAL MATCHES "host") # We still need to pull in some Linux specific sources target_sources(${LIB_FSFW_NAME} PUBLIC linux/tcpipHelpers.cpp) endif() - + set(FSFW_OSAL_HOST 1) else() + message( + WARNING + "${MSG_PREFIX} The FSFW_OSAL variable was not set. Assuming host OS..") - message(WARNING "The OS_FSFW variable was not set. Assuming host OS..") # Not set. Assumuing this is a host build, try to determine host OS if(WIN32) add_subdirectory(host) add_subdirectory(windows) + set(FSFW_OSAL_HOST 1) elseif(UNIX) add_subdirectory(linux) + set(FSFW_OSAL_LINUX 1) else() # MacOS or other OSes have not been tested yet / are not supported. message(FATAL_ERROR "The host OS could not be determined! Aborting.") @@ -31,3 +38,5 @@ else() endif() add_subdirectory(common) + +configure_file(osal.h.in ${CMAKE_BINARY_DIR}/fsfw/osal/osal.h) diff --git a/src/fsfw/osal/common/TcpTmTcServer.cpp b/src/fsfw/osal/common/TcpTmTcServer.cpp index dff959ba..903d8752 100644 --- a/src/fsfw/osal/common/TcpTmTcServer.cpp +++ b/src/fsfw/osal/common/TcpTmTcServer.cpp @@ -26,12 +26,12 @@ const std::string TcpTmTcServer::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT; TcpTmTcServer::TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge, - size_t receptionBufferSize, size_t ringBufferSize, - std::string customTcpServerPort, ReceptionModes receptionMode) + TcpTmTcServer::TcpConfig cfg, size_t receptionBufferSize, + size_t ringBufferSize, ReceptionModes receptionMode) : SystemObject(objectId), tmtcBridgeId(tmtcTcpBridge), receptionMode(receptionMode), - tcpConfig(std::move(customTcpServerPort)), + tcpConfig(cfg), receptionBuffer(receptionBufferSize), ringBuffer(ringBufferSize, true) {} @@ -91,6 +91,15 @@ ReturnValue_t TcpTmTcServer::initialize() { return returnvalue::FAILED; } + if (tcpConfig.reuseAddr) { + unsigned int enable = 1; + setsockopt(listenerTcpSocket, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)); + } + if (tcpConfig.reusePort) { + unsigned int enable = 1; + setsockopt(listenerTcpSocket, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(enable)); + } + // Bind to the address found by getaddrinfo retval = bind(listenerTcpSocket, addrResult->ai_addr, static_cast(addrResult->ai_addrlen)); if (retval == SOCKET_ERROR) { diff --git a/src/fsfw/osal/common/TcpTmTcServer.h b/src/fsfw/osal/common/TcpTmTcServer.h index 0e2182a5..009a1680 100644 --- a/src/fsfw/osal/common/TcpTmTcServer.h +++ b/src/fsfw/osal/common/TcpTmTcServer.h @@ -41,11 +41,11 @@ class SpacePacketParser; */ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableObjectIF { public: - enum class ReceptionModes { SPACE_PACKETS }; - struct TcpConfig { public: - explicit TcpConfig(std::string tcpPort) : tcpPort(std::move(tcpPort)) {} + TcpConfig(bool reuseAddr, bool reusePort) : reuseAddr(reuseAddr), reusePort(reusePort) {} + TcpConfig(std::string tcpPort, bool reuseAddr, bool reusePort) + : tcpPort(std::move(tcpPort)), reuseAddr(reuseAddr), reusePort(reusePort) {} /** * Passed to the recv call @@ -63,8 +63,23 @@ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableOb */ int tcpTmFlags = 0; - const std::string tcpPort; + std::string tcpPort = DEFAULT_SERVER_PORT; + + /** + * Sets the SO_REUSEADDR option on the socket. See + * https://man7.org/linux/man-pages/man7/socket.7.html for more details. This option is + * especially useful in a debugging and development environment where an OBSW image might be + * re-flashed oftentimes and where all incoming telecommands are received on a dedicated TCP + * port. + */ + bool reuseAddr = false; + /** + * Sets the SO_REUSEPORT option on the socket. See + * https://man7.org/linux/man-pages/man7/socket.7.html for more details. + */ + bool reusePort = false; }; + enum class ReceptionModes { SPACE_PACKETS }; static const std::string DEFAULT_SERVER_PORT; @@ -80,10 +95,9 @@ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableOb * size will be the Ethernet MTU size * @param customTcpServerPort The user can specify another port than the default (7301) here. */ - TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge, + TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge, TcpTmTcServer::TcpConfig cfg, size_t receptionBufferSize = RING_BUFFER_SIZE, size_t ringBufferSize = RING_BUFFER_SIZE, - std::string customTcpServerPort = DEFAULT_SERVER_PORT, ReceptionModes receptionMode = ReceptionModes::SPACE_PACKETS); ~TcpTmTcServer() override; diff --git a/src/fsfw/osal/linux/MessageQueue.cpp b/src/fsfw/osal/linux/MessageQueue.cpp index b2cca3f1..c08e3775 100644 --- a/src/fsfw/osal/linux/MessageQueue.cpp +++ b/src/fsfw/osal/linux/MessageQueue.cpp @@ -21,7 +21,7 @@ MessageQueue::MessageQueue(uint32_t messageDepth, size_t maxMessageSize, MqArgs* attributes.mq_msgsize = maxMessageSize; attributes.mq_flags = 0; // Flags are ignored on Linux during mq_open // Set the name of the queue. The slash is mandatory! - sprintf(name, "/FSFW_MQ%u\n", queueCounter++); + sprintf(name, "/FSFW_MQ%u", queueCounter++); // Create a nonblocking queue if the name is available (the queue is read // and writable for the owner as well as the group) diff --git a/src/fsfw/osal/osal.h.in b/src/fsfw/osal/osal.h.in new file mode 100644 index 00000000..8e48c31a --- /dev/null +++ b/src/fsfw/osal/osal.h.in @@ -0,0 +1,36 @@ +#pragma once + +namespace osal { + enum osalTarget{ + HOST, + LINUX, + WINDOWS, + FREERTOS, + RTEMS, + }; + +#cmakedefine FSFW_OSAL_HOST +#cmakedefine FSFW_OSAL_LINUX +#cmakedefine FSFW_OSAL_WINDOWS +#cmakedefine FSFW_OSAL_FREERTOS +#cmakedefine FSFW_OSAL_RTEMS + + + constexpr osalTarget getTarget() { +#ifdef FSFW_OSAL_HOST + return HOST; +#endif +#ifdef FSFW_OSAL_LINUX + return LINUX; +#endif +#ifdef FSFW_OSAL_WINDOWS + return WINDOWS; +#endif +#ifdef FSFW_OSAL_FREERTOS + return FREERTOS; +#endif +#ifdef FSFW_OSAL_RTEMS + return RTEMS; +#endif + } +}; \ No newline at end of file diff --git a/src/fsfw/osal/rtems/SemaphoreFactory.cpp b/src/fsfw/osal/rtems/SemaphoreFactory.cpp index 35099ddc..1e470f40 100644 --- a/src/fsfw/osal/rtems/SemaphoreFactory.cpp +++ b/src/fsfw/osal/rtems/SemaphoreFactory.cpp @@ -1,5 +1,5 @@ #include "fsfw/osal/rtems/BinarySemaphore.h" -//#include "fsfw/osal/rtems/CountingSemaphore.h" +// #include "fsfw/osal/rtems/CountingSemaphore.h" #include "fsfw/serviceinterface/ServiceInterface.h" #include "fsfw/tasks/SemaphoreFactory.h" diff --git a/src/fsfw/pus/CMakeLists.txt b/src/fsfw/pus/CMakeLists.txt index 35b35bea..7c5b340c 100644 --- a/src/fsfw/pus/CMakeLists.txt +++ b/src/fsfw/pus/CMakeLists.txt @@ -9,4 +9,4 @@ target_sources( Service17Test.cpp Service20ParameterManagement.cpp CService200ModeCommanding.cpp - CService201HealthCommanding.cpp) + CServiceHealthCommanding.cpp) diff --git a/src/fsfw/pus/CService200ModeCommanding.cpp b/src/fsfw/pus/CService200ModeCommanding.cpp index d28df59b..0dbdedfe 100644 --- a/src/fsfw/pus/CService200ModeCommanding.cpp +++ b/src/fsfw/pus/CService200ModeCommanding.cpp @@ -19,7 +19,8 @@ ReturnValue_t CService200ModeCommanding::isValidSubservice(uint8_t subservice) { switch (subservice) { case (Subservice::COMMAND_MODE_COMMAND): case (Subservice::COMMAND_MODE_READ): - case (Subservice::COMMAND_MODE_ANNCOUNCE): + case (Subservice::COMMAND_MODE_ANNOUNCE): + case (Subservice::COMMAND_MODE_ANNOUNCE_RECURSIVELY): return returnvalue::OK; default: return AcceptsTelecommandsIF::INVALID_SUBSERVICE; @@ -53,16 +54,32 @@ ReturnValue_t CService200ModeCommanding::checkInterfaceAndAcquireMessageQueue( ReturnValue_t CService200ModeCommanding::prepareCommand(CommandMessage *message, uint8_t subservice, const uint8_t *tcData, size_t tcDataLen, uint32_t *state, object_id_t objectId) { - ModePacket modeCommandPacket; - ReturnValue_t result = - modeCommandPacket.deSerialize(&tcData, &tcDataLen, SerializeIF::Endianness::BIG); - if (result != returnvalue::OK) { - return result; - } + bool recursive = false; + switch (subservice) { + case (Subservice::COMMAND_MODE_COMMAND): { + ModePacket modeCommandPacket; + ReturnValue_t result = + modeCommandPacket.deSerialize(&tcData, &tcDataLen, SerializeIF::Endianness::BIG); + if (result != returnvalue::OK) { + return result; + } - ModeMessage::setModeMessage(message, ModeMessage::CMD_MODE_COMMAND, modeCommandPacket.getMode(), - modeCommandPacket.getSubmode()); - return result; + ModeMessage::setModeMessage(message, ModeMessage::CMD_MODE_COMMAND, + modeCommandPacket.getMode(), modeCommandPacket.getSubmode()); + return returnvalue::OK; + } + case (Subservice::COMMAND_MODE_ANNOUNCE_RECURSIVELY): + recursive = true; + [[fallthrough]]; + case (Subservice::COMMAND_MODE_ANNOUNCE): + ModeMessage::setModeAnnounceMessage(*message, recursive); + return EXECUTION_COMPLETE; + case (Subservice::COMMAND_MODE_READ): + ModeMessage::setModeReadMessage(*message); + return returnvalue::OK; + default: + return CommandingServiceBase::INVALID_SUBSERVICE; + } } ReturnValue_t CService200ModeCommanding::handleReply(const CommandMessage *reply, @@ -73,8 +90,10 @@ ReturnValue_t CService200ModeCommanding::handleReply(const CommandMessage *reply ReturnValue_t result = returnvalue::FAILED; switch (replyId) { case (ModeMessage::REPLY_MODE_REPLY): { - result = prepareModeReply(reply, objectId); - break; + if (previousCommand != ModeMessage::CMD_MODE_COMMAND) { + return prepareModeReply(reply, objectId); + } + return returnvalue::OK; } case (ModeMessage::REPLY_WRONG_MODE_REPLY): { result = prepareWrongModeReply(reply, objectId); diff --git a/src/fsfw/pus/CService200ModeCommanding.h b/src/fsfw/pus/CService200ModeCommanding.h index 830e5950..cf2baf7e 100644 --- a/src/fsfw/pus/CService200ModeCommanding.h +++ b/src/fsfw/pus/CService200ModeCommanding.h @@ -52,7 +52,7 @@ class CService200ModeCommanding : public CommandingServiceBase { COMMAND_MODE_READ = 3, //!< [EXPORT] : [COMMAND] Trigger an ModeInfo Event. //! This command does NOT have a reply - COMMAND_MODE_ANNCOUNCE = 4, + COMMAND_MODE_ANNOUNCE = 4, //!< [EXPORT] : [COMMAND] Trigger a ModeInfo Event and to send this //! command to every child. This command does NOT have a reply. COMMAND_MODE_ANNOUNCE_RECURSIVELY = 5, diff --git a/src/fsfw/pus/CService201HealthCommanding.cpp b/src/fsfw/pus/CService201HealthCommanding.cpp deleted file mode 100644 index bf21c5bd..00000000 --- a/src/fsfw/pus/CService201HealthCommanding.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include "fsfw/pus/CService201HealthCommanding.h" - -#include "fsfw/health/HasHealthIF.h" -#include "fsfw/health/HealthMessage.h" -#include "fsfw/objectmanager/ObjectManager.h" -#include "fsfw/pus/servicepackets/Service201Packets.h" -#include "fsfw/serviceinterface/ServiceInterface.h" - -CService201HealthCommanding::CService201HealthCommanding(object_id_t objectId, uint16_t apid, - uint8_t serviceId, - uint8_t numParallelCommands, - uint16_t commandTimeoutSeconds) - : CommandingServiceBase(objectId, apid, "PUS 201 Health MGMT", serviceId, numParallelCommands, - commandTimeoutSeconds) {} - -ReturnValue_t CService201HealthCommanding::isValidSubservice(uint8_t subservice) { - switch (subservice) { - case (Subservice::COMMAND_SET_HEALTH): - case (Subservice::COMMAND_ANNOUNCE_HEALTH): - case (Subservice::COMMAND_ANNOUNCE_HEALTH_ALL): - return returnvalue::OK; - default: -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "Invalid Subservice" << std::endl; -#endif - return AcceptsTelecommandsIF::INVALID_SUBSERVICE; - } -} - -ReturnValue_t CService201HealthCommanding::getMessageQueueAndObject(uint8_t subservice, - const uint8_t *tcData, - size_t tcDataLen, - MessageQueueId_t *id, - object_id_t *objectId) { - if (tcDataLen < sizeof(object_id_t)) { - return CommandingServiceBase::INVALID_TC; - } - SerializeAdapter::deSerialize(objectId, &tcData, &tcDataLen, SerializeIF::Endianness::BIG); - - return checkInterfaceAndAcquireMessageQueue(id, objectId); -} - -ReturnValue_t CService201HealthCommanding::checkInterfaceAndAcquireMessageQueue( - MessageQueueId_t *messageQueueToSet, const object_id_t *objectId) { - auto *destination = ObjectManager::instance()->get(*objectId); - if (destination == nullptr) { - return CommandingServiceBase::INVALID_OBJECT; - } - - *messageQueueToSet = destination->getCommandQueue(); - return returnvalue::OK; -} - -ReturnValue_t CService201HealthCommanding::prepareCommand(CommandMessage *message, - uint8_t subservice, const uint8_t *tcData, - size_t tcDataLen, uint32_t *state, - object_id_t objectId) { - ReturnValue_t result = returnvalue::OK; - switch (subservice) { - case (Subservice::COMMAND_SET_HEALTH): { - HealthSetCommand healthCommand; - result = healthCommand.deSerialize(&tcData, &tcDataLen, SerializeIF::Endianness::BIG); - if (result != returnvalue::OK) { - break; - } - HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_SET, - healthCommand.getHealth()); - break; - } - case (Subservice::COMMAND_ANNOUNCE_HEALTH): { - HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_ANNOUNCE); - break; - } - case (Subservice::COMMAND_ANNOUNCE_HEALTH_ALL): { - HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_ANNOUNCE_ALL); - break; - } - default: { - // Should never happen, subservice was already checked - result = returnvalue::FAILED; - } - } - return result; -} - -ReturnValue_t CService201HealthCommanding::handleReply(const CommandMessage *reply, - Command_t previousCommand, uint32_t *state, - CommandMessage *optionalNextCommand, - object_id_t objectId, bool *isStep) { - Command_t replyId = reply->getCommand(); - if (replyId == HealthMessage::REPLY_HEALTH_SET) { - return EXECUTION_COMPLETE; - } else if (replyId == CommandMessageIF::REPLY_REJECTED) { - return reply->getReplyRejectedReason(); - } - return CommandingServiceBase::INVALID_REPLY; -} - -// Not used for now, health state already reported by event -[[maybe_unused]] ReturnValue_t CService201HealthCommanding::prepareHealthSetReply( - const CommandMessage *reply) { - auto health = static_cast(HealthMessage::getHealth(reply)); - auto oldHealth = static_cast(HealthMessage::getOldHealth(reply)); - HealthSetReply healthSetReply(health, oldHealth); - return sendTmPacket(Subservice::REPLY_HEALTH_SET, healthSetReply); -} diff --git a/src/fsfw/pus/CServiceHealthCommanding.cpp b/src/fsfw/pus/CServiceHealthCommanding.cpp new file mode 100644 index 00000000..3ced4ffb --- /dev/null +++ b/src/fsfw/pus/CServiceHealthCommanding.cpp @@ -0,0 +1,161 @@ +#include +#include + +#include "fsfw/health/HasHealthIF.h" +#include "fsfw/health/HealthMessage.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/pus/servicepackets/Service201Packets.h" +#include "fsfw/serviceinterface/ServiceInterface.h" + +CServiceHealthCommanding::CServiceHealthCommanding(HealthServiceCfg args) + : CommandingServiceBase(args.objectId, args.apid, "PUS 201 Health MGMT", args.service, + args.numParallelCommands, args.commandTimeoutSeconds), + healthTableId(args.table), + maxNumHealthInfoPerCycle(args.maxNumHealthInfoPerCycle) {} + +ReturnValue_t CServiceHealthCommanding::initialize() { + ReturnValue_t result = CommandingServiceBase::initialize(); + if (result != returnvalue::OK) { + return result; + } + + healthTable = ObjectManager::instance()->get(healthTableId); + if (healthTable == nullptr) { + return returnvalue::FAILED; + } + + return returnvalue::OK; +} + +ReturnValue_t CServiceHealthCommanding::isValidSubservice(uint8_t subservice) { + switch (subservice) { + case (Subservice::COMMAND_SET_HEALTH): + case (Subservice::COMMAND_ANNOUNCE_HEALTH): + case (Subservice::COMMAND_ANNOUNCE_HEALTH_ALL): + return returnvalue::OK; + default: +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "Invalid Subservice" << std::endl; +#endif + return AcceptsTelecommandsIF::INVALID_SUBSERVICE; + } +} + +ReturnValue_t CServiceHealthCommanding::getMessageQueueAndObject(uint8_t subservice, + const uint8_t *tcData, + size_t tcDataLen, + MessageQueueId_t *id, + object_id_t *objectId) { + switch (subservice) { + case (Subservice::COMMAND_SET_HEALTH): + case (Subservice::COMMAND_ANNOUNCE_HEALTH): { + if (tcDataLen < sizeof(object_id_t)) { + return CommandingServiceBase::INVALID_TC; + } + SerializeAdapter::deSerialize(objectId, &tcData, &tcDataLen, SerializeIF::Endianness::BIG); + + return checkInterfaceAndAcquireMessageQueue(id, objectId); + } + case (Subservice::COMMAND_ANNOUNCE_HEALTH_ALL): { + return returnvalue::OK; + } + default: { + return returnvalue::FAILED; + } + } +} + +ReturnValue_t CServiceHealthCommanding::checkInterfaceAndAcquireMessageQueue( + MessageQueueId_t *messageQueueToSet, const object_id_t *objectId) { + auto *destination = ObjectManager::instance()->get(*objectId); + if (destination == nullptr) { + return CommandingServiceBase::INVALID_OBJECT; + } + + *messageQueueToSet = destination->getCommandQueue(); + return returnvalue::OK; +} + +ReturnValue_t CServiceHealthCommanding::prepareCommand(CommandMessage *message, uint8_t subservice, + const uint8_t *tcData, size_t tcDataLen, + uint32_t *state, object_id_t objectId) { + ReturnValue_t result = returnvalue::OK; + switch (subservice) { + case (Subservice::COMMAND_SET_HEALTH): { + if (tcDataLen != sizeof(object_id_t) + sizeof(HasHealthIF::HealthState)) { + return CommandingServiceBase::INVALID_TC; + } + HealthSetCommand healthCommand; + result = healthCommand.deSerialize(&tcData, &tcDataLen, SerializeIF::Endianness::BIG); + if (result != returnvalue::OK) { + break; + } + HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_SET, + healthCommand.getHealth()); + break; + } + case (Subservice::COMMAND_ANNOUNCE_HEALTH): { + HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_ANNOUNCE); + return CommandingServiceBase::EXECUTION_COMPLETE; + } + case (Subservice::COMMAND_ANNOUNCE_HEALTH_ALL): { + ReturnValue_t result = iterateHealthTable(true); + if (result == returnvalue::OK) { + reportAllHealth = true; + return EXECUTION_COMPLETE; + } + return result; + } + default: { + // Should never happen, subservice was already checked + result = returnvalue::FAILED; + } + } + return result; +} + +ReturnValue_t CServiceHealthCommanding::handleReply(const CommandMessage *reply, + Command_t previousCommand, uint32_t *state, + CommandMessage *optionalNextCommand, + object_id_t objectId, bool *isStep) { + Command_t replyId = reply->getCommand(); + if (replyId == HealthMessage::REPLY_HEALTH_SET) { + return EXECUTION_COMPLETE; + } else if (replyId == CommandMessageIF::REPLY_REJECTED) { + return reply->getReplyRejectedReason(); + } + return CommandingServiceBase::INVALID_REPLY; +} + +void CServiceHealthCommanding::doPeriodicOperation() { + if (reportAllHealth) { + for (uint8_t i = 0; i < maxNumHealthInfoPerCycle; i++) { + ReturnValue_t result = iterateHealthTable(false); + if (result != returnvalue::OK) { + reportAllHealth = false; + break; + } + } + } +} + +// Not used for now, health state already reported by event +[[maybe_unused]] ReturnValue_t CServiceHealthCommanding::prepareHealthSetReply( + const CommandMessage *reply) { + auto health = static_cast(HealthMessage::getHealth(reply)); + auto oldHealth = static_cast(HealthMessage::getOldHealth(reply)); + HealthSetReply healthSetReply(health, oldHealth); + return sendTmPacket(Subservice::REPLY_HEALTH_SET, healthSetReply); +} + +ReturnValue_t CServiceHealthCommanding::iterateHealthTable(bool reset) { + std::pair pair; + + ReturnValue_t result = healthTable->iterate(&pair, reset); + if (result != returnvalue::OK) { + return result; + } else { + EventManagerIF::triggerEvent(pair.first, HasHealthIF::HEALTH_INFO, pair.second, pair.second); + return returnvalue::OK; + } +} diff --git a/src/fsfw/pus/CService201HealthCommanding.h b/src/fsfw/pus/CServiceHealthCommanding.h similarity index 70% rename from src/fsfw/pus/CService201HealthCommanding.h rename to src/fsfw/pus/CServiceHealthCommanding.h index 71b7caa0..2cc16589 100644 --- a/src/fsfw/pus/CService201HealthCommanding.h +++ b/src/fsfw/pus/CServiceHealthCommanding.h @@ -1,8 +1,26 @@ #ifndef FSFW_PUS_CSERVICE201HEALTHCOMMANDING_H_ #define FSFW_PUS_CSERVICE201HEALTHCOMMANDING_H_ +#include + #include "fsfw/tmtcservices/CommandingServiceBase.h" +struct HealthServiceCfg { + HealthServiceCfg(object_id_t objectId, uint16_t apid, object_id_t healthTable, + uint16_t maxNumHealthInfoPerCycle) + : objectId(objectId), + apid(apid), + table(healthTable), + maxNumHealthInfoPerCycle(maxNumHealthInfoPerCycle) {} + object_id_t objectId; + uint16_t apid; + object_id_t table; + uint16_t maxNumHealthInfoPerCycle; + uint8_t service = 201; + uint8_t numParallelCommands = 4; + uint16_t commandTimeoutSeconds = 60; +}; + /** * @brief Custom PUS service to set health of all objects * implementing hasHealthIF. @@ -17,11 +35,12 @@ * child class like this service * */ -class CService201HealthCommanding : public CommandingServiceBase { +class CServiceHealthCommanding : public CommandingServiceBase { public: - CService201HealthCommanding(object_id_t objectId, uint16_t apid, uint8_t serviceId, - uint8_t numParallelCommands = 4, uint16_t commandTimeoutSeconds = 60); - ~CService201HealthCommanding() override = default; + CServiceHealthCommanding(HealthServiceCfg args); + ~CServiceHealthCommanding() override = default; + + ReturnValue_t initialize() override; protected: /* CSB abstract function implementations */ @@ -37,7 +56,14 @@ class CService201HealthCommanding : public CommandingServiceBase { CommandMessage *optionalNextCommand, object_id_t objectId, bool *isStep) override; + void doPeriodicOperation() override; + private: + const object_id_t healthTableId; + HealthTable *healthTable; + uint16_t maxNumHealthInfoPerCycle = 0; + bool reportAllHealth = false; + ReturnValue_t iterateHealthTable(bool reset); static ReturnValue_t checkInterfaceAndAcquireMessageQueue(MessageQueueId_t *MessageQueueToSet, const object_id_t *objectId); diff --git a/src/fsfw/pus/Service11TelecommandScheduling.h b/src/fsfw/pus/Service11TelecommandScheduling.h index aa958193..83b2b4c0 100644 --- a/src/fsfw/pus/Service11TelecommandScheduling.h +++ b/src/fsfw/pus/Service11TelecommandScheduling.h @@ -41,6 +41,8 @@ class Service11TelecommandScheduling final : public PusServiceBase { static constexpr ReturnValue_t INVALID_TIME_WINDOW = returnvalue::makeCode(CLASS_ID, 2); static constexpr ReturnValue_t TIMESHIFTING_NOT_POSSIBLE = returnvalue::makeCode(CLASS_ID, 3); static constexpr ReturnValue_t INVALID_RELATIVE_TIME = returnvalue::makeCode(CLASS_ID, 4); + static constexpr ReturnValue_t CONTAINED_TC_TOO_SMALL = returnvalue::makeCode(CLASS_ID, 5); + static constexpr ReturnValue_t CONTAINED_TC_CRC_MISSMATCH = returnvalue::makeCode(CLASS_ID, 6); static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PUS_SERVICE_11; diff --git a/src/fsfw/pus/Service11TelecommandScheduling.tpp b/src/fsfw/pus/Service11TelecommandScheduling.tpp index 9016af80..ac08f02c 100644 --- a/src/fsfw/pus/Service11TelecommandScheduling.tpp +++ b/src/fsfw/pus/Service11TelecommandScheduling.tpp @@ -2,9 +2,11 @@ #include +#include "fsfw/globalfunctions/CRC.h" #include "fsfw/objectmanager/ObjectManager.h" #include "fsfw/serialize/SerializeAdapter.h" #include "fsfw/serviceinterface.h" +#include "fsfw/tmtcpacket/pus/tc/PusTcIF.h" #include "fsfw/tmtcservices/AcceptsTelecommandsIF.h" static constexpr auto DEF_END = SerializeIF::Endianness::BIG; @@ -171,6 +173,14 @@ inline ReturnValue_t Service11TelecommandScheduling::doInsertActivi return returnvalue::FAILED; } + if (size < PusTcIF::MIN_SIZE) { + return CONTAINED_TC_TOO_SMALL; + } + + if (CRC::crc16ccitt(data, size) != 0) { + return CONTAINED_TC_CRC_MISSMATCH; + } + // store currentPacket and receive the store address store_address_t addr{}; if (tcStore->addData(&addr, data, size) != returnvalue::OK || diff --git a/src/fsfw/pus/Service20ParameterManagement.cpp b/src/fsfw/pus/Service20ParameterManagement.cpp index e12d47bc..87bd5a13 100644 --- a/src/fsfw/pus/Service20ParameterManagement.cpp +++ b/src/fsfw/pus/Service20ParameterManagement.cpp @@ -69,14 +69,14 @@ ReturnValue_t Service20ParameterManagement::checkInterfaceAndAcquireMessageQueue #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Service20ParameterManagement::checkInterfaceAndAcquire" << "MessageQueue: Can't access object" << std::endl; - sif::error << "Object ID: " << std::hex << objectId << std::dec << std::endl; - sif::error << "Make sure it implements ReceivesParameterMessagesIF!" << std::endl; + sif::error << "Object ID: 0x" << std::hex << *objectId << std::dec << std::endl; + sif::error << "Make sure it implements ReceivesParameterMessagesIF" << std::endl; #else sif::printError( "Service20ParameterManagement::checkInterfaceAndAcquire" "MessageQueue: Can't access object\n"); sif::printError("Object ID: 0x%08x\n", *objectId); - sif::printError("Make sure it implements ReceivesParameterMessagesIF!\n"); + sif::printError("Make sure it implements ReceivesParameterMessagesIF\n"); #endif return CommandingServiceBase::INVALID_OBJECT; diff --git a/src/fsfw/pus/Service9TimeManagement.cpp b/src/fsfw/pus/Service9TimeManagement.cpp index d19cb518..fb32f60e 100644 --- a/src/fsfw/pus/Service9TimeManagement.cpp +++ b/src/fsfw/pus/Service9TimeManagement.cpp @@ -1,5 +1,7 @@ #include "fsfw/pus/Service9TimeManagement.h" +#include + #include "fsfw/events/EventManagerIF.h" #include "fsfw/pus/servicepackets/Service9Packets.h" #include "fsfw/serviceinterface/ServiceInterface.h" @@ -15,9 +17,17 @@ ReturnValue_t Service9TimeManagement::performService() { return returnvalue::OK; ReturnValue_t Service9TimeManagement::handleRequest(uint8_t subservice) { switch (subservice) { - case SUBSERVICE::SET_TIME: { + case Subservice::SET_TIME: { return setTime(); } + case Subservice::DUMP_TIME: { + timeval newTime; + Clock::getClock_timeval(&newTime); + uint32_t subsecondMs = + static_cast(std::floor(static_cast(newTime.tv_usec) / 1000.0)); + triggerEvent(CLOCK_DUMP, newTime.tv_sec, subsecondMs); + return returnvalue::OK; + } default: return AcceptsTelecommandsIF::INVALID_SUBSERVICE; } @@ -33,14 +43,14 @@ ReturnValue_t Service9TimeManagement::setTime() { return result; } - uint32_t formerUptime; - Clock::getUptime(&formerUptime); + timeval time; + Clock::getClock_timeval(&time); result = Clock::setClock(&timeToSet); if (result == returnvalue::OK) { - uint32_t newUptime; - Clock::getUptime(&newUptime); - triggerEvent(CLOCK_SET, newUptime, formerUptime); + timeval newTime; + Clock::getClock_timeval(&newTime); + triggerEvent(CLOCK_SET, time.tv_sec, newTime.tv_sec); return returnvalue::OK; } else { triggerEvent(CLOCK_SET_FAILURE, result, 0); diff --git a/src/fsfw/pus/Service9TimeManagement.h b/src/fsfw/pus/Service9TimeManagement.h index b4886bb0..556f3df3 100644 --- a/src/fsfw/pus/Service9TimeManagement.h +++ b/src/fsfw/pus/Service9TimeManagement.h @@ -6,10 +6,13 @@ class Service9TimeManagement : public PusServiceBase { public: static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PUS_SERVICE_9; - static constexpr Event CLOCK_SET = - MAKE_EVENT(0, severity::INFO); //!< Clock has been set. P1: New Uptime. P2: Old Uptime - static constexpr Event CLOCK_SET_FAILURE = - MAKE_EVENT(1, severity::LOW); //!< Clock could not be set. P1: Returncode. + + //!< Clock has been set. P1: old timeval seconds. P2: new timeval seconds. + static constexpr Event CLOCK_SET = MAKE_EVENT(0, severity::INFO); + //!< Clock dump event. P1: timeval seconds P2: timeval milliseconds. + static constexpr Event CLOCK_DUMP = MAKE_EVENT(1, severity::INFO); + //!< Clock could not be set. P1: Returncode. + static constexpr Event CLOCK_SET_FAILURE = MAKE_EVENT(2, severity::LOW); static constexpr uint8_t CLASS_ID = CLASS_ID::PUS_SERVICE_9; @@ -30,8 +33,9 @@ class Service9TimeManagement : public PusServiceBase { virtual ReturnValue_t setTime(); private: - enum SUBSERVICE { - SET_TIME = 128 //!< [EXPORT] : [COMMAND] Time command in ASCII, CUC or CDS format + enum Subservice { + SET_TIME = 128, //!< [EXPORT] : [COMMAND] Time command in ASCII, CUC or CDS format + DUMP_TIME = 129, }; }; diff --git a/src/fsfw/rmap/rmapStructs.h b/src/fsfw/rmap/rmapStructs.h index 55e32606..1e86734b 100644 --- a/src/fsfw/rmap/rmapStructs.h +++ b/src/fsfw/rmap/rmapStructs.h @@ -10,11 +10,11 @@ ////////////////////////////////////////////////////////////////////////////////// // RMAP command bits -//#define RMAP_COMMAND_BIT_INCREMENT 2 -//#define RMAP_COMMAND_BIT_REPLY 3 -//#define RMAP_COMMAND_BIT_WRITE 5 -//#define RMAP_COMMAND_BIT_VERIFY 4 -//#define RMAP_COMMAND_BIT 6 +// #define RMAP_COMMAND_BIT_INCREMENT 2 +// #define RMAP_COMMAND_BIT_REPLY 3 +// #define RMAP_COMMAND_BIT_WRITE 5 +// #define RMAP_COMMAND_BIT_VERIFY 4 +// #define RMAP_COMMAND_BIT 6 namespace RMAPIds { @@ -32,14 +32,14 @@ static const uint8_t RMAP_COMMAND_READ = ((1 << RMAP_COMMAND_BIT) | (1 << RMAP_C static const uint8_t RMAP_REPLY_WRITE = ((1 << RMAP_COMMAND_BIT_WRITE) | (1 << RMAP_COMMAND_BIT_REPLY)); static const uint8_t RMAP_REPLY_READ = ((1 << RMAP_COMMAND_BIT_REPLY)); -//#define RMAP_COMMAND_WRITE ((1<createMessageQueue(TMTC_RECEPTION_QUEUE_DEPTH); + auto mqArgs = MqArgs(objectId, static_cast(this)); + tmTcReceptionQueue = QueueFactory::instance()->createMessageQueue( + TMTC_RECEPTION_QUEUE_DEPTH, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs); } TmTcBridge::~TmTcBridge() { QueueFactory::instance()->deleteMessageQueue(tmTcReceptionQueue); } @@ -35,7 +37,7 @@ ReturnValue_t TmTcBridge::setNumberOfSentPacketsPerCycle(uint8_t sentPacketsPerC } } -ReturnValue_t TmTcBridge::setMaxNumberOfPacketsStored(uint8_t maxNumberOfPacketsStored) { +ReturnValue_t TmTcBridge::setMaxNumberOfPacketsStored(unsigned int maxNumberOfPacketsStored) { if (maxNumberOfPacketsStored <= LIMIT_DOWNLINK_PACKETS_STORED) { this->maxNumberOfPacketsStored = maxNumberOfPacketsStored; return returnvalue::OK; @@ -143,13 +145,17 @@ ReturnValue_t TmTcBridge::handleTmQueue() { #endif /* FSFW_VERBOSE_LEVEL >= 3 */ if (communicationLinkUp == false or packetSentCounter >= sentPacketsPerCycle) { - storeDownlinkData(&message); + ReturnValue_t result = storeDownlinkData(&message); + if (result != returnvalue::OK) { + tmStore->deleteData(message.getStorageId()); + } continue; } result = tmStore->getData(message.getStorageId(), &data, &size); if (result != returnvalue::OK) { status = result; + tmStore->deleteData(message.getStorageId()); continue; } @@ -157,9 +163,9 @@ ReturnValue_t TmTcBridge::handleTmQueue() { if (result != returnvalue::OK) { status = result; } else { - tmStore->deleteData(message.getStorageId()); packetSentCounter++; } + tmStore->deleteData(message.getStorageId()); } return status; } @@ -171,15 +177,18 @@ ReturnValue_t TmTcBridge::storeDownlinkData(TmTcMessage* message) { } if (tmFifo->full()) { + if (warningSwitch) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "TmTcBridge::storeDownlinkData: TM downlink max. number " - "of stored packet IDs reached!" - << std::endl; + sif::warning << "TmTcBridge::storeDownlinkData: TM downlink max. number " + "of stored packet IDs reached!" + << std::endl; #else - sif::printWarning( - "TmTcBridge::storeDownlinkData: TM downlink max. number " - "of stored packet IDs reached!\n"); + sif::printWarning( + "TmTcBridge::storeDownlinkData: TM downlink max. number " + "of stored packet IDs reached!\n"); #endif + warningSwitch = false; + } if (overwriteOld) { tmFifo->retrieve(&storeId); tmStore->deleteData(storeId); @@ -221,6 +230,7 @@ ReturnValue_t TmTcBridge::handleStoredTm() { packetSentCounter++; if (tmFifo->empty()) { + warningSwitch = true; tmStored = false; } tmStore->deleteData(storeId); diff --git a/src/fsfw/tmtcservices/TmTcBridge.h b/src/fsfw/tmtcservices/TmTcBridge.h index ed4d254e..3df3419c 100644 --- a/src/fsfw/tmtcservices/TmTcBridge.h +++ b/src/fsfw/tmtcservices/TmTcBridge.h @@ -17,7 +17,7 @@ class TmTcBridge : public AcceptsTelemetryIF, public: static constexpr uint8_t TMTC_RECEPTION_QUEUE_DEPTH = 20; static constexpr uint8_t LIMIT_STORED_DATA_SENT_PER_CYCLE = 15; - static constexpr uint8_t LIMIT_DOWNLINK_PACKETS_STORED = 200; + static constexpr unsigned int LIMIT_DOWNLINK_PACKETS_STORED = 500; static constexpr uint8_t DEFAULT_STORED_DATA_SENT_PER_CYCLE = 5; static constexpr uint8_t DEFAULT_DOWNLINK_PACKETS_STORED = 10; @@ -42,7 +42,7 @@ class TmTcBridge : public AcceptsTelemetryIF, * @return -@c returnvalue::OK if value was set successfully * -@c returnvalue::FAILED otherwise, stored value stays the same */ - ReturnValue_t setMaxNumberOfPacketsStored(uint8_t maxNumberOfPacketsStored); + ReturnValue_t setMaxNumberOfPacketsStored(unsigned int maxNumberOfPacketsStored); /** * This will set up the bridge to overwrite old data in the FIFO. @@ -91,6 +91,7 @@ class TmTcBridge : public AcceptsTelemetryIF, //! by default, so telemetry will be handled immediately. bool communicationLinkUp = true; bool tmStored = false; + bool warningSwitch = true; bool overwriteOld = true; uint8_t packetSentCounter = 0; @@ -152,7 +153,7 @@ class TmTcBridge : public AcceptsTelemetryIF, */ DynamicFIFO* tmFifo = nullptr; uint8_t sentPacketsPerCycle = DEFAULT_STORED_DATA_SENT_PER_CYCLE; - uint8_t maxNumberOfPacketsStored = DEFAULT_DOWNLINK_PACKETS_STORED; + unsigned int maxNumberOfPacketsStored = DEFAULT_DOWNLINK_PACKETS_STORED; }; #endif /* FSFW_TMTCSERVICES_TMTCBRIDGE_H_ */ diff --git a/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp b/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp index a32153eb..307d0a55 100644 --- a/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp +++ b/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp @@ -325,12 +325,12 @@ ReturnValue_t MgmRM3100Handler::handleDataReadout(const uint8_t *packet) { // trickery here to calculate the raw values first int32_t fieldStrengthRawX = ((packet[1] << 24) | (packet[2] << 16) | (packet[3] << 8)) >> 8; int32_t fieldStrengthRawY = ((packet[4] << 24) | (packet[5] << 16) | (packet[6] << 8)) >> 8; - int32_t fieldStrengthRawZ = ((packet[7] << 24) | (packet[8] << 16) | (packet[3] << 8)) >> 8; + int32_t fieldStrengthRawZ = ((packet[7] << 24) | (packet[8] << 16) | (packet[9] << 8)) >> 8; // Now scale to physical value in microtesla float fieldStrengthX = fieldStrengthRawX * scaleFactorX; - float fieldStrengthY = fieldStrengthRawY * scaleFactorX; - float fieldStrengthZ = fieldStrengthRawZ * scaleFactorX; + float fieldStrengthY = fieldStrengthRawY * scaleFactorY; + float fieldStrengthZ = fieldStrengthRawZ * scaleFactorZ; if (periodicPrintout) { if (debugDivider.checkAndIncrement()) { diff --git a/src/fsfw_hal/linux/i2c/I2cComIF.cpp b/src/fsfw_hal/linux/i2c/I2cComIF.cpp index 1ad19e82..e3e50040 100644 --- a/src/fsfw_hal/linux/i2c/I2cComIF.cpp +++ b/src/fsfw_hal/linux/i2c/I2cComIF.cpp @@ -180,10 +180,6 @@ ReturnValue_t I2cComIF::requestReceiveMessage(CookieIF* cookie, size_t requestLe } #else #endif -#endif -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << "I2cComIF::requestReceiveMessage: Read " << readLen << " of " << requestLen - << " bytes" << std::endl; #endif return returnvalue::FAILED; } diff --git a/unittests/CatchSetup.cpp b/unittests/CatchSetup.cpp index 4f2a4a54..fc5bb3f5 100644 --- a/unittests/CatchSetup.cpp +++ b/unittests/CatchSetup.cpp @@ -31,4 +31,7 @@ int customSetup() { return 0; } -int customTeardown() { return 0; } +int customTeardown() { + ObjectManager::clear(); + return 0; +} diff --git a/unittests/devicehandler/DeviceHandlerCommander.cpp b/unittests/devicehandler/DeviceHandlerCommander.cpp index 03ff992c..835faf2b 100644 --- a/unittests/devicehandler/DeviceHandlerCommander.cpp +++ b/unittests/devicehandler/DeviceHandlerCommander.cpp @@ -9,7 +9,9 @@ DeviceHandlerCommander::DeviceHandlerCommander(object_id_t objectId) QUEUE_SIZE, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs); } -DeviceHandlerCommander::~DeviceHandlerCommander() {} +DeviceHandlerCommander::~DeviceHandlerCommander() { + QueueFactory::instance()->deleteMessageQueue(commandQueue); +} ReturnValue_t DeviceHandlerCommander::performOperation(uint8_t operationCode) { readCommandQueue(); diff --git a/unittests/osal/TestSemaphore.cpp b/unittests/osal/TestSemaphore.cpp index 376b08db..1d8758b1 100644 --- a/unittests/osal/TestSemaphore.cpp +++ b/unittests/osal/TestSemaphore.cpp @@ -1,46 +1,38 @@ - -#ifdef LINUX - -/* +#include #include #include -#include "catch.hpp" -#include "core/CatchDefinitions.h" +#include -TEST_CASE("Binary Semaphore Test" , "[BinSemaphore]") { - //perform set-up here - SemaphoreIF* binSemaph = SemaphoreFactory::instance()-> - createBinarySemaphore(); - REQUIRE(binSemaph != nullptr); - SECTION("Simple Test") { - // set-up is run for each section - REQUIRE(binSemaph->getSemaphoreCounter() == 1); - REQUIRE(binSemaph->release() == - static_cast(SemaphoreIF::SEMAPHORE_NOT_OWNED)); - REQUIRE(binSemaph->acquire(SemaphoreIF::POLLING) == - result::OK); - { - // not precise enough on linux.. should use clock instead.. - //Stopwatch stopwatch(false); - //REQUIRE(binSemaph->acquire(SemaphoreIF::TimeoutType::WAITING, 5) == - // SemaphoreIF::SEMAPHORE_TIMEOUT); - //dur_millis_t time = stopwatch.stop(); - //CHECK(time == 5); - } - REQUIRE(binSemaph->getSemaphoreCounter() == 0); - REQUIRE(binSemaph->release() == result::OK); - } - SemaphoreFactory::instance()->deleteSemaphore(binSemaph); - // perform tear-down here +// binary semaphores currently only supported on linux +#ifdef FSFW_OSAL_LINUX + +TEST_CASE("Binary Semaphore Test", "[BinSemaphore]") { + // perform set-up here + SemaphoreIF* binSemaph = SemaphoreFactory::instance()->createBinarySemaphore(); + REQUIRE(binSemaph != nullptr); + SECTION("Simple Test") { + // set-up is run for each section + REQUIRE(binSemaph->getSemaphoreCounter() == 1); + REQUIRE(binSemaph->release() == static_cast(SemaphoreIF::SEMAPHORE_NOT_OWNED)); + REQUIRE(binSemaph->acquire(SemaphoreIF::POLLING) == returnvalue::OK); + { + // not precise enough on linux.. should use clock instead.. + // Stopwatch stopwatch(false); + // REQUIRE(binSemaph->acquire(SemaphoreIF::TimeoutType::WAITING, 5) == + // SemaphoreIF::SEMAPHORE_TIMEOUT); + // dur_millis_t time = stopwatch.stop(); + // CHECK(time == 5); + } + REQUIRE(binSemaph->getSemaphoreCounter() == 0); + REQUIRE(binSemaph->release() == returnvalue::OK); + } + SemaphoreFactory::instance()->deleteSemaphore(binSemaph); + // perform tear-down here } - -TEST_CASE("Counting Semaphore Test" , "[CountingSemaph]") { - SECTION("Simple Test") { - - } +TEST_CASE("Counting Semaphore Test", "[CountingSemaph]") { + SECTION("Simple Test") {} } -*/ -#endif +#endif \ No newline at end of file diff --git a/unittests/testcfg/devices/logicalAddresses.h b/unittests/testcfg/devices/logicalAddresses.h index 788c124f..a7e34cce 100644 --- a/unittests/testcfg/devices/logicalAddresses.h +++ b/unittests/testcfg/devices/logicalAddresses.h @@ -7,7 +7,7 @@ namespace addresses { /* Logical addresses have uint32_t datatype */ -enum logicalAddresses : address_t {}; +enum LogicAddress : address_t {}; } // namespace addresses #endif /* CONFIG_DEVICES_LOGICALADDRESSES_H_ */