From 9ce59d3c750e74e81c04a0a740c6994c48674b5c Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 22 Mar 2022 17:54:09 +0100 Subject: [PATCH 01/52] added an additional conversion function - timeval to TimeOfDay_t --- src/fsfw/timemanager/Clock.h | 7 +++++++ src/fsfw/timemanager/ClockCommon.cpp | 21 ++++++++++++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/fsfw/timemanager/Clock.h b/src/fsfw/timemanager/Clock.h index 99e8a56a..e9afff2e 100644 --- a/src/fsfw/timemanager/Clock.h +++ b/src/fsfw/timemanager/Clock.h @@ -99,6 +99,13 @@ class Clock { */ static ReturnValue_t getDateAndTime(TimeOfDay_t *time); + /** + * Convert to time of day struct given the POSIX timeval struct + * @param from + * @param to + * @return + */ + static ReturnValue_t convertTimevalToTimeOfDay(const timeval *from, TimeOfDay_t *to); /** * Converts a time of day struct to POSIX seconds. * @param time The time of day as input diff --git a/src/fsfw/timemanager/ClockCommon.cpp b/src/fsfw/timemanager/ClockCommon.cpp index e5749b19..18407362 100644 --- a/src/fsfw/timemanager/ClockCommon.cpp +++ b/src/fsfw/timemanager/ClockCommon.cpp @@ -1,7 +1,9 @@ +#include + #include "fsfw/ipc/MutexGuard.h" #include "fsfw/timemanager/Clock.h" -ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval *tt) { +ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) { uint16_t leapSeconds; ReturnValue_t result = getLeapSeconds(&leapSeconds); if (result != HasReturnvaluesIF::RETURN_OK) { @@ -31,7 +33,7 @@ ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) { return HasReturnvaluesIF::RETURN_OK; } -ReturnValue_t Clock::getLeapSeconds(uint16_t *leapSeconds_) { +ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) { if (timeMutex == nullptr) { return HasReturnvaluesIF::RETURN_FAILED; } @@ -42,9 +44,22 @@ ReturnValue_t Clock::getLeapSeconds(uint16_t *leapSeconds_) { return HasReturnvaluesIF::RETURN_OK; } +ReturnValue_t Clock::convertTimevalToTimeOfDay(const timeval* from, TimeOfDay_t* to) { + struct tm* timeInfo; + timeInfo = gmtime(&from->tv_sec); + to->year = timeInfo->tm_year + 1900; + to->month = timeInfo->tm_mon + 1; + to->day = timeInfo->tm_mday; + to->hour = timeInfo->tm_hour; + to->minute = timeInfo->tm_min; + to->second = timeInfo->tm_sec; + to->usecond = from->tv_usec; + return HasReturnvaluesIF::RETURN_OK; +} + ReturnValue_t Clock::checkOrCreateClockMutex() { if (timeMutex == nullptr) { - MutexFactory *mutexFactory = MutexFactory::instance(); + MutexFactory* mutexFactory = MutexFactory::instance(); if (mutexFactory == nullptr) { return HasReturnvaluesIF::RETURN_FAILED; } From 7ffb4107d246446c468ca10c49a60a939e39e29f Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 25 Mar 2022 13:32:29 +0100 Subject: [PATCH 02/52] added missing docs --- src/fsfw/timemanager/ClockCommon.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/fsfw/timemanager/ClockCommon.cpp b/src/fsfw/timemanager/ClockCommon.cpp index 18407362..87b88497 100644 --- a/src/fsfw/timemanager/ClockCommon.cpp +++ b/src/fsfw/timemanager/ClockCommon.cpp @@ -46,6 +46,9 @@ ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) { ReturnValue_t Clock::convertTimevalToTimeOfDay(const timeval* from, TimeOfDay_t* to) { struct tm* timeInfo; + // According to https://en.cppreference.com/w/c/chrono/gmtime, the implementation of gmtime_s + // in the Windows CRT is incompatible with the C standard but this should not be an issue for + // this implementation timeInfo = gmtime(&from->tv_sec); to->year = timeInfo->tm_year + 1900; to->month = timeInfo->tm_mon + 1; From 7095999bd2a412a475362bce19f6f1eb9d1cfec6 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 25 Mar 2022 13:34:35 +0100 Subject: [PATCH 03/52] remove CCSDSTime function --- src/fsfw/timemanager/CCSDSTime.cpp | 5 ----- src/fsfw/timemanager/CCSDSTime.h | 1 - 2 files changed, 6 deletions(-) diff --git a/src/fsfw/timemanager/CCSDSTime.cpp b/src/fsfw/timemanager/CCSDSTime.cpp index c5132cbb..6a0a8e77 100644 --- a/src/fsfw/timemanager/CCSDSTime.cpp +++ b/src/fsfw/timemanager/CCSDSTime.cpp @@ -489,11 +489,6 @@ ReturnValue_t CCSDSTime::checkTimeOfDay(const Clock::TimeOfDay_t* time) { return RETURN_OK; } -ReturnValue_t CCSDSTime::convertTimevalToTimeOfDay(Clock::TimeOfDay_t* to, timeval* from) { - // This is rather tricky. Implement only if needed. Also, if so, move to OSAL. - return UNSUPPORTED_TIME_FORMAT; -} - ReturnValue_t CCSDSTime::convertFromCDS(timeval* to, const uint8_t* from, size_t* foundLength, size_t maxLength) { uint8_t pField = *from; diff --git a/src/fsfw/timemanager/CCSDSTime.h b/src/fsfw/timemanager/CCSDSTime.h index 9de41e09..19c980d0 100644 --- a/src/fsfw/timemanager/CCSDSTime.h +++ b/src/fsfw/timemanager/CCSDSTime.h @@ -223,7 +223,6 @@ class CCSDSTime : public HasReturnvaluesIF { uint8_t *day); static bool isLeapYear(uint32_t year); - static ReturnValue_t convertTimevalToTimeOfDay(Clock::TimeOfDay_t *to, timeval *from); }; #endif /* FSFW_TIMEMANAGER_CCSDSTIME_H_ */ From 59ab54b2fb0ff75d253cbbb6bb4ea59dbce37bbf Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 25 Mar 2022 13:41:37 +0100 Subject: [PATCH 04/52] call corrections --- src/fsfw/timemanager/CCSDSTime.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fsfw/timemanager/CCSDSTime.cpp b/src/fsfw/timemanager/CCSDSTime.cpp index 6a0a8e77..d4f4f331 100644 --- a/src/fsfw/timemanager/CCSDSTime.cpp +++ b/src/fsfw/timemanager/CCSDSTime.cpp @@ -91,7 +91,7 @@ ReturnValue_t CCSDSTime::convertFromCDS(Clock::TimeOfDay_t* to, const uint8_t* f if (result != HasReturnvaluesIF::RETURN_OK) { return result; } - return convertTimevalToTimeOfDay(to, &time); + return Clock::convertTimevalToTimeOfDay(to, &time); } ReturnValue_t CCSDSTime::convertFromCCS(Clock::TimeOfDay_t* to, const uint8_t* from, @@ -578,7 +578,7 @@ ReturnValue_t CCSDSTime::convertFromCDS(Clock::TimeOfDay_t* to, const CCSDSTime: if (result != HasReturnvaluesIF::RETURN_OK) { return result; } - return CCSDSTime::convertTimevalToTimeOfDay(to, &tempTimeval); + return Clock::convertTimevalToTimeOfDay(to, &tempTimeval); } ReturnValue_t CCSDSTime::convertFromCUC(timeval* to, uint8_t pField, const uint8_t* from, From d0fec93dc34007aafb988e04106f01524670cb8a Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 25 Mar 2022 13:42:49 +0100 Subject: [PATCH 05/52] argument order inversion --- src/fsfw/timemanager/CCSDSTime.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fsfw/timemanager/CCSDSTime.cpp b/src/fsfw/timemanager/CCSDSTime.cpp index d4f4f331..9ebd1d79 100644 --- a/src/fsfw/timemanager/CCSDSTime.cpp +++ b/src/fsfw/timemanager/CCSDSTime.cpp @@ -91,7 +91,7 @@ ReturnValue_t CCSDSTime::convertFromCDS(Clock::TimeOfDay_t* to, const uint8_t* f if (result != HasReturnvaluesIF::RETURN_OK) { return result; } - return Clock::convertTimevalToTimeOfDay(to, &time); + return Clock::convertTimevalToTimeOfDay(&time, to); } ReturnValue_t CCSDSTime::convertFromCCS(Clock::TimeOfDay_t* to, const uint8_t* from, @@ -578,7 +578,7 @@ ReturnValue_t CCSDSTime::convertFromCDS(Clock::TimeOfDay_t* to, const CCSDSTime: if (result != HasReturnvaluesIF::RETURN_OK) { return result; } - return Clock::convertTimevalToTimeOfDay(to, &tempTimeval); + return Clock::convertTimevalToTimeOfDay(&tempTimeval, to); } ReturnValue_t CCSDSTime::convertFromCUC(timeval* to, uint8_t pField, const uint8_t* from, From 10398855a9aeddfc808f511f24d3e363846bc756 Mon Sep 17 00:00:00 2001 From: Steffen Gaisser Date: Fri, 25 Mar 2022 18:47:31 +0100 Subject: [PATCH 06/52] Added more unittest coverage Added Mutex for gmtime functions Moved Statics used in ClockCommon to ClockCommon --- src/fsfw/osal/freertos/Clock.cpp | 3 - src/fsfw/osal/host/Clock.cpp | 11 +- src/fsfw/osal/linux/Clock.cpp | 12 +- src/fsfw/osal/rtems/Clock.cpp | 2 - src/fsfw/timemanager/Clock.h | 1 + src/fsfw/timemanager/ClockCommon.cpp | 17 ++- .../unit/globalfunctions/CMakeLists.txt | 1 + .../globalfunctions/testTimevalOperations.cpp | 125 ++++++++++++++++++ tests/src/fsfw_tests/unit/osal/CMakeLists.txt | 1 + tests/src/fsfw_tests/unit/osal/TestClock.cpp | 92 +++++++++++++ .../unit/timemanager/TestCCSDSTime.cpp | 14 ++ 11 files changed, 266 insertions(+), 13 deletions(-) create mode 100644 tests/src/fsfw_tests/unit/globalfunctions/testTimevalOperations.cpp create mode 100644 tests/src/fsfw_tests/unit/osal/TestClock.cpp diff --git a/src/fsfw/osal/freertos/Clock.cpp b/src/fsfw/osal/freertos/Clock.cpp index 05083968..cabf7d81 100644 --- a/src/fsfw/osal/freertos/Clock.cpp +++ b/src/fsfw/osal/freertos/Clock.cpp @@ -11,9 +11,6 @@ // TODO sanitize input? // TODO much of this code can be reused for tick-only systems -uint16_t Clock::leapSeconds = 0; -MutexIF* Clock::timeMutex = nullptr; - uint32_t Clock::getTicksPerSecond(void) { return 1000; } ReturnValue_t Clock::setClock(const TimeOfDay_t* time) { diff --git a/src/fsfw/osal/host/Clock.cpp b/src/fsfw/osal/host/Clock.cpp index d0acdfdf..b4fd73f6 100644 --- a/src/fsfw/osal/host/Clock.cpp +++ b/src/fsfw/osal/host/Clock.cpp @@ -4,6 +4,7 @@ #include "fsfw/platform.h" #include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/ipc/MutexGuard.h" #if defined(PLATFORM_WIN) #include @@ -11,9 +12,6 @@ #include #endif -uint16_t Clock::leapSeconds = 0; -MutexIF* Clock::timeMutex = NULL; - using SystemClock = std::chrono::system_clock; uint32_t Clock::getTicksPerSecond(void) { @@ -127,6 +125,13 @@ ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) { auto seconds = std::chrono::time_point_cast(now); auto fraction = now - seconds; time_t tt = SystemClock::to_time_t(now); + ReturnValue_t result = checkOrCreateClockMutex(); + if(result != HasReturnvaluesIF::RETURN_OK){ + return result; + } + MutexGuard helper(timeMutex); + // gmtime writes its output in a global buffer which is not Thread Safe + // Therefore we have to use a Mutex here struct tm* timeInfo; timeInfo = gmtime(&tt); time->year = timeInfo->tm_year + 1900; diff --git a/src/fsfw/osal/linux/Clock.cpp b/src/fsfw/osal/linux/Clock.cpp index 61eb970f..a3480b56 100644 --- a/src/fsfw/osal/linux/Clock.cpp +++ b/src/fsfw/osal/linux/Clock.cpp @@ -9,9 +9,7 @@ #include #include "fsfw/serviceinterface/ServiceInterface.h" - -uint16_t Clock::leapSeconds = 0; -MutexIF* Clock::timeMutex = NULL; +#include "fsfw/ipc/MutexGuard.h" uint32_t Clock::getTicksPerSecond(void) { uint32_t ticks = sysconf(_SC_CLK_TCK); @@ -117,7 +115,13 @@ ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) { // TODO errno return HasReturnvaluesIF::RETURN_FAILED; } - + ReturnValue_t result = checkOrCreateClockMutex(); + if(result != HasReturnvaluesIF::RETURN_OK){ + return result; + } + MutexGuard helper(timeMutex); + // gmtime writes its output in a global buffer which is not Thread Safe + // Therefore we have to use a Mutex here struct tm* timeInfo; timeInfo = gmtime(&timeUnix.tv_sec); time->year = timeInfo->tm_year + 1900; diff --git a/src/fsfw/osal/rtems/Clock.cpp b/src/fsfw/osal/rtems/Clock.cpp index 06b0c1d8..fe0afb46 100644 --- a/src/fsfw/osal/rtems/Clock.cpp +++ b/src/fsfw/osal/rtems/Clock.cpp @@ -6,8 +6,6 @@ #include "fsfw/ipc/MutexGuard.h" #include "fsfw/osal/rtems/RtemsBasic.h" -uint16_t Clock::leapSeconds = 0; -MutexIF* Clock::timeMutex = nullptr; uint32_t Clock::getTicksPerSecond(void) { rtems_interval ticks_per_second = rtems_clock_get_ticks_per_second(); diff --git a/src/fsfw/timemanager/Clock.h b/src/fsfw/timemanager/Clock.h index e9afff2e..75c898e5 100644 --- a/src/fsfw/timemanager/Clock.h +++ b/src/fsfw/timemanager/Clock.h @@ -173,6 +173,7 @@ class Clock { static MutexIF *timeMutex; static uint16_t leapSeconds; + static bool leapSecondsSet; }; #endif /* FSFW_TIMEMANAGER_CLOCK_H_ */ diff --git a/src/fsfw/timemanager/ClockCommon.cpp b/src/fsfw/timemanager/ClockCommon.cpp index 87b88497..c24dd781 100644 --- a/src/fsfw/timemanager/ClockCommon.cpp +++ b/src/fsfw/timemanager/ClockCommon.cpp @@ -3,6 +3,10 @@ #include "fsfw/ipc/MutexGuard.h" #include "fsfw/timemanager/Clock.h" +uint16_t Clock::leapSeconds = 0; +MutexIF* Clock::timeMutex = nullptr; +bool Clock::leapSecondsSet = false; + ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) { uint16_t leapSeconds; ReturnValue_t result = getLeapSeconds(&leapSeconds); @@ -29,12 +33,16 @@ ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) { MutexGuard helper(timeMutex); leapSeconds = leapSeconds_; + leapSecondsSet = true; return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) { - if (timeMutex == nullptr) { + if(not leapSecondsSet){ + return HasReturnvaluesIF::RETURN_FAILED; + } + if (checkOrCreateClockMutex() != HasReturnvaluesIF::RETURN_OK) { return HasReturnvaluesIF::RETURN_FAILED; } MutexGuard helper(timeMutex); @@ -49,6 +57,13 @@ ReturnValue_t Clock::convertTimevalToTimeOfDay(const timeval* from, TimeOfDay_t* // According to https://en.cppreference.com/w/c/chrono/gmtime, the implementation of gmtime_s // in the Windows CRT is incompatible with the C standard but this should not be an issue for // this implementation + ReturnValue_t result = checkOrCreateClockMutex(); + if(result != HasReturnvaluesIF::RETURN_OK){ + return result; + } + MutexGuard helper(timeMutex); + // gmtime writes its output in a global buffer which is not Thread Safe + // Therefore we have to use a Mutex here timeInfo = gmtime(&from->tv_sec); to->year = timeInfo->tm_year + 1900; to->month = timeInfo->tm_mon + 1; diff --git a/tests/src/fsfw_tests/unit/globalfunctions/CMakeLists.txt b/tests/src/fsfw_tests/unit/globalfunctions/CMakeLists.txt index 79f847bf..348b99fc 100644 --- a/tests/src/fsfw_tests/unit/globalfunctions/CMakeLists.txt +++ b/tests/src/fsfw_tests/unit/globalfunctions/CMakeLists.txt @@ -3,4 +3,5 @@ target_sources(${FSFW_TEST_TGT} PRIVATE testOpDivider.cpp testBitutil.cpp testCRC.cpp + testTimevalOperations.cpp ) diff --git a/tests/src/fsfw_tests/unit/globalfunctions/testTimevalOperations.cpp b/tests/src/fsfw_tests/unit/globalfunctions/testTimevalOperations.cpp new file mode 100644 index 00000000..92242ed9 --- /dev/null +++ b/tests/src/fsfw_tests/unit/globalfunctions/testTimevalOperations.cpp @@ -0,0 +1,125 @@ +#include +#include + +#include + +#include "fsfw_tests/unit/CatchDefinitions.h" + +TEST_CASE("TimevalTest", "[timevalOperations]"){ + SECTION("Comparison"){ + timeval t1; + t1.tv_sec = 1648227422; + t1.tv_usec = 123456; + timeval t2; + t2.tv_sec = 1648227422; + t2.tv_usec = 123456; + REQUIRE(t1 == t2); + REQUIRE(t2 == t1); + REQUIRE_FALSE(t1 != t2); + REQUIRE_FALSE(t2 != t1); + REQUIRE(t1 <= t2); + REQUIRE(t2 <= t1); + REQUIRE(t1 >= t2); + REQUIRE(t2 >= t1); + REQUIRE_FALSE(t1 < t2); + REQUIRE_FALSE(t2 < t1); + REQUIRE_FALSE(t1 > t2); + REQUIRE_FALSE(t2 > t1); + + timeval t3; + t3.tv_sec = 1648227422; + t3.tv_usec = 123457; + REQUIRE_FALSE(t1 == t3); + REQUIRE(t1 != t3); + REQUIRE(t1 <= t3); + REQUIRE_FALSE(t3 <= t1); + REQUIRE_FALSE(t1 >= t3); + REQUIRE(t3 >= t1); + REQUIRE(t1 < t3); + REQUIRE_FALSE(t3 < t1); + REQUIRE_FALSE(t1 > t3); + REQUIRE(t3 > t1); + + timeval t4; + t4.tv_sec = 1648227423; + t4.tv_usec = 123456; + REQUIRE_FALSE(t1 == t4); + REQUIRE(t1 != t4); + REQUIRE(t1 <= t4); + REQUIRE_FALSE(t4 <= t1); + REQUIRE_FALSE(t1 >= t4); + REQUIRE(t4 >= t1); + REQUIRE(t1 < t4); + REQUIRE_FALSE(t4 < t1); + REQUIRE_FALSE(t1 > t4); + REQUIRE(t4 > t1); + } + SECTION("Operators"){ + timeval t1; + t1.tv_sec = 1648227422; + t1.tv_usec = 123456; + timeval t2; + t2.tv_sec = 1648227422; + t2.tv_usec = 123456; + timeval t3 = t1 - t2; + REQUIRE(t3.tv_sec == 0); + REQUIRE(t3.tv_usec == 0); + timeval t4 = t1 - t3; + REQUIRE(t4.tv_sec == 1648227422); + REQUIRE(t4.tv_usec == 123456); + timeval t5 = t3 - t1; + REQUIRE(t5.tv_sec == -1648227422); + REQUIRE(t5.tv_usec == -123456); + + timeval t6; + t6.tv_sec = 1648227400; + t6.tv_usec = 999999; + + timeval t7 = t6 + t1; + REQUIRE(t7.tv_sec == (1648227422ull + 1648227400ull + 1ull)); + REQUIRE(t7.tv_usec == 123455); + + timeval t8 = t1 - t6; + REQUIRE(t8.tv_sec == 1648227422 - 1648227400 - 1); + REQUIRE(t8.tv_usec == 123457); + + double scalar = 2; + timeval t9 = t1 * scalar; + REQUIRE(t9.tv_sec == 3296454844); + REQUIRE(t9.tv_usec == 246912); + timeval t10 = scalar * t1; + REQUIRE(t10.tv_sec == 3296454844); + REQUIRE(t10.tv_usec == 246912); + timeval t11 = t6 * scalar; + REQUIRE(t11.tv_sec == (3296454800 + 1)); + REQUIRE(t11.tv_usec == 999998); + + timeval t12 = t1 / scalar; + REQUIRE(t12.tv_sec == 824113711); + REQUIRE(t12.tv_usec == 61728); + + timeval t13 = t6 / scalar; + REQUIRE(t13.tv_sec == 824113700); + // Rounding issue + REQUIRE(t13.tv_usec == 499999); + + double scalar2 = t9 / t1; + REQUIRE(scalar2 == Catch::Approx(2.0)); + double scalar3 = t1 / t6; + REQUIRE(scalar3 == Catch::Approx(1.000000013)); + double scalar4 = t3 / t1; + REQUIRE(scalar4 == Catch::Approx(0)); + double scalar5 = t12 / t1; + REQUIRE(scalar5 == Catch::Approx(0.5)); + } + + SECTION("timevalOperations::toTimeval"){ + double seconds = 1648227422.123456; + timeval t1 = timevalOperations::toTimeval(seconds); + REQUIRE(t1.tv_sec == 1648227422); + // Allow 1 usec rounding tolerance + REQUIRE(t1.tv_usec >= 123455); + REQUIRE(t1.tv_usec <= 123457); + } + +} \ No newline at end of file diff --git a/tests/src/fsfw_tests/unit/osal/CMakeLists.txt b/tests/src/fsfw_tests/unit/osal/CMakeLists.txt index 293be2e8..030d363b 100644 --- a/tests/src/fsfw_tests/unit/osal/CMakeLists.txt +++ b/tests/src/fsfw_tests/unit/osal/CMakeLists.txt @@ -1,4 +1,5 @@ target_sources(${FSFW_TEST_TGT} PRIVATE TestMessageQueue.cpp TestSemaphore.cpp + TestClock.cpp ) diff --git a/tests/src/fsfw_tests/unit/osal/TestClock.cpp b/tests/src/fsfw_tests/unit/osal/TestClock.cpp new file mode 100644 index 00000000..ff530832 --- /dev/null +++ b/tests/src/fsfw_tests/unit/osal/TestClock.cpp @@ -0,0 +1,92 @@ +#include +#include + +#include +#include +#include + +#include "fsfw_tests/unit/CatchDefinitions.h" + +TEST_CASE("OSAL::Clock Test", "[OSAL::Clock Test]"){ + SECTION("Test getClock"){ + timeval time; + ReturnValue_t result = Clock::getClock_timeval(&time); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + Clock::TimeOfDay_t timeOfDay; + result = Clock::getDateAndTime(&timeOfDay); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + timeval timeOfDayAsTimeval; + result = Clock::convertTimeOfDayToTimeval(&timeOfDay, &timeOfDayAsTimeval); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + // We require timeOfDayAsTimeval to be larger than time as it + // was request a few ns later + double difference = timevalOperations::toDouble(timeOfDayAsTimeval-time); + CHECK(difference>=0.0); + CHECK(difference<=0.005); + + // Conversion in the other direction + Clock::TimeOfDay_t timevalAsTimeOfDay; + result = Clock::convertTimevalToTimeOfDay(&time, &timevalAsTimeOfDay); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + CHECK(timevalAsTimeOfDay.year <= timeOfDay.year); + // TODO We should write TimeOfDay operators! + } + SECTION("Leap seconds"){ + uint16_t leapSeconds = 0; + ReturnValue_t result = Clock::getLeapSeconds(&leapSeconds); + REQUIRE(result == HasReturnvaluesIF::RETURN_FAILED); + REQUIRE(leapSeconds == 0); + result = Clock::setLeapSeconds(18); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + result = Clock::getLeapSeconds(&leapSeconds); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(leapSeconds == 18); + } + SECTION("usec Test"){ + timeval timeAsTimeval; + ReturnValue_t result = Clock::getClock_timeval(&timeAsTimeval); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + uint64_t timeAsUsec = 0; + result = Clock::getClock_usecs(&timeAsUsec); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + double timeAsUsecDouble = static_cast(timeAsUsec)/1000000.0; + timeval timeAsUsecTimeval = timevalOperations::toTimeval(timeAsUsecDouble); + double difference = timevalOperations::toDouble(timeAsTimeval - timeAsUsecTimeval); + // We accept 5 ms difference + CHECK(abs(difference) <= 0.005); + uint64_t timevalAsUint64 = static_cast(timeAsTimeval.tv_sec)*1000000ull + static_cast(timeAsTimeval.tv_usec); + if(timeAsUsec > timevalAsUint64){ + // This should not be the case but we can see some rounding issue sometimes + // This is the case if used in valgrind. This might indicate an other issue + CHECK((timeAsUsec - timevalAsUint64)>=0); + CHECK((timeAsUsec - timevalAsUint64)<=(5*1000)); + }else{ + CHECK((timevalAsUint64 - timeAsUsec)>=0); + CHECK((timevalAsUint64 - timeAsUsec)<=(5*1000)); + } + + } + SECTION("Test j2000"){ + double j2000; + timeval time; + time.tv_sec = 1648208539; + time.tv_usec = 0; + ReturnValue_t result = Clock::convertTimevalToJD2000(time, &j2000); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + double correctJ2000 = 2459663.98772 - 2451545.0; + CHECK(j2000 == Catch::Approx(correctJ2000).margin(1.2*1e-8)); + } + SECTION("Convert to TT"){ + timeval utcTime; + utcTime.tv_sec = 1648208539; + utcTime.tv_usec = 999000; + timeval tt; + ReturnValue_t result = Clock::setLeapSeconds(27); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + result = Clock::convertUTCToTT(utcTime, &tt); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + CHECK(tt.tv_usec == 183000); + // The plus 1 is a own forced overflow of usecs + CHECK(tt.tv_sec == (1648208539 + 27 + 10 + 32 + 1)); + } +} \ No newline at end of file diff --git a/tests/src/fsfw_tests/unit/timemanager/TestCCSDSTime.cpp b/tests/src/fsfw_tests/unit/timemanager/TestCCSDSTime.cpp index 2e80487a..2bf6aaf0 100644 --- a/tests/src/fsfw_tests/unit/timemanager/TestCCSDSTime.cpp +++ b/tests/src/fsfw_tests/unit/timemanager/TestCCSDSTime.cpp @@ -120,6 +120,8 @@ TEST_CASE("CCSDSTime Tests", "[TestCCSDSTime]") { CHECK(cdsTime.msDay_l == 0xC5); CHECK(cdsTime.msDay_ll == 0xC3); + + // Conversion back to timeval timeval timeReturnAsTimeval; result = CCSDSTime::convertFromCDS(&timeReturnAsTimeval, &cdsTime); @@ -128,5 +130,17 @@ TEST_CASE("CCSDSTime Tests", "[TestCCSDSTime]") { timeval difference = timeAsTimeval - timeReturnAsTimeval; CHECK(difference.tv_usec == 456); CHECK(difference.tv_sec == 0); + + Clock::TimeOfDay_t timeReturnAsTimeOfDay; + result = CCSDSTime::convertFromCDS(&timeReturnAsTimeOfDay, &cdsTime); + CHECK(result == HasReturnvaluesIF::RETURN_OK); + CHECK(timeReturnAsTimeOfDay.year == 2020); + CHECK(timeReturnAsTimeOfDay.month == 2); + CHECK(timeReturnAsTimeOfDay.day == 29); + CHECK(timeReturnAsTimeOfDay.hour == 13); + CHECK(timeReturnAsTimeOfDay.minute == 24); + CHECK(timeReturnAsTimeOfDay.second == 45); + // micro seconds precision is lost + CHECK(timeReturnAsTimeOfDay.usecond == 123000); } } \ No newline at end of file From 665d8cd4792310f01236b4c7ef7413d3ac340a9a Mon Sep 17 00:00:00 2001 From: Steffen Gaisser Date: Fri, 25 Mar 2022 18:48:53 +0100 Subject: [PATCH 07/52] Applied clang format --- src/fsfw/osal/host/Clock.cpp | 6 +- src/fsfw/osal/linux/Clock.cpp | 4 +- src/fsfw/osal/rtems/Clock.cpp | 1 - src/fsfw/timemanager/ClockCommon.cpp | 4 +- src/fsfw/version.cpp | 3 +- src/fsfw/version.h | 2 +- .../globalfunctions/testTimevalOperations.cpp | 219 +++++++++--------- tests/src/fsfw_tests/unit/osal/TestClock.cpp | 164 ++++++------- .../unit/timemanager/TestCCSDSTime.cpp | 2 - tests/src/fsfw_tests/unit/version.cpp | 50 ++-- 10 files changed, 226 insertions(+), 229 deletions(-) diff --git a/src/fsfw/osal/host/Clock.cpp b/src/fsfw/osal/host/Clock.cpp index b4fd73f6..19e120b3 100644 --- a/src/fsfw/osal/host/Clock.cpp +++ b/src/fsfw/osal/host/Clock.cpp @@ -2,9 +2,9 @@ #include +#include "fsfw/ipc/MutexGuard.h" #include "fsfw/platform.h" #include "fsfw/serviceinterface/ServiceInterface.h" -#include "fsfw/ipc/MutexGuard.h" #if defined(PLATFORM_WIN) #include @@ -125,8 +125,8 @@ ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) { auto seconds = std::chrono::time_point_cast(now); auto fraction = now - seconds; time_t tt = SystemClock::to_time_t(now); - ReturnValue_t result = checkOrCreateClockMutex(); - if(result != HasReturnvaluesIF::RETURN_OK){ + ReturnValue_t result = checkOrCreateClockMutex(); + if (result != HasReturnvaluesIF::RETURN_OK) { return result; } MutexGuard helper(timeMutex); diff --git a/src/fsfw/osal/linux/Clock.cpp b/src/fsfw/osal/linux/Clock.cpp index a3480b56..534e7e22 100644 --- a/src/fsfw/osal/linux/Clock.cpp +++ b/src/fsfw/osal/linux/Clock.cpp @@ -8,8 +8,8 @@ #include -#include "fsfw/serviceinterface/ServiceInterface.h" #include "fsfw/ipc/MutexGuard.h" +#include "fsfw/serviceinterface/ServiceInterface.h" uint32_t Clock::getTicksPerSecond(void) { uint32_t ticks = sysconf(_SC_CLK_TCK); @@ -116,7 +116,7 @@ ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) { return HasReturnvaluesIF::RETURN_FAILED; } ReturnValue_t result = checkOrCreateClockMutex(); - if(result != HasReturnvaluesIF::RETURN_OK){ + if (result != HasReturnvaluesIF::RETURN_OK) { return result; } MutexGuard helper(timeMutex); diff --git a/src/fsfw/osal/rtems/Clock.cpp b/src/fsfw/osal/rtems/Clock.cpp index fe0afb46..831c67d4 100644 --- a/src/fsfw/osal/rtems/Clock.cpp +++ b/src/fsfw/osal/rtems/Clock.cpp @@ -6,7 +6,6 @@ #include "fsfw/ipc/MutexGuard.h" #include "fsfw/osal/rtems/RtemsBasic.h" - uint32_t Clock::getTicksPerSecond(void) { rtems_interval ticks_per_second = rtems_clock_get_ticks_per_second(); return static_cast(ticks_per_second); diff --git a/src/fsfw/timemanager/ClockCommon.cpp b/src/fsfw/timemanager/ClockCommon.cpp index c24dd781..ca8b12a4 100644 --- a/src/fsfw/timemanager/ClockCommon.cpp +++ b/src/fsfw/timemanager/ClockCommon.cpp @@ -39,7 +39,7 @@ ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) { } ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) { - if(not leapSecondsSet){ + if (not leapSecondsSet) { return HasReturnvaluesIF::RETURN_FAILED; } if (checkOrCreateClockMutex() != HasReturnvaluesIF::RETURN_OK) { @@ -58,7 +58,7 @@ ReturnValue_t Clock::convertTimevalToTimeOfDay(const timeval* from, TimeOfDay_t* // in the Windows CRT is incompatible with the C standard but this should not be an issue for // this implementation ReturnValue_t result = checkOrCreateClockMutex(); - if(result != HasReturnvaluesIF::RETURN_OK){ + if (result != HasReturnvaluesIF::RETURN_OK) { return result; } MutexGuard helper(timeMutex); diff --git a/src/fsfw/version.cpp b/src/fsfw/version.cpp index 926e465f..e4a62002 100644 --- a/src/fsfw/version.cpp +++ b/src/fsfw/version.cpp @@ -1,8 +1,9 @@ #include "version.h" -#include "fsfw/FSFWVersion.h" #include +#include "fsfw/FSFWVersion.h" + #ifdef major #undef major #endif diff --git a/src/fsfw/version.h b/src/fsfw/version.h index 7cddf193..bb4d0399 100644 --- a/src/fsfw/version.h +++ b/src/fsfw/version.h @@ -29,7 +29,7 @@ class Version { } friend bool operator>(const Version& v1, const Version& v2) { - return not (v1 < v2) and not (v1 == v2); + return not(v1 < v2) and not(v1 == v2); } friend bool operator<=(const Version& v1, const Version& v2) { return ((v1 == v2) or (v1 < v2)); } diff --git a/tests/src/fsfw_tests/unit/globalfunctions/testTimevalOperations.cpp b/tests/src/fsfw_tests/unit/globalfunctions/testTimevalOperations.cpp index 92242ed9..347d2204 100644 --- a/tests/src/fsfw_tests/unit/globalfunctions/testTimevalOperations.cpp +++ b/tests/src/fsfw_tests/unit/globalfunctions/testTimevalOperations.cpp @@ -1,125 +1,124 @@ -#include -#include - #include +#include +#include + #include "fsfw_tests/unit/CatchDefinitions.h" -TEST_CASE("TimevalTest", "[timevalOperations]"){ - SECTION("Comparison"){ - timeval t1; - t1.tv_sec = 1648227422; - t1.tv_usec = 123456; - timeval t2; - t2.tv_sec = 1648227422; - t2.tv_usec = 123456; - REQUIRE(t1 == t2); - REQUIRE(t2 == t1); - REQUIRE_FALSE(t1 != t2); - REQUIRE_FALSE(t2 != t1); - REQUIRE(t1 <= t2); - REQUIRE(t2 <= t1); - REQUIRE(t1 >= t2); - REQUIRE(t2 >= t1); - REQUIRE_FALSE(t1 < t2); - REQUIRE_FALSE(t2 < t1); - REQUIRE_FALSE(t1 > t2); - REQUIRE_FALSE(t2 > t1); +TEST_CASE("TimevalTest", "[timevalOperations]") { + SECTION("Comparison") { + timeval t1; + t1.tv_sec = 1648227422; + t1.tv_usec = 123456; + timeval t2; + t2.tv_sec = 1648227422; + t2.tv_usec = 123456; + REQUIRE(t1 == t2); + REQUIRE(t2 == t1); + REQUIRE_FALSE(t1 != t2); + REQUIRE_FALSE(t2 != t1); + REQUIRE(t1 <= t2); + REQUIRE(t2 <= t1); + REQUIRE(t1 >= t2); + REQUIRE(t2 >= t1); + REQUIRE_FALSE(t1 < t2); + REQUIRE_FALSE(t2 < t1); + REQUIRE_FALSE(t1 > t2); + REQUIRE_FALSE(t2 > t1); - timeval t3; - t3.tv_sec = 1648227422; - t3.tv_usec = 123457; - REQUIRE_FALSE(t1 == t3); - REQUIRE(t1 != t3); - REQUIRE(t1 <= t3); - REQUIRE_FALSE(t3 <= t1); - REQUIRE_FALSE(t1 >= t3); - REQUIRE(t3 >= t1); - REQUIRE(t1 < t3); - REQUIRE_FALSE(t3 < t1); - REQUIRE_FALSE(t1 > t3); - REQUIRE(t3 > t1); + timeval t3; + t3.tv_sec = 1648227422; + t3.tv_usec = 123457; + REQUIRE_FALSE(t1 == t3); + REQUIRE(t1 != t3); + REQUIRE(t1 <= t3); + REQUIRE_FALSE(t3 <= t1); + REQUIRE_FALSE(t1 >= t3); + REQUIRE(t3 >= t1); + REQUIRE(t1 < t3); + REQUIRE_FALSE(t3 < t1); + REQUIRE_FALSE(t1 > t3); + REQUIRE(t3 > t1); - timeval t4; - t4.tv_sec = 1648227423; - t4.tv_usec = 123456; - REQUIRE_FALSE(t1 == t4); - REQUIRE(t1 != t4); - REQUIRE(t1 <= t4); - REQUIRE_FALSE(t4 <= t1); - REQUIRE_FALSE(t1 >= t4); - REQUIRE(t4 >= t1); - REQUIRE(t1 < t4); - REQUIRE_FALSE(t4 < t1); - REQUIRE_FALSE(t1 > t4); - REQUIRE(t4 > t1); - } - SECTION("Operators"){ - timeval t1; - t1.tv_sec = 1648227422; - t1.tv_usec = 123456; - timeval t2; - t2.tv_sec = 1648227422; - t2.tv_usec = 123456; - timeval t3 = t1 - t2; - REQUIRE(t3.tv_sec == 0); - REQUIRE(t3.tv_usec == 0); - timeval t4 = t1 - t3; - REQUIRE(t4.tv_sec == 1648227422); - REQUIRE(t4.tv_usec == 123456); - timeval t5 = t3 - t1; - REQUIRE(t5.tv_sec == -1648227422); - REQUIRE(t5.tv_usec == -123456); + timeval t4; + t4.tv_sec = 1648227423; + t4.tv_usec = 123456; + REQUIRE_FALSE(t1 == t4); + REQUIRE(t1 != t4); + REQUIRE(t1 <= t4); + REQUIRE_FALSE(t4 <= t1); + REQUIRE_FALSE(t1 >= t4); + REQUIRE(t4 >= t1); + REQUIRE(t1 < t4); + REQUIRE_FALSE(t4 < t1); + REQUIRE_FALSE(t1 > t4); + REQUIRE(t4 > t1); + } + SECTION("Operators") { + timeval t1; + t1.tv_sec = 1648227422; + t1.tv_usec = 123456; + timeval t2; + t2.tv_sec = 1648227422; + t2.tv_usec = 123456; + timeval t3 = t1 - t2; + REQUIRE(t3.tv_sec == 0); + REQUIRE(t3.tv_usec == 0); + timeval t4 = t1 - t3; + REQUIRE(t4.tv_sec == 1648227422); + REQUIRE(t4.tv_usec == 123456); + timeval t5 = t3 - t1; + REQUIRE(t5.tv_sec == -1648227422); + REQUIRE(t5.tv_usec == -123456); - timeval t6; - t6.tv_sec = 1648227400; - t6.tv_usec = 999999; + timeval t6; + t6.tv_sec = 1648227400; + t6.tv_usec = 999999; - timeval t7 = t6 + t1; - REQUIRE(t7.tv_sec == (1648227422ull + 1648227400ull + 1ull)); - REQUIRE(t7.tv_usec == 123455); + timeval t7 = t6 + t1; + REQUIRE(t7.tv_sec == (1648227422ull + 1648227400ull + 1ull)); + REQUIRE(t7.tv_usec == 123455); - timeval t8 = t1 - t6; - REQUIRE(t8.tv_sec == 1648227422 - 1648227400 - 1); - REQUIRE(t8.tv_usec == 123457); + timeval t8 = t1 - t6; + REQUIRE(t8.tv_sec == 1648227422 - 1648227400 - 1); + REQUIRE(t8.tv_usec == 123457); - double scalar = 2; - timeval t9 = t1 * scalar; - REQUIRE(t9.tv_sec == 3296454844); - REQUIRE(t9.tv_usec == 246912); - timeval t10 = scalar * t1; - REQUIRE(t10.tv_sec == 3296454844); - REQUIRE(t10.tv_usec == 246912); - timeval t11 = t6 * scalar; - REQUIRE(t11.tv_sec == (3296454800 + 1)); - REQUIRE(t11.tv_usec == 999998); + double scalar = 2; + timeval t9 = t1 * scalar; + REQUIRE(t9.tv_sec == 3296454844); + REQUIRE(t9.tv_usec == 246912); + timeval t10 = scalar * t1; + REQUIRE(t10.tv_sec == 3296454844); + REQUIRE(t10.tv_usec == 246912); + timeval t11 = t6 * scalar; + REQUIRE(t11.tv_sec == (3296454800 + 1)); + REQUIRE(t11.tv_usec == 999998); - timeval t12 = t1 / scalar; - REQUIRE(t12.tv_sec == 824113711); - REQUIRE(t12.tv_usec == 61728); + timeval t12 = t1 / scalar; + REQUIRE(t12.tv_sec == 824113711); + REQUIRE(t12.tv_usec == 61728); - timeval t13 = t6 / scalar; - REQUIRE(t13.tv_sec == 824113700); - // Rounding issue - REQUIRE(t13.tv_usec == 499999); + timeval t13 = t6 / scalar; + REQUIRE(t13.tv_sec == 824113700); + // Rounding issue + REQUIRE(t13.tv_usec == 499999); - double scalar2 = t9 / t1; - REQUIRE(scalar2 == Catch::Approx(2.0)); - double scalar3 = t1 / t6; - REQUIRE(scalar3 == Catch::Approx(1.000000013)); - double scalar4 = t3 / t1; - REQUIRE(scalar4 == Catch::Approx(0)); - double scalar5 = t12 / t1; - REQUIRE(scalar5 == Catch::Approx(0.5)); - } - - SECTION("timevalOperations::toTimeval"){ - double seconds = 1648227422.123456; - timeval t1 = timevalOperations::toTimeval(seconds); - REQUIRE(t1.tv_sec == 1648227422); - // Allow 1 usec rounding tolerance - REQUIRE(t1.tv_usec >= 123455); - REQUIRE(t1.tv_usec <= 123457); - } + double scalar2 = t9 / t1; + REQUIRE(scalar2 == Catch::Approx(2.0)); + double scalar3 = t1 / t6; + REQUIRE(scalar3 == Catch::Approx(1.000000013)); + double scalar4 = t3 / t1; + REQUIRE(scalar4 == Catch::Approx(0)); + double scalar5 = t12 / t1; + REQUIRE(scalar5 == Catch::Approx(0.5)); + } + SECTION("timevalOperations::toTimeval") { + double seconds = 1648227422.123456; + timeval t1 = timevalOperations::toTimeval(seconds); + REQUIRE(t1.tv_sec == 1648227422); + // Allow 1 usec rounding tolerance + REQUIRE(t1.tv_usec >= 123455); + REQUIRE(t1.tv_usec <= 123457); + } } \ No newline at end of file diff --git a/tests/src/fsfw_tests/unit/osal/TestClock.cpp b/tests/src/fsfw_tests/unit/osal/TestClock.cpp index ff530832..f7c63cce 100644 --- a/tests/src/fsfw_tests/unit/osal/TestClock.cpp +++ b/tests/src/fsfw_tests/unit/osal/TestClock.cpp @@ -1,92 +1,92 @@ -#include #include +#include #include -#include #include +#include #include "fsfw_tests/unit/CatchDefinitions.h" -TEST_CASE("OSAL::Clock Test", "[OSAL::Clock Test]"){ - SECTION("Test getClock"){ - timeval time; - ReturnValue_t result = Clock::getClock_timeval(&time); - REQUIRE(result == HasReturnvaluesIF::RETURN_OK); - Clock::TimeOfDay_t timeOfDay; - result = Clock::getDateAndTime(&timeOfDay); - REQUIRE(result == HasReturnvaluesIF::RETURN_OK); - timeval timeOfDayAsTimeval; - result = Clock::convertTimeOfDayToTimeval(&timeOfDay, &timeOfDayAsTimeval); - REQUIRE(result == HasReturnvaluesIF::RETURN_OK); - // We require timeOfDayAsTimeval to be larger than time as it - // was request a few ns later - double difference = timevalOperations::toDouble(timeOfDayAsTimeval-time); - CHECK(difference>=0.0); - CHECK(difference<=0.005); +TEST_CASE("OSAL::Clock Test", "[OSAL::Clock Test]") { + SECTION("Test getClock") { + timeval time; + ReturnValue_t result = Clock::getClock_timeval(&time); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + Clock::TimeOfDay_t timeOfDay; + result = Clock::getDateAndTime(&timeOfDay); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + timeval timeOfDayAsTimeval; + result = Clock::convertTimeOfDayToTimeval(&timeOfDay, &timeOfDayAsTimeval); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + // We require timeOfDayAsTimeval to be larger than time as it + // was request a few ns later + double difference = timevalOperations::toDouble(timeOfDayAsTimeval - time); + CHECK(difference >= 0.0); + CHECK(difference <= 0.005); - // Conversion in the other direction - Clock::TimeOfDay_t timevalAsTimeOfDay; - result = Clock::convertTimevalToTimeOfDay(&time, &timevalAsTimeOfDay); - REQUIRE(result == HasReturnvaluesIF::RETURN_OK); - CHECK(timevalAsTimeOfDay.year <= timeOfDay.year); - // TODO We should write TimeOfDay operators! - } - SECTION("Leap seconds"){ - uint16_t leapSeconds = 0; - ReturnValue_t result = Clock::getLeapSeconds(&leapSeconds); - REQUIRE(result == HasReturnvaluesIF::RETURN_FAILED); - REQUIRE(leapSeconds == 0); - result = Clock::setLeapSeconds(18); - REQUIRE(result == HasReturnvaluesIF::RETURN_OK); - result = Clock::getLeapSeconds(&leapSeconds); - REQUIRE(result == HasReturnvaluesIF::RETURN_OK); - REQUIRE(leapSeconds == 18); - } - SECTION("usec Test"){ - timeval timeAsTimeval; - ReturnValue_t result = Clock::getClock_timeval(&timeAsTimeval); - REQUIRE(result == HasReturnvaluesIF::RETURN_OK); - uint64_t timeAsUsec = 0; - result = Clock::getClock_usecs(&timeAsUsec); - REQUIRE(result == HasReturnvaluesIF::RETURN_OK); - double timeAsUsecDouble = static_cast(timeAsUsec)/1000000.0; - timeval timeAsUsecTimeval = timevalOperations::toTimeval(timeAsUsecDouble); - double difference = timevalOperations::toDouble(timeAsTimeval - timeAsUsecTimeval); - // We accept 5 ms difference - CHECK(abs(difference) <= 0.005); - uint64_t timevalAsUint64 = static_cast(timeAsTimeval.tv_sec)*1000000ull + static_cast(timeAsTimeval.tv_usec); - if(timeAsUsec > timevalAsUint64){ - // This should not be the case but we can see some rounding issue sometimes - // This is the case if used in valgrind. This might indicate an other issue - CHECK((timeAsUsec - timevalAsUint64)>=0); - CHECK((timeAsUsec - timevalAsUint64)<=(5*1000)); - }else{ - CHECK((timevalAsUint64 - timeAsUsec)>=0); - CHECK((timevalAsUint64 - timeAsUsec)<=(5*1000)); - } - - } - SECTION("Test j2000"){ - double j2000; - timeval time; - time.tv_sec = 1648208539; - time.tv_usec = 0; - ReturnValue_t result = Clock::convertTimevalToJD2000(time, &j2000); - REQUIRE(result == HasReturnvaluesIF::RETURN_OK); - double correctJ2000 = 2459663.98772 - 2451545.0; - CHECK(j2000 == Catch::Approx(correctJ2000).margin(1.2*1e-8)); - } - SECTION("Convert to TT"){ - timeval utcTime; - utcTime.tv_sec = 1648208539; - utcTime.tv_usec = 999000; - timeval tt; - ReturnValue_t result = Clock::setLeapSeconds(27); - REQUIRE(result == HasReturnvaluesIF::RETURN_OK); - result = Clock::convertUTCToTT(utcTime, &tt); - REQUIRE(result == HasReturnvaluesIF::RETURN_OK); - CHECK(tt.tv_usec == 183000); - // The plus 1 is a own forced overflow of usecs - CHECK(tt.tv_sec == (1648208539 + 27 + 10 + 32 + 1)); + // Conversion in the other direction + Clock::TimeOfDay_t timevalAsTimeOfDay; + result = Clock::convertTimevalToTimeOfDay(&time, &timevalAsTimeOfDay); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + CHECK(timevalAsTimeOfDay.year <= timeOfDay.year); + // TODO We should write TimeOfDay operators! + } + SECTION("Leap seconds") { + uint16_t leapSeconds = 0; + ReturnValue_t result = Clock::getLeapSeconds(&leapSeconds); + REQUIRE(result == HasReturnvaluesIF::RETURN_FAILED); + REQUIRE(leapSeconds == 0); + result = Clock::setLeapSeconds(18); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + result = Clock::getLeapSeconds(&leapSeconds); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(leapSeconds == 18); + } + SECTION("usec Test") { + timeval timeAsTimeval; + ReturnValue_t result = Clock::getClock_timeval(&timeAsTimeval); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + uint64_t timeAsUsec = 0; + result = Clock::getClock_usecs(&timeAsUsec); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + double timeAsUsecDouble = static_cast(timeAsUsec) / 1000000.0; + timeval timeAsUsecTimeval = timevalOperations::toTimeval(timeAsUsecDouble); + double difference = timevalOperations::toDouble(timeAsTimeval - timeAsUsecTimeval); + // We accept 5 ms difference + CHECK(abs(difference) <= 0.005); + uint64_t timevalAsUint64 = static_cast(timeAsTimeval.tv_sec) * 1000000ull + + static_cast(timeAsTimeval.tv_usec); + if (timeAsUsec > timevalAsUint64) { + // This should not be the case but we can see some rounding issue sometimes + // This is the case if used in valgrind. This might indicate an other issue + CHECK((timeAsUsec - timevalAsUint64) >= 0); + CHECK((timeAsUsec - timevalAsUint64) <= (5 * 1000)); + } else { + CHECK((timevalAsUint64 - timeAsUsec) >= 0); + CHECK((timevalAsUint64 - timeAsUsec) <= (5 * 1000)); } + } + SECTION("Test j2000") { + double j2000; + timeval time; + time.tv_sec = 1648208539; + time.tv_usec = 0; + ReturnValue_t result = Clock::convertTimevalToJD2000(time, &j2000); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + double correctJ2000 = 2459663.98772 - 2451545.0; + CHECK(j2000 == Catch::Approx(correctJ2000).margin(1.2 * 1e-8)); + } + SECTION("Convert to TT") { + timeval utcTime; + utcTime.tv_sec = 1648208539; + utcTime.tv_usec = 999000; + timeval tt; + ReturnValue_t result = Clock::setLeapSeconds(27); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + result = Clock::convertUTCToTT(utcTime, &tt); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + CHECK(tt.tv_usec == 183000); + // The plus 1 is a own forced overflow of usecs + CHECK(tt.tv_sec == (1648208539 + 27 + 10 + 32 + 1)); + } } \ No newline at end of file diff --git a/tests/src/fsfw_tests/unit/timemanager/TestCCSDSTime.cpp b/tests/src/fsfw_tests/unit/timemanager/TestCCSDSTime.cpp index 2bf6aaf0..6970b193 100644 --- a/tests/src/fsfw_tests/unit/timemanager/TestCCSDSTime.cpp +++ b/tests/src/fsfw_tests/unit/timemanager/TestCCSDSTime.cpp @@ -120,8 +120,6 @@ TEST_CASE("CCSDSTime Tests", "[TestCCSDSTime]") { CHECK(cdsTime.msDay_l == 0xC5); CHECK(cdsTime.msDay_ll == 0xC3); - - // Conversion back to timeval timeval timeReturnAsTimeval; result = CCSDSTime::convertFromCDS(&timeReturnAsTimeval, &cdsTime); diff --git a/tests/src/fsfw_tests/unit/version.cpp b/tests/src/fsfw_tests/unit/version.cpp index 92a930dc..2967dfa5 100644 --- a/tests/src/fsfw_tests/unit/version.cpp +++ b/tests/src/fsfw_tests/unit/version.cpp @@ -17,15 +17,15 @@ TEST_CASE("Version API Tests", "[TestVersionAPI]") { fsfw::Version v1 = fsfw::Version(1, 1, 1); fsfw::Version v2 = fsfw::Version(1, 1, 1); REQUIRE(v1 == v2); - REQUIRE(not (v1 < v2)); - REQUIRE(not (v1 > v2)); + REQUIRE(not(v1 < v2)); + REQUIRE(not(v1 > v2)); REQUIRE(v1 <= v2); REQUIRE(v1 >= v2); v1.revision -= 1; REQUIRE(v1 != v2); - REQUIRE(not (v1 == v2)); - REQUIRE(not (v1 > v2)); - REQUIRE(not (v1 >= v2)); + REQUIRE(not(v1 == v2)); + REQUIRE(not(v1 > v2)); + REQUIRE(not(v1 >= v2)); REQUIRE(v1 < v2); REQUIRE(v1 <= v2); v1.revision += 1; @@ -33,60 +33,60 @@ TEST_CASE("Version API Tests", "[TestVersionAPI]") { REQUIRE(v1 != v2); REQUIRE(v1 < v2); REQUIRE(v1 <= v2); - REQUIRE(not (v1 == v2)); - REQUIRE(not (v1 > v2)); - REQUIRE(not (v1 >= v2)); + REQUIRE(not(v1 == v2)); + REQUIRE(not(v1 > v2)); + REQUIRE(not(v1 >= v2)); v1.minor += 1; v1.major -= 1; REQUIRE(v1 != v2); REQUIRE(v1 < v2); REQUIRE(v1 <= v2); - REQUIRE(not (v1 == v2)); - REQUIRE(not (v1 > v2)); - REQUIRE(not (v1 >= v2)); + REQUIRE(not(v1 == v2)); + REQUIRE(not(v1 > v2)); + REQUIRE(not(v1 >= v2)); v1.major += 1; REQUIRE(v1 == v2); REQUIRE(v1 <= v2); REQUIRE(v1 >= v2); - REQUIRE(not (v1 != v2)); - REQUIRE(not (v1 > v2)); - REQUIRE(not (v1 < v2)); + REQUIRE(not(v1 != v2)); + REQUIRE(not(v1 > v2)); + REQUIRE(not(v1 < v2)); v1.major += 1; v1.minor -= 1; REQUIRE(v1 != v2); REQUIRE(v1 > v2); REQUIRE(v1 >= v2); - REQUIRE(not (v1 == v2)); - REQUIRE(not (v1 < v2)); - REQUIRE(not (v1 <= v2)); + REQUIRE(not(v1 == v2)); + REQUIRE(not(v1 < v2)); + REQUIRE(not(v1 <= v2)); v1.major -= 1; v1.minor += 2; v1.revision -= 1; REQUIRE(v1 != v2); REQUIRE(v1 > v2); REQUIRE(v1 >= v2); - REQUIRE(not (v1 == v2)); - REQUIRE(not (v1 < v2)); - REQUIRE(not (v1 <= v2)); + REQUIRE(not(v1 == v2)); + REQUIRE(not(v1 < v2)); + REQUIRE(not(v1 <= v2)); v1.minor -= 1; v1.revision += 2; REQUIRE(v1 != v2); REQUIRE(v1 > v2); REQUIRE(v1 >= v2); - REQUIRE(not (v1 == v2)); - REQUIRE(not (v1 < v2)); - REQUIRE(not (v1 <= v2)); + REQUIRE(not(v1 == v2)); + REQUIRE(not(v1 < v2)); + REQUIRE(not(v1 <= v2)); v1.revision -= 1; REQUIRE(v1 == v2); REQUIRE(v1 <= v2); REQUIRE(v1 >= v2); - REQUIRE(not (v1 != v2)); + REQUIRE(not(v1 != v2)); #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::info << "v" << fsfw::FSFW_VERSION << std::endl; #endif char verString[10] = {}; fsfw::FSFW_VERSION.getVersion(verString, sizeof(verString)); #if FSFW_DISABLE_PRINTOUT == 0 - printf("v%s\n",verString); + printf("v%s\n", verString); #endif } From 0b3255e463f45d58c555481482567f45c753451a Mon Sep 17 00:00:00 2001 From: Steffen Gaisser Date: Mon, 28 Mar 2022 15:17:59 +0200 Subject: [PATCH 08/52] Fixed tests --- tests/src/fsfw_tests/unit/osal/TestClock.cpp | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/tests/src/fsfw_tests/unit/osal/TestClock.cpp b/tests/src/fsfw_tests/unit/osal/TestClock.cpp index f7c63cce..38ec3915 100644 --- a/tests/src/fsfw_tests/unit/osal/TestClock.cpp +++ b/tests/src/fsfw_tests/unit/osal/TestClock.cpp @@ -51,20 +51,14 @@ TEST_CASE("OSAL::Clock Test", "[OSAL::Clock Test]") { REQUIRE(result == HasReturnvaluesIF::RETURN_OK); double timeAsUsecDouble = static_cast(timeAsUsec) / 1000000.0; timeval timeAsUsecTimeval = timevalOperations::toTimeval(timeAsUsecDouble); - double difference = timevalOperations::toDouble(timeAsTimeval - timeAsUsecTimeval); + double difference = timevalOperations::toDouble(timeAsUsecTimeval - timeAsTimeval); // We accept 5 ms difference - CHECK(abs(difference) <= 0.005); + CHECK(difference >= 0.0); + CHECK(difference <= 0.005); uint64_t timevalAsUint64 = static_cast(timeAsTimeval.tv_sec) * 1000000ull + static_cast(timeAsTimeval.tv_usec); - if (timeAsUsec > timevalAsUint64) { - // This should not be the case but we can see some rounding issue sometimes - // This is the case if used in valgrind. This might indicate an other issue - CHECK((timeAsUsec - timevalAsUint64) >= 0); - CHECK((timeAsUsec - timevalAsUint64) <= (5 * 1000)); - } else { - CHECK((timevalAsUint64 - timeAsUsec) >= 0); - CHECK((timevalAsUint64 - timeAsUsec) <= (5 * 1000)); - } + CHECK((timeAsUsec - timevalAsUint64) >= 0); + CHECK((timeAsUsec - timevalAsUint64) <= (5 * 1000)); } SECTION("Test j2000") { double j2000; From e6e71436c280bcf688cfdffde1b0971955fea20d Mon Sep 17 00:00:00 2001 From: Steffen Gaisser Date: Mon, 28 Mar 2022 18:32:51 +0200 Subject: [PATCH 09/52] Added more tests --- .../unit/timemanager/TestCCSDSTime.cpp | 57 ++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/tests/src/fsfw_tests/unit/timemanager/TestCCSDSTime.cpp b/tests/src/fsfw_tests/unit/timemanager/TestCCSDSTime.cpp index 6970b193..ce54d2f1 100644 --- a/tests/src/fsfw_tests/unit/timemanager/TestCCSDSTime.cpp +++ b/tests/src/fsfw_tests/unit/timemanager/TestCCSDSTime.cpp @@ -81,7 +81,8 @@ TEST_CASE("CCSDSTime Tests", "[TestCCSDSTime]") { std::string timeAscii = "2022-12-31T23:59:59.123Z"; Clock::TimeOfDay_t timeTo; const uint8_t* timeChar = reinterpret_cast(timeAscii.c_str()); - CCSDSTime::convertFromASCII(&timeTo, timeChar, timeAscii.length()); + auto result = CCSDSTime::convertFromASCII(&timeTo, timeChar, timeAscii.length()); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); REQUIRE(timeTo.year == 2022); REQUIRE(timeTo.month == 12); REQUIRE(timeTo.day == 31); @@ -89,6 +90,19 @@ TEST_CASE("CCSDSTime Tests", "[TestCCSDSTime]") { REQUIRE(timeTo.minute == 59); REQUIRE(timeTo.second == 59); REQUIRE(timeTo.usecond == Catch::Approx(123000)); + + std::string timeAscii2 = "2022-365T23:59:59.123Z"; + const uint8_t* timeChar2 = reinterpret_cast(timeAscii2.c_str()); + Clock::TimeOfDay_t timeTo2; + result = CCSDSTime::convertFromCcsds(&timeTo2, timeChar2, timeAscii2.length()); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(timeTo2.year == 2022); + REQUIRE(timeTo2.month == 12); + REQUIRE(timeTo2.day == 31); + REQUIRE(timeTo2.hour == 23); + REQUIRE(timeTo2.minute == 59); + REQUIRE(timeTo2.second == 59); + REQUIRE(timeTo2.usecond == Catch::Approx(123000)); } SECTION("CDS Conversions") { @@ -119,6 +133,7 @@ TEST_CASE("CCSDSTime Tests", "[TestCCSDSTime]") { CHECK(cdsTime.msDay_h == 0xE0); CHECK(cdsTime.msDay_l == 0xC5); CHECK(cdsTime.msDay_ll == 0xC3); + CHECK(cdsTime.pField == CCSDSTime::P_FIELD_CDS_SHORT); // Conversion back to timeval timeval timeReturnAsTimeval; @@ -140,5 +155,45 @@ TEST_CASE("CCSDSTime Tests", "[TestCCSDSTime]") { CHECK(timeReturnAsTimeOfDay.second == 45); // micro seconds precision is lost CHECK(timeReturnAsTimeOfDay.usecond == 123000); + + Clock::TimeOfDay_t timeReturnAsTodFromBuffer; + const uint8_t* buffer = reinterpret_cast(&cdsTime); + result = CCSDSTime::convertFromCDS(&timeReturnAsTodFromBuffer, buffer, sizeof(cdsTime)); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + CHECK(timeReturnAsTodFromBuffer.year == time.year); + CHECK(timeReturnAsTodFromBuffer.month == time.month); + CHECK(timeReturnAsTodFromBuffer.day == time.day); + CHECK(timeReturnAsTodFromBuffer.hour == time.hour); + CHECK(timeReturnAsTodFromBuffer.minute == time.minute); + CHECK(timeReturnAsTodFromBuffer.second == time.second); + CHECK(timeReturnAsTodFromBuffer.usecond == 123000); + + + Clock::TimeOfDay_t todFromCCSDS; + result = CCSDSTime::convertFromCcsds(&todFromCCSDS, buffer, sizeof(cdsTime)); + CHECK(result == HasReturnvaluesIF::RETURN_OK); + CHECK(todFromCCSDS.year == time.year); + CHECK(todFromCCSDS.month == time.month); + CHECK(todFromCCSDS.day == time.day); + CHECK(todFromCCSDS.hour == time.hour); + CHECK(todFromCCSDS.minute == time.minute); + CHECK(todFromCCSDS.second == time.second); + CHECK(todFromCCSDS.usecond == 123000); + } + SECTION("CCSDS Failures"){ + Clock::TimeOfDay_t time; + time.year = 2020; + time.month = 12; + time.day = 32; + time.hour = 13; + time.minute = 24; + time.second = 45; + time.usecond = 123456; + CCSDSTime::Ccs_mseconds to; + auto result = CCSDSTime::convertToCcsds(&to, &time); + REQUIRE(result == CCSDSTime::INVALID_TIME_FORMAT); + CCSDSTime::Ccs_seconds to2; + result = CCSDSTime::convertToCcsds(&to2, &time); + REQUIRE(result == CCSDSTime::INVALID_TIME_FORMAT); } } \ No newline at end of file From b4effe7a46fcb64647846a42509516f1f5eb8043 Mon Sep 17 00:00:00 2001 From: Steffen Gaisser Date: Mon, 28 Mar 2022 18:33:24 +0200 Subject: [PATCH 10/52] Clang format --- tests/src/fsfw_tests/unit/timemanager/TestCCSDSTime.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/src/fsfw_tests/unit/timemanager/TestCCSDSTime.cpp b/tests/src/fsfw_tests/unit/timemanager/TestCCSDSTime.cpp index ce54d2f1..a43ff8ab 100644 --- a/tests/src/fsfw_tests/unit/timemanager/TestCCSDSTime.cpp +++ b/tests/src/fsfw_tests/unit/timemanager/TestCCSDSTime.cpp @@ -168,7 +168,6 @@ TEST_CASE("CCSDSTime Tests", "[TestCCSDSTime]") { CHECK(timeReturnAsTodFromBuffer.second == time.second); CHECK(timeReturnAsTodFromBuffer.usecond == 123000); - Clock::TimeOfDay_t todFromCCSDS; result = CCSDSTime::convertFromCcsds(&todFromCCSDS, buffer, sizeof(cdsTime)); CHECK(result == HasReturnvaluesIF::RETURN_OK); @@ -180,7 +179,7 @@ TEST_CASE("CCSDSTime Tests", "[TestCCSDSTime]") { CHECK(todFromCCSDS.second == time.second); CHECK(todFromCCSDS.usecond == 123000); } - SECTION("CCSDS Failures"){ + SECTION("CCSDS Failures") { Clock::TimeOfDay_t time; time.year = 2020; time.month = 12; From 2800d6f28c6c3f5b890746f28279ff0ec1c94ab5 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 28 Mar 2022 20:16:11 +0200 Subject: [PATCH 11/52] add ETL dependency --- CMakeLists.txt | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9786d572..137d6cb9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -88,6 +88,26 @@ if(FSFW_BUILD_UNITTESTS) endif() endif() +message(STATUS "Finding and/or providing ETL library") +# Check whether the user has already installed Catch2 first +find_package(etl QUIET) +# Not installed, so use FetchContent to download and provide etl +if(NOT etl_FOUND) + message(STATUS + "No ETL installation was found with find_package. Installing and providing " + "etl with FindPackage" + ) + include(FetchContent) + + FetchContent_Declare( + etl + GIT_REPOSITORY https://github.com/ETLCPP/etl + GIT_TAG 20.26.0 + ) + + FetchContent_MakeAvailable(etl) +endif() + set(FSFW_CORE_INC_PATH "inc") set_property(CACHE FSFW_OSAL PROPERTY STRINGS host linux rtems freertos) From 082c86ea181c42f52200cd5d3ae2b73b7cb48e24 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 28 Mar 2022 20:18:49 +0200 Subject: [PATCH 12/52] link ETL lib as well --- CMakeLists.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 137d6cb9..282cf564 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,7 @@ set(FSFW_REVISION 0) # Add the cmake folder so the FindSphinx module is found set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) +set(FSFW_ETL_LIB_NAME etl) option(FSFW_GENERATE_SECTIONS "Generate function and data sections. Required to remove unused code" ON @@ -90,9 +91,9 @@ endif() message(STATUS "Finding and/or providing ETL library") # Check whether the user has already installed Catch2 first -find_package(etl QUIET) +find_package(${FSFW_ETL_LIB_NAME} QUIET) # Not installed, so use FetchContent to download and provide etl -if(NOT etl_FOUND) +if(NOT ${FSFW_ETL_LIB_NAME}_FOUND) message(STATUS "No ETL installation was found with find_package. Installing and providing " "etl with FindPackage" @@ -100,7 +101,7 @@ if(NOT etl_FOUND) include(FetchContent) FetchContent_Declare( - etl + ${FSFW_ETL_LIB_NAME} GIT_REPOSITORY https://github.com/ETLCPP/etl GIT_TAG 20.26.0 ) @@ -369,6 +370,7 @@ target_compile_options(${LIB_FSFW_NAME} PRIVATE ) target_link_libraries(${LIB_FSFW_NAME} PRIVATE + ${FSFW_ETL_LIB_NAME} ${FSFW_ADDITIONAL_LINK_LIBS} ) From 8ff9eadf308b3507529fcc8f37b41c4fecee3637 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 28 Mar 2022 20:43:36 +0200 Subject: [PATCH 13/52] update changelog, add basic instructions for etl --- CHANGELOG.md | 2 ++ CMakeLists.txt | 3 ++- README.md | 26 ++++++++++++++++++++++++-- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3eb6942..c7b510f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Dedicated Version class and constant `fsfw::FSFW_VERSION` containing version information inside `fsfw/version.h` PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/559 +- Added ETL dependency + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/592 # [v4.0.0] diff --git a/CMakeLists.txt b/CMakeLists.txt index 282cf564..a0fe9859 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,7 @@ set(FSFW_REVISION 0) # Add the cmake folder so the FindSphinx module is found set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) +set(FSFW_ETL_LIB_VERSION 20.26.0) set(FSFW_ETL_LIB_NAME etl) option(FSFW_GENERATE_SECTIONS @@ -103,7 +104,7 @@ if(NOT ${FSFW_ETL_LIB_NAME}_FOUND) FetchContent_Declare( ${FSFW_ETL_LIB_NAME} GIT_REPOSITORY https://github.com/ETLCPP/etl - GIT_TAG 20.26.0 + GIT_TAG ${FSFW_ETL_LIB_VERSION} ) FetchContent_MakeAvailable(etl) diff --git a/README.md b/README.md index dff87b2e..c8a6c874 100644 --- a/README.md +++ b/README.md @@ -11,9 +11,15 @@ with Airbus Defence and Space GmbH. ## Quick facts -The framework is designed for systems, which communicate with external devices, perform control loops, receive telecommands and send telemetry, and need to maintain a high level of availability. Therefore, a mode and health system provides control over the states of the software and the controlled devices. In addition, a simple mechanism of event based fault detection, isolation and recovery is implemented as well. +The framework is designed for systems, which communicate with external devices, perform control loops, +receive telecommands and send telemetry, and need to maintain a high level of availability. Therefore, +a mode and health system provides control over the states of the software and the controlled devices. +In addition, a simple mechanism of event based fault detection, isolation and recovery is implemented as well. -The FSFW provides abstraction layers for operating systems to provide a uniform operating system abstraction layer (OSAL). Some components of this OSAL are required internally by the FSFW but is also very useful for developers to implement the same application logic on different operating systems with a uniform interface. +The FSFW provides abstraction layers for operating systems to provide a uniform operating system +abstraction layer (OSAL). Some components of this OSAL are required internally by the FSFW but is +also very useful for developers to implement the same application logic on different operating +systems with a uniform interface. Currently, the FSFW provides the following OSALs: @@ -45,6 +51,22 @@ A template configuration folder was provided and can be copied into the project a starting point. The [configuration section](docs/README-config.md#top) provides more specific information about the possible options. +## Prerequisites + +The Embedded Template Library (etl) is a dependency of the FSFW which is automatically +installed and provided by the build system unless the correction version was installed. + +You can install the ETL library like this: + +```cpp +git clone https://github.com/ETLCPP/etl +cd etl +git checkout +mkdir build && cd build +cmake .. +cmake --install . +``` + ## Adding the library The following steps show how to add and use FSFW components. It is still recommended to From 05495077ecf0c202ec95f47b9a58e966236bcb5b Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 28 Mar 2022 20:53:39 +0200 Subject: [PATCH 14/52] doc update --- CMakeLists.txt | 10 ++++++++-- README.md | 20 ++++++++++++++++++++ docs/getting_started.rst | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a0fe9859..b2d6714c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,13 @@ set(FSFW_REVISION 0) # Add the cmake folder so the FindSphinx module is found set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) -set(FSFW_ETL_LIB_VERSION 20.26.0) + +set(FSFW_ETL_LIB_MAJOR_VERSION 20) +set(FSFW_ETL_LIB_VERSION ${FSFW_ETL_LIB_MAJOR_VERSION}.26.0) + +set(FSFW_CATCH2_LIB_MAJOR_VERSION 3) +set(FSFW_CATCH2_LIB_VERSION v${FSFW_CATCH2_LIB_MAJOR_VERSION}.0.0-preview4) + set(FSFW_ETL_LIB_NAME etl) option(FSFW_GENERATE_SECTIONS @@ -58,7 +64,7 @@ if(FSFW_BUILD_UNITTESTS) FetchContent_Declare( Catch2 GIT_REPOSITORY https://github.com/catchorg/Catch2.git - GIT_TAG v3.0.0-preview4 + GIT_TAG ${FSFW_CATCH2_LIB_VERSION} ) FetchContent_MakeAvailable(Catch2) diff --git a/README.md b/README.md index c8a6c874..51d78b25 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,8 @@ information about the possible options. The Embedded Template Library (etl) is a dependency of the FSFW which is automatically installed and provided by the build system unless the correction version was installed. +The current recommended version can be found inside the fsfw `CMakeLists.txt` file or by using +`ccmake` and looking up the `FSFW_ETL_LIB_VERSION` variable. You can install the ETL library like this: @@ -67,6 +69,11 @@ cmake .. cmake --install . ``` +Right now, the version provision feature by the ETL library has not been implemented +yet so `CMake` is unable to determine and check the major version of the ETL +library. You have to ensure that the ETL library has been installed with the +correct major version. + ## Adding the library The following steps show how to add and use FSFW components. It is still recommended to @@ -105,6 +112,19 @@ The FSFW also has unittests which use the [Catch2 library](https://github.com/ca These are built by setting the CMake option `FSFW_BUILD_UNITTESTS` to `ON` or `TRUE` from your project `CMakeLists.txt` file or from the command line. +You can install the Catch2 library, which prevents the build system to avoid re-downloading +the dependency if the unit tests are completely rebuilt. The current recommended version +can be found inside the fsfw `CMakeLists.txt` file or by using `ccmake` and looking up +the `FSFW_CATCH2_LIB_VERSION` variable. + +```sh +git clone https://github.com/catchorg/Catch2.git +cd Catch2 +git checkout +cmake -Bbuild -H. -DBUILD_TESTING=OFF +sudo cmake --build build/ --target install +``` + The fsfw-tests binary will be built as part of the static library and dropped alongside it. If the unittests are built, the library and the tests will be built with coverage information by default. This can be disabled by setting the `FSFW_TESTS_COV_GEN` option to `OFF` or `FALSE`. diff --git a/docs/getting_started.rst b/docs/getting_started.rst index 34547211..fb316a97 100644 --- a/docs/getting_started.rst +++ b/docs/getting_started.rst @@ -19,6 +19,30 @@ A template configuration folder was provided and can be copied into the project a starting point. The [configuration section](docs/README-config.md#top) provides more specific information about the possible options. +Prerequisites +------------------- + +The Embedded Template Library (etl) is a dependency of the FSFW which is automatically +installed and provided by the build system unless the correction version was installed. +The current recommended version can be found inside the fsfw ``CMakeLists.txt`` file or by using +``ccmake`` and looking up the ``FSFW_ETL_LIB_VERSION`` variable. + +You can install the ETL library like this: + +.. code-block:: console + + git clone https://github.com/ETLCPP/etl + cd etl + git checkout + mkdir build && cd build + cmake .. + cmake --install . + +Right now, the version provision feature by the ETL library has not been implemented +yet so ``CMake`` is unable to determine and check the major version of the ETL +library. You have to ensure that the ETL library has been installed with the +correct major version. + Adding the library ------------------- @@ -60,6 +84,20 @@ The FSFW also has unittests which use the `Catch2 library`_. These are built by setting the CMake option ``FSFW_BUILD_UNITTESTS`` to ``ON`` or `TRUE` from your project `CMakeLists.txt` file or from the command line. +You can install the Catch2 library, which prevents the build system to avoid re-downloading +the dependency if the unit tests are completely rebuilt. The current recommended version +can be found inside the fsfw ``CMakeLists.txt`` file or by using ``ccmake`` and looking up +the ``FSFW_CATCH2_LIB_VERSION`` variable. + +.. code-block:: console + + git clone https://github.com/catchorg/Catch2.git + cd Catch2 + git checkout + cmake -Bbuild -H. -DBUILD_TESTING=OFF + sudo cmake --build build/ --target install + + The fsfw-tests binary will be built as part of the static library and dropped alongside it. If the unittests are built, the library and the tests will be built with coverage information by default. This can be disabled by setting the `FSFW_TESTS_COV_GEN` option to `OFF` or `FALSE`. From 8dd0b2608d7e3c27bbd8eae80dad669a8bbf8f08 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 28 Mar 2022 20:55:34 +0200 Subject: [PATCH 15/52] cache version variables --- CMakeLists.txt | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b2d6714c..903133a1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,11 +7,19 @@ set(FSFW_REVISION 0) # Add the cmake folder so the FindSphinx module is found set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) -set(FSFW_ETL_LIB_MAJOR_VERSION 20) -set(FSFW_ETL_LIB_VERSION ${FSFW_ETL_LIB_MAJOR_VERSION}.26.0) +set(FSFW_ETL_LIB_MAJOR_VERSION 20 CACHE + "ETL library major version requirement" +) +set(FSFW_ETL_LIB_VERSION ${FSFW_ETL_LIB_MAJOR_VERSION}.26.0 CACHE + "ETL library exact version requirement" +) -set(FSFW_CATCH2_LIB_MAJOR_VERSION 3) -set(FSFW_CATCH2_LIB_VERSION v${FSFW_CATCH2_LIB_MAJOR_VERSION}.0.0-preview4) +set(FSFW_CATCH2_LIB_MAJOR_VERSION 3 CACHE + "Catch2 library major version requirement" +) +set(FSFW_CATCH2_LIB_VERSION v${FSFW_CATCH2_LIB_MAJOR_VERSION}.0.0-preview4 CACHE + "Catch2 library exact version requirement" +) set(FSFW_ETL_LIB_NAME etl) From c2a89bf709ccdd022399ecd6b6a68da209a481ac Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 28 Mar 2022 20:57:13 +0200 Subject: [PATCH 16/52] bugfix --- CMakeLists.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 903133a1..82466481 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,17 +7,17 @@ set(FSFW_REVISION 0) # Add the cmake folder so the FindSphinx module is found set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) -set(FSFW_ETL_LIB_MAJOR_VERSION 20 CACHE +set(FSFW_ETL_LIB_MAJOR_VERSION 20 CACHE STRING "ETL library major version requirement" ) -set(FSFW_ETL_LIB_VERSION ${FSFW_ETL_LIB_MAJOR_VERSION}.26.0 CACHE +set(FSFW_ETL_LIB_VERSION ${FSFW_ETL_LIB_MAJOR_VERSION}.26.0 CACHE STRING "ETL library exact version requirement" ) -set(FSFW_CATCH2_LIB_MAJOR_VERSION 3 CACHE +set(FSFW_CATCH2_LIB_MAJOR_VERSION 3 CACHE STRING "Catch2 library major version requirement" ) -set(FSFW_CATCH2_LIB_VERSION v${FSFW_CATCH2_LIB_MAJOR_VERSION}.0.0-preview4 CACHE +set(FSFW_CATCH2_LIB_VERSION v${FSFW_CATCH2_LIB_MAJOR_VERSION}.0.0-preview4 CACHE STRING "Catch2 library exact version requirement" ) From 5525466b5247c949770406f1f2deac850497e760 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 28 Mar 2022 20:57:30 +0200 Subject: [PATCH 17/52] update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c7b510f2..39c52139 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,7 +37,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Dedicated Version class and constant `fsfw::FSFW_VERSION` containing version information inside `fsfw/version.h` PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/559 -- Added ETL dependency +- Added ETL dependency and improved library dependency management PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/592 # [v4.0.0] From d07e0e55765d2b1f9e9cb48b19cb5d6da87b63bf Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 28 Mar 2022 21:01:26 +0200 Subject: [PATCH 18/52] trying something --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 82466481..54db77ce 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,7 +64,7 @@ add_library(${LIB_FSFW_NAME}) if(FSFW_BUILD_UNITTESTS) message(STATUS "Building the FSFW unittests in addition to the static library") # Check whether the user has already installed Catch2 first - find_package(Catch2 3) + find_package(Catch2 ${FSFW_CATCH2_LIB_MAJOR_VERSION}) # Not installed, so use FetchContent to download and provide Catch2 if(NOT Catch2_FOUND) include(FetchContent) @@ -106,7 +106,7 @@ endif() message(STATUS "Finding and/or providing ETL library") # Check whether the user has already installed Catch2 first -find_package(${FSFW_ETL_LIB_NAME} QUIET) +find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} QUIET) # Not installed, so use FetchContent to download and provide etl if(NOT ${FSFW_ETL_LIB_NAME}_FOUND) message(STATUS From 8037e8074b544ab1587fc355adda20ad09dcd36f Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 28 Mar 2022 21:03:18 +0200 Subject: [PATCH 19/52] more docs --- CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 54db77ce..9d9c4f70 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -106,7 +106,10 @@ endif() message(STATUS "Finding and/or providing ETL library") # Check whether the user has already installed Catch2 first -find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} QUIET) +# I think the version provisioning feature of CMake has not been implemented for the ETL library +# yet. Therefore we can not specify any (not even the major) version here and we have to rely +# on the user having installed the correct version for now +find_package(${FSFW_ETL_LIB_NAME} QUIET) # Not installed, so use FetchContent to download and provide etl if(NOT ${FSFW_ETL_LIB_NAME}_FOUND) message(STATUS From 1a530633ca5deef06f9eb7ffb2e008ad59051ec5 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 28 Mar 2022 21:10:51 +0200 Subject: [PATCH 20/52] small fix --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9d9c4f70..fc797084 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -105,7 +105,7 @@ if(FSFW_BUILD_UNITTESTS) endif() message(STATUS "Finding and/or providing ETL library") -# Check whether the user has already installed Catch2 first +# Check whether the user has already installed ETL first # I think the version provisioning feature of CMake has not been implemented for the ETL library # yet. Therefore we can not specify any (not even the major) version here and we have to rely # on the user having installed the correct version for now From 6c1db8473bdd7639065e230341d52007c58ecf49 Mon Sep 17 00:00:00 2001 From: Jakob Meier Date: Thu, 31 Mar 2022 14:36:45 +0200 Subject: [PATCH 21/52] get alternative reply from device command info --- src/fsfw/devicehandlers/DeviceHandlerBase.cpp | 31 ++++++++++++++----- src/fsfw/devicehandlers/DeviceHandlerBase.h | 6 +++- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp index 08a15d5f..0e2802ac 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp @@ -410,7 +410,7 @@ ReturnValue_t DeviceHandlerBase::insertInCommandAndReplyMap( DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles, LocalPoolDataSetBase* replyDataSet, size_t replyLen, bool periodic, bool hasDifferentReplyId, DeviceCommandId_t replyId) { // No need to check, as we may try to insert multiple times. - insertInCommandMap(deviceCommand); + insertInCommandMap(deviceCommand, hasDifferentReplyId, replyId); if (hasDifferentReplyId) { return insertInReplyMap(replyId, maxDelayCycles, replyDataSet, replyLen, periodic); } else { @@ -437,11 +437,15 @@ ReturnValue_t DeviceHandlerBase::insertInReplyMap(DeviceCommandId_t replyId, } } -ReturnValue_t DeviceHandlerBase::insertInCommandMap(DeviceCommandId_t deviceCommand) { +ReturnValue_t DeviceHandlerBase::insertInCommandMap(DeviceCommandId_t deviceCommand, + bool useAlternativeReply, + DeviceCommandId_t alternativeReplyId) { DeviceCommandInfo info; info.expectedReplies = 0; info.isExecuting = false; info.sendReplyTo = NO_COMMANDER; + info.useAlternativeReplyId = alternativeReplyId; + info.alternativeReplyId = alternativeReplyId; auto resultPair = deviceCommandMap.emplace(deviceCommand, info); if (resultPair.second) { return RETURN_OK; @@ -451,12 +455,21 @@ ReturnValue_t DeviceHandlerBase::insertInCommandMap(DeviceCommandId_t deviceComm } size_t DeviceHandlerBase::getNextReplyLength(DeviceCommandId_t commandId) { - DeviceReplyIter iter = deviceReplyMap.find(commandId); - if (iter != deviceReplyMap.end()) { - return iter->second.replyLen; - } else { - return 0; + DeviceCommandId_t replyId = NO_COMMAND_ID; + DeviceCommandMap::iterator command = cookieInfo.pendingCommand; + if (command->second.useAlternativeReplyId) { + replyId = command->second.alternativeReplyId; } + else { + replyId = commandId; + } + DeviceReplyIter iter = deviceReplyMap.find(replyId); + if (iter != deviceReplyMap.end()) { + if (iter->second.delayCycles != 0) { + return iter->second.replyLen; + } + } + return 0; } ReturnValue_t DeviceHandlerBase::updateReplyMapEntry(DeviceCommandId_t deviceReply, @@ -651,7 +664,9 @@ void DeviceHandlerBase::doGetWrite() { // We need to distinguish here, because a raw command never expects a reply. //(Could be done in eRIRM, but then child implementations need to be careful. - result = enableReplyInReplyMap(cookieInfo.pendingCommand); + DeviceCommandMap::iterator command = cookieInfo.pendingCommand; + result = enableReplyInReplyMap(command, 1, command->second.useAlternativeReplyId, + command->second.alternativeReplyId); } else { // always generate a failure event, so that FDIR knows what's up triggerEvent(DEVICE_SENDING_COMMAND_FAILED, result, cookieInfo.pendingCommand->first); diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.h b/src/fsfw/devicehandlers/DeviceHandlerBase.h index c8b8b86d..5e974831 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerBase.h +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.h @@ -478,7 +478,9 @@ class DeviceHandlerBase : public DeviceHandlerIF, * @return - @c RETURN_OK when the command was successfully inserted, * - @c RETURN_FAILED else. */ - ReturnValue_t insertInCommandMap(DeviceCommandId_t deviceCommand); + ReturnValue_t insertInCommandMap(DeviceCommandId_t deviceCommand, + bool useAlternativeReply = false, + DeviceCommandId_t alternativeReplyId = 0); /** * Enables a periodic reply for a given command. It sets to delay cycles to the specified @@ -751,6 +753,8 @@ class DeviceHandlerBase : public DeviceHandlerIF, //! if this is != NO_COMMANDER, DHB was commanded externally and shall //! report everything to commander. MessageQueueId_t sendReplyTo; + bool useAlternativeReplyId; + DeviceCommandId_t alternativeReplyId; }; using DeviceCommandMap = std::map; /** From 17771c0497857dc8f968b8a047bb7dcbf45509e3 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 11 Apr 2022 13:57:18 +0200 Subject: [PATCH 22/52] progagate reply returnvalue --- src/fsfw/datapoollocal/LocalDataPoolManager.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/fsfw/datapoollocal/LocalDataPoolManager.cpp b/src/fsfw/datapoollocal/LocalDataPoolManager.cpp index acfa23c5..fe9ed3a4 100644 --- a/src/fsfw/datapoollocal/LocalDataPoolManager.cpp +++ b/src/fsfw/datapoollocal/LocalDataPoolManager.cpp @@ -801,8 +801,7 @@ ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid, bool i HousekeepingMessage::setHkStuctureReportReply(&reply, sid, storeId); } - hkQueue->reply(&reply); - return result; + return hkQueue->reply(&reply); } void LocalDataPoolManager::clearReceiversList() { From acc4c8d975bb05c704ad94613ea10782f707d106 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 11 Apr 2022 14:33:28 +0200 Subject: [PATCH 23/52] check serialize result as well --- src/fsfw/datapoollocal/LocalDataPoolManager.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/fsfw/datapoollocal/LocalDataPoolManager.cpp b/src/fsfw/datapoollocal/LocalDataPoolManager.cpp index fe9ed3a4..0c255571 100644 --- a/src/fsfw/datapoollocal/LocalDataPoolManager.cpp +++ b/src/fsfw/datapoollocal/LocalDataPoolManager.cpp @@ -787,6 +787,10 @@ ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid, bool i // Serialize set packet into store. size_t size = 0; result = setPacket.serialize(&storePtr, &size, expectedSize, SerializeIF::Endianness::BIG); + if(result != HasReturnvaluesIF::RETURN_OK) { + ipcStore->deleteData(storeId); + return result; + } if (expectedSize != size) { printWarningOrError(sif::OutputTypes::OUT_WARNING, "generateSetStructurePacket", HasReturnvaluesIF::RETURN_FAILED, From 7761b66fe240b604a3fc4f3f6283ac5bbfe39c9f Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 11 Apr 2022 14:35:16 +0200 Subject: [PATCH 24/52] delete data from ipc store if reply fails --- src/fsfw/datapoollocal/LocalDataPoolManager.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/fsfw/datapoollocal/LocalDataPoolManager.cpp b/src/fsfw/datapoollocal/LocalDataPoolManager.cpp index 0c255571..6053bd43 100644 --- a/src/fsfw/datapoollocal/LocalDataPoolManager.cpp +++ b/src/fsfw/datapoollocal/LocalDataPoolManager.cpp @@ -805,7 +805,11 @@ ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid, bool i HousekeepingMessage::setHkStuctureReportReply(&reply, sid, storeId); } - return hkQueue->reply(&reply); + result = hkQueue->reply(&reply); + if(result != HasReturnvaluesIF::RETURN_OK) { + ipcStore->deleteData(storeId); + } + return result; } void LocalDataPoolManager::clearReceiversList() { From d1151ca707557598d5609c82497436047787dc5d Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 11 Apr 2022 16:13:47 +0200 Subject: [PATCH 25/52] changelog update --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3eb6942..01d60987 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - `oneShotAction` flag in the `TestTask` class is not static anymore - HAL Linux Uart: Baudrate and bits per word are enums now, avoiding misconfigurations PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/585 +- IPC Message Queue Handling: Allow passing an optional `MqArgs` argument into the MessageQueue + creation call. It allows passing context information and an arbitrary user argument into + the message queue. Also streamlined and simplified `MessageQueue` implementation for all OSALs + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/583 ## Removed From 4f0669c57407af9d1cbf4bc14e28922be3a38c90 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 11 Apr 2022 16:44:20 +0200 Subject: [PATCH 26/52] doc update --- CMakeLists.txt | 8 +++----- README.md | 11 +++++------ docs/getting_started.rst | 11 +++++------ 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 51d40f48..d8ca812e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) set(FSFW_ETL_LIB_MAJOR_VERSION 20 CACHE STRING "ETL library major version requirement" ) -set(FSFW_ETL_LIB_VERSION ${FSFW_ETL_LIB_MAJOR_VERSION}.26.0 CACHE STRING +set(FSFW_ETL_LIB_VERSION ${FSFW_ETL_LIB_MAJOR_VERSION}.27.2 CACHE STRING "ETL library exact version requirement" ) @@ -106,11 +106,9 @@ if(FSFW_BUILD_UNITTESTS) endif() message(STATUS "Finding and/or providing ETL library") + # Check whether the user has already installed ETL first -# I think the version provisioning feature of CMake has not been implemented for the ETL library -# yet. Therefore we can not specify any (not even the major) version here and we have to rely -# on the user having installed the correct version for now -find_package(${FSFW_ETL_LIB_NAME} QUIET) +find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} QUIET) # Not installed, so use FetchContent to download and provide etl if(NOT ${FSFW_ETL_LIB_NAME}_FOUND) message(STATUS diff --git a/README.md b/README.md index 51d78b25..99c842af 100644 --- a/README.md +++ b/README.md @@ -56,9 +56,10 @@ information about the possible options. The Embedded Template Library (etl) is a dependency of the FSFW which is automatically installed and provided by the build system unless the correction version was installed. The current recommended version can be found inside the fsfw `CMakeLists.txt` file or by using -`ccmake` and looking up the `FSFW_ETL_LIB_VERSION` variable. +`ccmake` and looking up the `FSFW_ETL_LIB_MAJOR_VERSION` variable. -You can install the ETL library like this: +You can install the ETL library like this. On Linux, it might be necessary to add `sudo` before +the install call: ```cpp git clone https://github.com/ETLCPP/etl @@ -69,10 +70,8 @@ cmake .. cmake --install . ``` -Right now, the version provision feature by the ETL library has not been implemented -yet so `CMake` is unable to determine and check the major version of the ETL -library. You have to ensure that the ETL library has been installed with the -correct major version. +It is recommended to install `20.27.2` or newer for the package version handling of +ETL to work. ## Adding the library diff --git a/docs/getting_started.rst b/docs/getting_started.rst index fb316a97..01724b3a 100644 --- a/docs/getting_started.rst +++ b/docs/getting_started.rst @@ -25,9 +25,10 @@ Prerequisites The Embedded Template Library (etl) is a dependency of the FSFW which is automatically installed and provided by the build system unless the correction version was installed. The current recommended version can be found inside the fsfw ``CMakeLists.txt`` file or by using -``ccmake`` and looking up the ``FSFW_ETL_LIB_VERSION`` variable. +``ccmake`` and looking up the ``FSFW_ETL_LIB_MAJOR_VERSION`` variable. -You can install the ETL library like this: +You can install the ETL library like this. On Linux, it might be necessary to add ``sudo`` before +the install call: .. code-block:: console @@ -38,10 +39,8 @@ You can install the ETL library like this: cmake .. cmake --install . -Right now, the version provision feature by the ETL library has not been implemented -yet so ``CMake`` is unable to determine and check the major version of the ETL -library. You have to ensure that the ETL library has been installed with the -correct major version. +It is recommended to install ``20.27.2`` or newer for the package version handling of +ETL to work. Adding the library ------------------- From 6aa54fe1d4bd4bc3121ea91a442a9fa4c5d98f7a Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 11 Apr 2022 17:30:27 +0200 Subject: [PATCH 27/52] added missing empty implementation --- CHANGELOG.md | 5 +++++ hal/src/fsfw_hal/stm32h7/spi/mspInit.h | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3eb6942..8f3a3a1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/). inside `fsfw/version.h` PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/559 +## Fixed + +- Small bugfix in STM32 HAL for SPI + PR: + # [v4.0.0] ## Additions diff --git a/hal/src/fsfw_hal/stm32h7/spi/mspInit.h b/hal/src/fsfw_hal/stm32h7/spi/mspInit.h index 00c68017..f0658fb9 100644 --- a/hal/src/fsfw_hal/stm32h7/spi/mspInit.h +++ b/hal/src/fsfw_hal/stm32h7/spi/mspInit.h @@ -21,7 +21,7 @@ using mspCb = void (*)(void); namespace spi { struct MspCfgBase { - MspCfgBase(); + MspCfgBase() {} MspCfgBase(stm32h7::GpioCfg sck, stm32h7::GpioCfg mosi, stm32h7::GpioCfg miso, mspCb cleanupCb = nullptr, mspCb setupCb = nullptr) : sck(sck), mosi(mosi), miso(miso), cleanupCb(cleanupCb), setupCb(setupCb) {} From 7c2e50b665f515d6234f3d2f070609f8f37efde2 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 11 Apr 2022 17:32:01 +0200 Subject: [PATCH 28/52] added related PR in changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f3a3a1b..85f6ef28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,7 +41,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## Fixed - Small bugfix in STM32 HAL for SPI - PR: + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/599 # [v4.0.0] From 085213c60f0f86dd7e28769767a0d235ed333336 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 21 Apr 2022 10:30:46 +0200 Subject: [PATCH 29/52] add nullptr check --- hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp b/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp index 52b6dc07..278f6f4b 100644 --- a/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp +++ b/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp @@ -375,13 +375,16 @@ float MgmLIS3MDLHandler::getSensitivityFactor(MGMLIS3MDL::Sensitivies sens) { ReturnValue_t MgmLIS3MDLHandler::enableTemperatureSensor(const uint8_t *commandData, size_t commandDataLen) { + if(commandData == nullptr) { + return INVALID_COMMAND_PARAMETER; + } triggerEvent(CHANGE_OF_SETUP_PARAMETER); uint32_t size = 2; commandBuffer[0] = writeCommand(MGMLIS3MDL::CTRL_REG1); if (commandDataLen > 1) { return INVALID_NUMBER_OR_LENGTH_OF_PARAMETERS; } - switch (*commandData) { + switch (commandData[0]) { case (MGMLIS3MDL::ON): { commandBuffer[1] = registers[0] | (1 << 7); break; From 8c6c8ad3c0c8ff652f8c20893219d826f80698d9 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 22 Apr 2022 11:58:44 +0200 Subject: [PATCH 30/52] exntend version class to allow add info --- src/fsfw/version.cpp | 24 ++++++++++++++++++------ src/fsfw/version.h | 16 ++++++++-------- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/fsfw/version.cpp b/src/fsfw/version.cpp index 926e465f..a7f1d6a1 100644 --- a/src/fsfw/version.cpp +++ b/src/fsfw/version.cpp @@ -11,12 +11,24 @@ #undef minor #endif -const fsfw::Version fsfw::FSFW_VERSION = {FSFW_VERSION_MAJOR, FSFW_VERSION_MINOR, - FSFW_VERSION_REVISION}; +const Version fsfw::FSFW_VERSION = {FSFW_VERSION_MAJOR, FSFW_VERSION_MINOR, FSFW_VERSION_REVISION}; -fsfw::Version::Version(uint32_t major, uint32_t minor, uint32_t revision) - : major(major), minor(minor), revision(revision) {} +Version::Version(uint32_t major, uint32_t minor, uint32_t revision, const char* addInfo) + : major(major), minor(minor), revision(revision), addInfo(addInfo) {} -void fsfw::Version::getVersion(char* str, size_t maxLen) const { - snprintf(str, maxLen, "%d.%d.%d", major, minor, revision); +void Version::getVersion(char* str, size_t maxLen) const { + size_t len = snprintf(str, maxLen, "%d.%d.%d", major, minor, revision); + if (addInfo != nullptr) { + snprintf(str + len, maxLen - len, "-%s", addInfo); + } } + +#if FSFW_CPP_OSTREAM_ENABLED == 1 +std::ostream& operator<<(std::ostream& os, const Version& v) { + os << v.major << "." << v.minor << "." << v.revision; + if (v.addInfo != nullptr) { + os << "-" << v.addInfo; + } + return os; +} +#endif diff --git a/src/fsfw/version.h b/src/fsfw/version.h index 7cddf193..d8497703 100644 --- a/src/fsfw/version.h +++ b/src/fsfw/version.h @@ -8,15 +8,16 @@ #endif #include -namespace fsfw { - class Version { public: - Version(uint32_t major, uint32_t minor, uint32_t revision); + Version(uint32_t major, uint32_t minor, uint32_t revision, const char* addInfo = nullptr); uint32_t major = 0; uint32_t minor = 0; uint32_t revision = 0; + // Additional information, e.g. a git SHA hash + const char* addInfo = nullptr; + friend bool operator==(const Version& v1, const Version& v2) { return (v1.major == v2.major and v1.minor == v2.minor and v1.revision == v2.revision); } @@ -43,10 +44,7 @@ class Version { * @param v * @return */ - friend std::ostream& operator<<(std::ostream& os, const Version& v) { - os << v.major << "." << v.minor << "." << v.revision; - return os; - } + friend std::ostream& operator<<(std::ostream& os, const Version& v); #endif /** @@ -57,7 +55,9 @@ class Version { void getVersion(char* str, size_t maxLen) const; }; -extern const fsfw::Version FSFW_VERSION; +namespace fsfw { + +extern const Version FSFW_VERSION; } // namespace fsfw From 07155e25464afe73ae3ae79b88913d4f0961f9c5 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 22 Apr 2022 14:04:18 +0200 Subject: [PATCH 31/52] extend version handling with git describe --- CMakeLists.txt | 22 +- cmake/GetGitRevisionDescription.cmake | 284 +++++++++++++++++++++++ cmake/GetGitRevisionDescription.cmake.in | 43 ++++ cmake/helpers.cmake | 28 +++ src/fsfw/FSFWVersion.h.in | 7 +- src/fsfw/version.cpp | 2 +- src/fsfw/version.h | 8 +- 7 files changed, 382 insertions(+), 12 deletions(-) create mode 100644 cmake/GetGitRevisionDescription.cmake create mode 100644 cmake/GetGitRevisionDescription.cmake.in create mode 100644 cmake/helpers.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 7ef11493..4f9ed91d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,9 +1,5 @@ cmake_minimum_required(VERSION 3.13) -set(FSFW_VERSION 4) -set(FSFW_SUBVERSION 0) -set(FSFW_REVISION 0) - # Add the cmake folder so the FindSphinx module is found set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) @@ -45,6 +41,24 @@ set(FSFW_DUMMY_TGT fsfw-dummy) project(${LIB_FSFW_NAME}) add_library(${LIB_FSFW_NAME}) +# Version handling +include("GetGitRevisionDescription") +determine_version_with_git("--exclude" "docker_*") +set(GIT_INFO ${GIT_INFO} CACHE STRING "Version information retrieved with git describe") +list(GET GIT_INFO 1 FSFW_VERSION) +list(GET GIT_INFO 2 FSFW_SUBVERSION) +list(GET GIT_INFO 3 FSFW_REVISION) +list(GET GIT_INFO 4 FSFW_VERSION_CST_GIT_SHA1) +if(NOT FSFW_VERSION) + set(FSFW_VERSION -1) +endif() +if(NOT FSFW_SUBVERSION) + set(FSFW_SUBVERSION -1) +endif() +if(NOT FSFW_REVISION) + set(FSFW_REVISION -1) +endif() + if(FSFW_BUILD_UNITTESTS) message(STATUS "Building the FSFW unittests in addition to the static library") # Check whether the user has already installed Catch2 first diff --git a/cmake/GetGitRevisionDescription.cmake b/cmake/GetGitRevisionDescription.cmake new file mode 100644 index 00000000..69ef78b2 --- /dev/null +++ b/cmake/GetGitRevisionDescription.cmake @@ -0,0 +1,284 @@ +# - Returns a version string from Git +# +# These functions force a re-configure on each git commit so that you can +# trust the values of the variables in your build system. +# +# get_git_head_revision( [ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR]) +# +# Returns the refspec and sha hash of the current head revision +# +# git_describe( [ ...]) +# +# Returns the results of git describe on the source tree, and adjusting +# the output so that it tests false if an error occurs. +# +# git_describe_working_tree( [ ...]) +# +# Returns the results of git describe on the working tree (--dirty option), +# and adjusting the output so that it tests false if an error occurs. +# +# git_get_exact_tag( [ ...]) +# +# Returns the results of git describe --exact-match on the source tree, +# and adjusting the output so that it tests false if there was no exact +# matching tag. +# +# git_local_changes() +# +# Returns either "CLEAN" or "DIRTY" with respect to uncommitted changes. +# Uses the return code of "git diff-index --quiet HEAD --". +# Does not regard untracked files. +# +# Requires CMake 2.6 or newer (uses the 'function' command) +# +# Original Author: +# 2009-2020 Ryan Pavlik +# http://academic.cleardefinition.com +# +# Copyright 2009-2013, Iowa State University. +# Copyright 2013-2020, Ryan Pavlik +# Copyright 2013-2020, Contributors +# SPDX-License-Identifier: BSL-1.0 +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +if(__get_git_revision_description) + return() +endif() +set(__get_git_revision_description YES) + +# We must run the following at "include" time, not at function call time, +# to find the path to this module rather than the path to a calling list file +get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH) + +# Function _git_find_closest_git_dir finds the next closest .git directory +# that is part of any directory in the path defined by _start_dir. +# The result is returned in the parent scope variable whose name is passed +# as variable _git_dir_var. If no .git directory can be found, the +# function returns an empty string via _git_dir_var. +# +# Example: Given a path C:/bla/foo/bar and assuming C:/bla/.git exists and +# neither foo nor bar contain a file/directory .git. This wil return +# C:/bla/.git +# +function(_git_find_closest_git_dir _start_dir _git_dir_var) + set(cur_dir "${_start_dir}") + set(git_dir "${_start_dir}/.git") + while(NOT EXISTS "${git_dir}") + # .git dir not found, search parent directories + set(git_previous_parent "${cur_dir}") + get_filename_component(cur_dir "${cur_dir}" DIRECTORY) + if(cur_dir STREQUAL git_previous_parent) + # We have reached the root directory, we are not in git + set(${_git_dir_var} + "" + PARENT_SCOPE) + return() + endif() + set(git_dir "${cur_dir}/.git") + endwhile() + set(${_git_dir_var} + "${git_dir}" + PARENT_SCOPE) +endfunction() + +function(get_git_head_revision _refspecvar _hashvar) + _git_find_closest_git_dir("${CMAKE_CURRENT_SOURCE_DIR}" GIT_DIR) + + if("${ARGN}" STREQUAL "ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR") + set(ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR TRUE) + else() + set(ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR FALSE) + endif() + if(NOT "${GIT_DIR}" STREQUAL "") + file(RELATIVE_PATH _relative_to_source_dir "${CMAKE_SOURCE_DIR}" + "${GIT_DIR}") + if("${_relative_to_source_dir}" MATCHES "[.][.]" AND NOT ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR) + # We've gone above the CMake root dir. + set(GIT_DIR "") + endif() + endif() + if("${GIT_DIR}" STREQUAL "") + set(${_refspecvar} + "GITDIR-NOTFOUND" + PARENT_SCOPE) + set(${_hashvar} + "GITDIR-NOTFOUND" + PARENT_SCOPE) + return() + endif() + + # Check if the current source dir is a git submodule or a worktree. + # In both cases .git is a file instead of a directory. + # + if(NOT IS_DIRECTORY ${GIT_DIR}) + # The following git command will return a non empty string that + # points to the super project working tree if the current + # source dir is inside a git submodule. + # Otherwise the command will return an empty string. + # + execute_process( + COMMAND "${GIT_EXECUTABLE}" rev-parse + --show-superproject-working-tree + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + OUTPUT_VARIABLE out + ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) + if(NOT "${out}" STREQUAL "") + # If out is empty, GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a submodule + file(READ ${GIT_DIR} submodule) + string(REGEX REPLACE "gitdir: (.*)$" "\\1" GIT_DIR_RELATIVE + ${submodule}) + string(STRIP ${GIT_DIR_RELATIVE} GIT_DIR_RELATIVE) + get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH) + get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} + ABSOLUTE) + set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD") + else() + # GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a worktree + file(READ ${GIT_DIR} worktree_ref) + # The .git directory contains a path to the worktree information directory + # inside the parent git repo of the worktree. + # + string(REGEX REPLACE "gitdir: (.*)$" "\\1" git_worktree_dir + ${worktree_ref}) + string(STRIP ${git_worktree_dir} git_worktree_dir) + _git_find_closest_git_dir("${git_worktree_dir}" GIT_DIR) + set(HEAD_SOURCE_FILE "${git_worktree_dir}/HEAD") + endif() + else() + set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD") + endif() + set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data") + if(NOT EXISTS "${GIT_DATA}") + file(MAKE_DIRECTORY "${GIT_DATA}") + endif() + + if(NOT EXISTS "${HEAD_SOURCE_FILE}") + return() + endif() + set(HEAD_FILE "${GIT_DATA}/HEAD") + configure_file("${HEAD_SOURCE_FILE}" "${HEAD_FILE}" COPYONLY) + + configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in" + "${GIT_DATA}/grabRef.cmake" @ONLY) + include("${GIT_DATA}/grabRef.cmake") + + set(${_refspecvar} + "${HEAD_REF}" + PARENT_SCOPE) + set(${_hashvar} + "${HEAD_HASH}" + PARENT_SCOPE) +endfunction() + +function(git_describe _var) + if(NOT GIT_FOUND) + find_package(Git QUIET) + endif() + get_git_head_revision(refspec hash) + if(NOT GIT_FOUND) + set(${_var} + "GIT-NOTFOUND" + PARENT_SCOPE) + return() + endif() + if(NOT hash) + set(${_var} + "HEAD-HASH-NOTFOUND" + PARENT_SCOPE) + return() + endif() + + # TODO sanitize + #if((${ARGN}" MATCHES "&&") OR + # (ARGN MATCHES "||") OR + # (ARGN MATCHES "\\;")) + # message("Please report the following error to the project!") + # message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}") + #endif() + + #message(STATUS "Arguments to execute_process: ${ARGN}") + + execute_process( + COMMAND "${GIT_EXECUTABLE}" describe --tags --always ${hash} ${ARGN} + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + RESULT_VARIABLE res + OUTPUT_VARIABLE out + ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) + if(NOT res EQUAL 0) + set(out "${out}-${res}-NOTFOUND") + endif() + + set(${_var} + "${out}" + PARENT_SCOPE) +endfunction() + +function(git_describe_working_tree _var) + if(NOT GIT_FOUND) + find_package(Git QUIET) + endif() + if(NOT GIT_FOUND) + set(${_var} + "GIT-NOTFOUND" + PARENT_SCOPE) + return() + endif() + + execute_process( + COMMAND "${GIT_EXECUTABLE}" describe --dirty ${ARGN} + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + RESULT_VARIABLE res + OUTPUT_VARIABLE out + ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) + if(NOT res EQUAL 0) + set(out "${out}-${res}-NOTFOUND") + endif() + + set(${_var} + "${out}" + PARENT_SCOPE) +endfunction() + +function(git_get_exact_tag _var) + git_describe(out --exact-match ${ARGN}) + set(${_var} + "${out}" + PARENT_SCOPE) +endfunction() + +function(git_local_changes _var) + if(NOT GIT_FOUND) + find_package(Git QUIET) + endif() + get_git_head_revision(refspec hash) + if(NOT GIT_FOUND) + set(${_var} + "GIT-NOTFOUND" + PARENT_SCOPE) + return() + endif() + if(NOT hash) + set(${_var} + "HEAD-HASH-NOTFOUND" + PARENT_SCOPE) + return() + endif() + + execute_process( + COMMAND "${GIT_EXECUTABLE}" diff-index --quiet HEAD -- + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + RESULT_VARIABLE res + OUTPUT_VARIABLE out + ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) + if(res EQUAL 0) + set(${_var} + "CLEAN" + PARENT_SCOPE) + else() + set(${_var} + "DIRTY" + PARENT_SCOPE) + endif() +endfunction() diff --git a/cmake/GetGitRevisionDescription.cmake.in b/cmake/GetGitRevisionDescription.cmake.in new file mode 100644 index 00000000..66eee637 --- /dev/null +++ b/cmake/GetGitRevisionDescription.cmake.in @@ -0,0 +1,43 @@ +# +# Internal file for GetGitRevisionDescription.cmake +# +# Requires CMake 2.6 or newer (uses the 'function' command) +# +# Original Author: +# 2009-2010 Ryan Pavlik +# http://academic.cleardefinition.com +# Iowa State University HCI Graduate Program/VRAC +# +# Copyright 2009-2012, Iowa State University +# Copyright 2011-2015, Contributors +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) +# SPDX-License-Identifier: BSL-1.0 + +set(HEAD_HASH) + +file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024) + +string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS) +if(HEAD_CONTENTS MATCHES "ref") + # named branch + string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}") + if(EXISTS "@GIT_DIR@/${HEAD_REF}") + configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) + else() + configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY) + file(READ "@GIT_DATA@/packed-refs" PACKED_REFS) + if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}") + set(HEAD_HASH "${CMAKE_MATCH_1}") + endif() + endif() +else() + # detached HEAD + configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY) +endif() + +if(NOT HEAD_HASH) + file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024) + string(STRIP "${HEAD_HASH}" HEAD_HASH) +endif() diff --git a/cmake/helpers.cmake b/cmake/helpers.cmake new file mode 100644 index 00000000..14fc4978 --- /dev/null +++ b/cmake/helpers.cmake @@ -0,0 +1,28 @@ +# Determines the git version with git describe and returns it by setting +# the GIT_INFO list in the parent scope. The list has the following entries +# 1. Full version string +# 2. Major version +# 3. Minor version +# 4. Revision +# 5. git SHA hash and commits since tag +function(determine_version_with_git) + include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/GetGitRevisionDescription.cmake) + git_describe(VERSION ${ARGN}) + string(FIND ${VERSION} "." VALID_VERSION) + if(VALID_VERSION EQUAL -1) + message(WARNING "Version string ${VERSION} retrieved with git describe is invalid") + return() + endif() + # Parse the version information into pieces. + string(REGEX REPLACE "^v([0-9]+)\\..*" "\\1" _VERSION_MAJOR "${VERSION}") + string(REGEX REPLACE "^v[0-9]+\\.([0-9]+).*" "\\1" _VERSION_MINOR "${VERSION}") + string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" _VERSION_PATCH "${VERSION}") + string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.[0-9]+-(.*)" "\\1" VERSION_SHA1 "${VERSION}") + set(GIT_INFO ${VERSION}) + list(APPEND GIT_INFO ${_VERSION_MAJOR}) + list(APPEND GIT_INFO ${_VERSION_MINOR}) + list(APPEND GIT_INFO ${_VERSION_PATCH}) + list(APPEND GIT_INFO ${VERSION_SHA1}) + set(GIT_INFO ${GIT_INFO} PARENT_SCOPE) + message(STATUS "Set git version info into GIT_INFO from the git tag ${VERSION}") +endfunction() diff --git a/src/fsfw/FSFWVersion.h.in b/src/fsfw/FSFWVersion.h.in index 19a56214..79d1f130 100644 --- a/src/fsfw/FSFWVersion.h.in +++ b/src/fsfw/FSFWVersion.h.in @@ -2,8 +2,9 @@ #define FSFW_VERSION_H_ // Versioning is kept in project CMakeLists.txt file -#define FSFW_VERSION_MAJOR @FSFW_VERSION@ -#define FSFW_VERSION_MINOR @FSFW_SUBVERSION@ -#define FSFW_VERSION_REVISION @FSFW_REVISION@ +static constexpr int FSFW_VERSION_MAJOR = @FSFW_VERSION@; +static constexpr int FSFW_VERSION_MINOR = @FSFW_SUBVERSION@; +static constexpr int FSFW_VERSION_REVISION = @FSFW_REVISION@; +static const char FSFW_VERSION_CST_GIT_SHA1[] = "@FSFW_VERSION_CST_GIT_SHA1@"; #endif /* FSFW_VERSION_H_ */ diff --git a/src/fsfw/version.cpp b/src/fsfw/version.cpp index a7f1d6a1..4717b188 100644 --- a/src/fsfw/version.cpp +++ b/src/fsfw/version.cpp @@ -13,7 +13,7 @@ const Version fsfw::FSFW_VERSION = {FSFW_VERSION_MAJOR, FSFW_VERSION_MINOR, FSFW_VERSION_REVISION}; -Version::Version(uint32_t major, uint32_t minor, uint32_t revision, const char* addInfo) +Version::Version(int major, int minor, int revision, const char* addInfo) : major(major), minor(minor), revision(revision), addInfo(addInfo) {} void Version::getVersion(char* str, size_t maxLen) const { diff --git a/src/fsfw/version.h b/src/fsfw/version.h index d8497703..d97306ec 100644 --- a/src/fsfw/version.h +++ b/src/fsfw/version.h @@ -10,10 +10,10 @@ class Version { public: - Version(uint32_t major, uint32_t minor, uint32_t revision, const char* addInfo = nullptr); - uint32_t major = 0; - uint32_t minor = 0; - uint32_t revision = 0; + Version(int major, int minor, int revision, const char* addInfo = nullptr); + int major = -1; + int minor = -1; + int revision = -1; // Additional information, e.g. a git SHA hash const char* addInfo = nullptr; From 7e1aed6ad9bdd9a2b02c1e17a135472dcc9fa11d Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 22 Apr 2022 14:04:30 +0200 Subject: [PATCH 32/52] apply afmt --- .../devicehandlers/MgmLIS3MDLHandler.cpp | 4 +- hal/src/fsfw_hal/linux/uart/UartCookie.cpp | 4 +- .../datapoollocal/LocalDataPoolManager.cpp | 10 ++-- src/fsfw/devicehandlers/DeviceHandlerBase.cpp | 13 +++-- src/fsfw/osal/rtems/PeriodicTask.h | 5 +- src/fsfw/version.cpp | 3 +- src/fsfw/version.h | 2 +- tests/src/fsfw_tests/unit/version.cpp | 50 +++++++++---------- 8 files changed, 44 insertions(+), 47 deletions(-) diff --git a/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp b/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp index 52b6dc07..644b488d 100644 --- a/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp +++ b/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp @@ -1,9 +1,9 @@ #include "MgmLIS3MDLHandler.h" -#include "fsfw/datapool/PoolReadGuard.h" - #include +#include "fsfw/datapool/PoolReadGuard.h" + MgmLIS3MDLHandler::MgmLIS3MDLHandler(object_id_t objectId, object_id_t deviceCommunication, CookieIF *comCookie, uint32_t transitionDelay) : DeviceHandlerBase(objectId, deviceCommunication, comCookie), diff --git a/hal/src/fsfw_hal/linux/uart/UartCookie.cpp b/hal/src/fsfw_hal/linux/uart/UartCookie.cpp index aa2dd214..3fedc9d4 100644 --- a/hal/src/fsfw_hal/linux/uart/UartCookie.cpp +++ b/hal/src/fsfw_hal/linux/uart/UartCookie.cpp @@ -24,9 +24,7 @@ void UartCookie::setParityEven() { parity = Parity::EVEN; } Parity UartCookie::getParity() const { return parity; } -void UartCookie::setBitsPerWord(BitsPerWord bitsPerWord_) { - bitsPerWord = bitsPerWord_; -} +void UartCookie::setBitsPerWord(BitsPerWord bitsPerWord_) { bitsPerWord = bitsPerWord_; } BitsPerWord UartCookie::getBitsPerWord() const { return bitsPerWord; } diff --git a/src/fsfw/datapoollocal/LocalDataPoolManager.cpp b/src/fsfw/datapoollocal/LocalDataPoolManager.cpp index 6053bd43..781d8f71 100644 --- a/src/fsfw/datapoollocal/LocalDataPoolManager.cpp +++ b/src/fsfw/datapoollocal/LocalDataPoolManager.cpp @@ -787,9 +787,9 @@ ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid, bool i // Serialize set packet into store. size_t size = 0; result = setPacket.serialize(&storePtr, &size, expectedSize, SerializeIF::Endianness::BIG); - if(result != HasReturnvaluesIF::RETURN_OK) { - ipcStore->deleteData(storeId); - return result; + if (result != HasReturnvaluesIF::RETURN_OK) { + ipcStore->deleteData(storeId); + return result; } if (expectedSize != size) { printWarningOrError(sif::OutputTypes::OUT_WARNING, "generateSetStructurePacket", @@ -806,8 +806,8 @@ ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid, bool i } result = hkQueue->reply(&reply); - if(result != HasReturnvaluesIF::RETURN_OK) { - ipcStore->deleteData(storeId); + if (result != HasReturnvaluesIF::RETURN_OK) { + ipcStore->deleteData(storeId); } return result; } diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp index 0e2802ac..dd9bd5d7 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp @@ -458,16 +458,15 @@ size_t DeviceHandlerBase::getNextReplyLength(DeviceCommandId_t commandId) { DeviceCommandId_t replyId = NO_COMMAND_ID; DeviceCommandMap::iterator command = cookieInfo.pendingCommand; if (command->second.useAlternativeReplyId) { - replyId = command->second.alternativeReplyId; - } - else { - replyId = commandId; + replyId = command->second.alternativeReplyId; + } else { + replyId = commandId; } DeviceReplyIter iter = deviceReplyMap.find(replyId); if (iter != deviceReplyMap.end()) { - if (iter->second.delayCycles != 0) { - return iter->second.replyLen; - } + if (iter->second.delayCycles != 0) { + return iter->second.replyLen; + } } return 0; } diff --git a/src/fsfw/osal/rtems/PeriodicTask.h b/src/fsfw/osal/rtems/PeriodicTask.h index 24ce4af1..9f47dfc6 100644 --- a/src/fsfw/osal/rtems/PeriodicTask.h +++ b/src/fsfw/osal/rtems/PeriodicTask.h @@ -59,14 +59,13 @@ class PeriodicTask : public RTEMSTaskBase, public PeriodicTaskIF { */ ReturnValue_t addComponent(object_id_t object) override; -/** + /** * Adds an object to the list of objects to be executed. * The objects are executed in the order added. * @param object pointer to the object to add. * @return RETURN_OK on success, RETURN_FAILED if the object could not be added. */ - ReturnValue_t addComponent(ExecutableObjectIF* object) override; - + ReturnValue_t addComponent(ExecutableObjectIF *object) override; uint32_t getPeriodMs() const override; diff --git a/src/fsfw/version.cpp b/src/fsfw/version.cpp index 4717b188..7355fc1d 100644 --- a/src/fsfw/version.cpp +++ b/src/fsfw/version.cpp @@ -1,8 +1,9 @@ #include "version.h" -#include "fsfw/FSFWVersion.h" #include +#include "fsfw/FSFWVersion.h" + #ifdef major #undef major #endif diff --git a/src/fsfw/version.h b/src/fsfw/version.h index d97306ec..f7d56d91 100644 --- a/src/fsfw/version.h +++ b/src/fsfw/version.h @@ -30,7 +30,7 @@ class Version { } friend bool operator>(const Version& v1, const Version& v2) { - return not (v1 < v2) and not (v1 == v2); + return not(v1 < v2) and not(v1 == v2); } friend bool operator<=(const Version& v1, const Version& v2) { return ((v1 == v2) or (v1 < v2)); } diff --git a/tests/src/fsfw_tests/unit/version.cpp b/tests/src/fsfw_tests/unit/version.cpp index 92a930dc..2967dfa5 100644 --- a/tests/src/fsfw_tests/unit/version.cpp +++ b/tests/src/fsfw_tests/unit/version.cpp @@ -17,15 +17,15 @@ TEST_CASE("Version API Tests", "[TestVersionAPI]") { fsfw::Version v1 = fsfw::Version(1, 1, 1); fsfw::Version v2 = fsfw::Version(1, 1, 1); REQUIRE(v1 == v2); - REQUIRE(not (v1 < v2)); - REQUIRE(not (v1 > v2)); + REQUIRE(not(v1 < v2)); + REQUIRE(not(v1 > v2)); REQUIRE(v1 <= v2); REQUIRE(v1 >= v2); v1.revision -= 1; REQUIRE(v1 != v2); - REQUIRE(not (v1 == v2)); - REQUIRE(not (v1 > v2)); - REQUIRE(not (v1 >= v2)); + REQUIRE(not(v1 == v2)); + REQUIRE(not(v1 > v2)); + REQUIRE(not(v1 >= v2)); REQUIRE(v1 < v2); REQUIRE(v1 <= v2); v1.revision += 1; @@ -33,60 +33,60 @@ TEST_CASE("Version API Tests", "[TestVersionAPI]") { REQUIRE(v1 != v2); REQUIRE(v1 < v2); REQUIRE(v1 <= v2); - REQUIRE(not (v1 == v2)); - REQUIRE(not (v1 > v2)); - REQUIRE(not (v1 >= v2)); + REQUIRE(not(v1 == v2)); + REQUIRE(not(v1 > v2)); + REQUIRE(not(v1 >= v2)); v1.minor += 1; v1.major -= 1; REQUIRE(v1 != v2); REQUIRE(v1 < v2); REQUIRE(v1 <= v2); - REQUIRE(not (v1 == v2)); - REQUIRE(not (v1 > v2)); - REQUIRE(not (v1 >= v2)); + REQUIRE(not(v1 == v2)); + REQUIRE(not(v1 > v2)); + REQUIRE(not(v1 >= v2)); v1.major += 1; REQUIRE(v1 == v2); REQUIRE(v1 <= v2); REQUIRE(v1 >= v2); - REQUIRE(not (v1 != v2)); - REQUIRE(not (v1 > v2)); - REQUIRE(not (v1 < v2)); + REQUIRE(not(v1 != v2)); + REQUIRE(not(v1 > v2)); + REQUIRE(not(v1 < v2)); v1.major += 1; v1.minor -= 1; REQUIRE(v1 != v2); REQUIRE(v1 > v2); REQUIRE(v1 >= v2); - REQUIRE(not (v1 == v2)); - REQUIRE(not (v1 < v2)); - REQUIRE(not (v1 <= v2)); + REQUIRE(not(v1 == v2)); + REQUIRE(not(v1 < v2)); + REQUIRE(not(v1 <= v2)); v1.major -= 1; v1.minor += 2; v1.revision -= 1; REQUIRE(v1 != v2); REQUIRE(v1 > v2); REQUIRE(v1 >= v2); - REQUIRE(not (v1 == v2)); - REQUIRE(not (v1 < v2)); - REQUIRE(not (v1 <= v2)); + REQUIRE(not(v1 == v2)); + REQUIRE(not(v1 < v2)); + REQUIRE(not(v1 <= v2)); v1.minor -= 1; v1.revision += 2; REQUIRE(v1 != v2); REQUIRE(v1 > v2); REQUIRE(v1 >= v2); - REQUIRE(not (v1 == v2)); - REQUIRE(not (v1 < v2)); - REQUIRE(not (v1 <= v2)); + REQUIRE(not(v1 == v2)); + REQUIRE(not(v1 < v2)); + REQUIRE(not(v1 <= v2)); v1.revision -= 1; REQUIRE(v1 == v2); REQUIRE(v1 <= v2); REQUIRE(v1 >= v2); - REQUIRE(not (v1 != v2)); + REQUIRE(not(v1 != v2)); #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::info << "v" << fsfw::FSFW_VERSION << std::endl; #endif char verString[10] = {}; fsfw::FSFW_VERSION.getVersion(verString, sizeof(verString)); #if FSFW_DISABLE_PRINTOUT == 0 - printf("v%s\n",verString); + printf("v%s\n", verString); #endif } From b951cb736a41c8b8db6532da3168529ad88cc017 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 22 Apr 2022 14:08:26 +0200 Subject: [PATCH 33/52] add fsfw specific cmake message prefix --- CMakeLists.txt | 24 +++++++++++++----------- cmake/helpers.cmake | 2 +- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f9ed91d..21495f37 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,8 @@ cmake_minimum_required(VERSION 3.13) # Add the cmake folder so the FindSphinx module is found set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) +set(MSG_PREFIX "fsfw |") + option(FSFW_GENERATE_SECTIONS "Generate function and data sections. Required to remove unused code" ON ) @@ -60,12 +62,12 @@ if(NOT FSFW_REVISION) endif() if(FSFW_BUILD_UNITTESTS) - message(STATUS "Building the FSFW unittests in addition to the static library") + message(STATUS "${MSG_PREFIX} Building the FSFW unittests in addition to the static library") # Check whether the user has already installed Catch2 first find_package(Catch2 3 QUIET) # Not installed, so use FetchContent to download and provide Catch2 if(NOT Catch2_FOUND) - message(STATUS "Catch2 installation not found. Downloading Catch2 library with FetchContent") + message(STATUS "${MSG_PREFIX} Catch2 installation not found. Downloading Catch2 library with FetchContent") include(FetchContent) FetchContent_Declare( @@ -87,8 +89,8 @@ if(FSFW_BUILD_UNITTESTS) add_executable(${FSFW_TEST_TGT}) if(FSFW_TESTS_GEN_COV) - message(STATUS "Generating coverage data for the library") - message(STATUS "Targets linking against ${LIB_FSFW_NAME} " + message(STATUS "${MSG_PREFIX} Generating coverage data for the library") + message(STATUS "${MSG_PREFIX} Targets linking against ${LIB_FSFW_NAME} " "will be compiled with coverage data as well" ) include(FetchContent) @@ -119,17 +121,17 @@ if(NOT CMAKE_CXX_STANDARD) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED True) elseif(${CMAKE_CXX_STANDARD} LESS 11) - message(FATAL_ERROR "Compiling the FSFW requires a minimum of C++11 support") + message(FATAL_ERROR "${MSG_PREFIX} Compiling the FSFW requires a minimum of C++11 support") endif() # Backwards comptability if(OS_FSFW AND NOT FSFW_OSAL) - message(WARNING "Please pass the FSFW OSAL as FSFW_OSAL instead of OS_FSFW") + message(WARNING "${MSG_PREFIX} Please pass the FSFW OSAL as FSFW_OSAL instead of OS_FSFW") set(FSFW_OSAL OS_FSFW) endif() if(NOT FSFW_OSAL) - message(STATUS "No OS for FSFW via FSFW_OSAL set. Assuming host OS") + message(STATUS "${MSG_PREFIX} No OS for FSFW via FSFW_OSAL set. Assuming host OS") # Assume host OS and autodetermine from OS_FSFW if(UNIX) set(FSFW_OSAL "linux" @@ -163,7 +165,7 @@ elseif(FSFW_OSAL STREQUAL rtems) set(FSFW_OSAL_RTEMS ON) else() message(WARNING - "Invalid operating system for FSFW specified! Setting to host.." + "${MSG_PREFIX} Invalid operating system for FSFW specified! Setting to host.." ) set(FSFW_OS_NAME "Host") set(OS_FSFW "host") @@ -172,7 +174,7 @@ endif() configure_file(src/fsfw/FSFW.h.in fsfw/FSFW.h) configure_file(src/fsfw/FSFWVersion.h.in fsfw/FSFWVersion.h) -message(STATUS "Compiling FSFW for the ${FSFW_OS_NAME} operating system.") +message(STATUS "${MSG_PREFIX} Compiling FSFW for the ${FSFW_OS_NAME} operating system") add_subdirectory(src) add_subdirectory(tests) @@ -256,8 +258,8 @@ endif() if(NOT FSFW_CONFIG_PATH) set(DEF_CONF_PATH misc/defaultcfg/fsfwconfig) if(NOT FSFW_BUILD_DOCS) - message(WARNING "Flight Software Framework configuration path not set!") - message(WARNING "Setting default configuration from ${DEF_CONF_PATH} ..") + message(WARNING "${MSG_PREFIX} Flight Software Framework configuration path not set") + message(WARNING "${MSG_PREFIX} Setting default configuration from ${DEF_CONF_PATH} ..") endif() add_subdirectory(${DEF_CONF_PATH}) set(FSFW_CONFIG_PATH ${DEF_CONF_PATH}) diff --git a/cmake/helpers.cmake b/cmake/helpers.cmake index 14fc4978..530926a6 100644 --- a/cmake/helpers.cmake +++ b/cmake/helpers.cmake @@ -24,5 +24,5 @@ function(determine_version_with_git) list(APPEND GIT_INFO ${_VERSION_PATCH}) list(APPEND GIT_INFO ${VERSION_SHA1}) set(GIT_INFO ${GIT_INFO} PARENT_SCOPE) - message(STATUS "Set git version info into GIT_INFO from the git tag ${VERSION}") + message(STATUS "${MSG_PREFIX} Set git version info into GIT_INFO from the git tag ${VERSION}") endfunction() From effecd46627feeb5590333014523670a6a12772e Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 22 Apr 2022 14:33:34 +0200 Subject: [PATCH 34/52] include cmake-modules manually instead - Instead of using FetchContent - Separate folder for easier update and for distintion - LICENSE file included --- CMakeLists.txt | 13 +- cmake/GetGitRevisionDescription.cmake | 284 ------- cmake/cmake-modules/CodeCoverage.cmake | 719 ++++++++++++++++++ .../GetGitRevisionDescription.cmake | 141 ++++ .../GetGitRevisionDescription.cmake.in | 21 +- cmake/cmake-modules/LICENSE_1_0.txt | 23 + cmake/cmake-modules/README.md | 5 + cmake/helpers.cmake | 2 +- 8 files changed, 900 insertions(+), 308 deletions(-) delete mode 100644 cmake/GetGitRevisionDescription.cmake create mode 100644 cmake/cmake-modules/CodeCoverage.cmake create mode 100644 cmake/cmake-modules/GetGitRevisionDescription.cmake rename cmake/{ => cmake-modules}/GetGitRevisionDescription.cmake.in (59%) create mode 100644 cmake/cmake-modules/LICENSE_1_0.txt create mode 100644 cmake/cmake-modules/README.md diff --git a/CMakeLists.txt b/CMakeLists.txt index 21495f37..282eadcc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,8 @@ cmake_minimum_required(VERSION 3.13) # Add the cmake folder so the FindSphinx module is found -set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) - +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ) +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake-modules") set(MSG_PREFIX "fsfw |") option(FSFW_GENERATE_SECTIONS @@ -44,7 +44,7 @@ project(${LIB_FSFW_NAME}) add_library(${LIB_FSFW_NAME}) # Version handling -include("GetGitRevisionDescription") +include(helpers) determine_version_with_git("--exclude" "docker_*") set(GIT_INFO ${GIT_INFO} CACHE STRING "Version information retrieved with git describe") list(GET GIT_INFO 1 FSFW_VERSION) @@ -93,14 +93,7 @@ if(FSFW_BUILD_UNITTESTS) message(STATUS "${MSG_PREFIX} Targets linking against ${LIB_FSFW_NAME} " "will be compiled with coverage data as well" ) - include(FetchContent) - FetchContent_Declare( - cmake-modules - GIT_REPOSITORY https://github.com/bilke/cmake-modules.git - ) - FetchContent_MakeAvailable(cmake-modules) set(CMAKE_BUILD_TYPE "Debug") - list(APPEND CMAKE_MODULE_PATH ${cmake-modules_SOURCE_DIR}) include(CodeCoverage) endif() endif() diff --git a/cmake/GetGitRevisionDescription.cmake b/cmake/GetGitRevisionDescription.cmake deleted file mode 100644 index 69ef78b2..00000000 --- a/cmake/GetGitRevisionDescription.cmake +++ /dev/null @@ -1,284 +0,0 @@ -# - Returns a version string from Git -# -# These functions force a re-configure on each git commit so that you can -# trust the values of the variables in your build system. -# -# get_git_head_revision( [ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR]) -# -# Returns the refspec and sha hash of the current head revision -# -# git_describe( [ ...]) -# -# Returns the results of git describe on the source tree, and adjusting -# the output so that it tests false if an error occurs. -# -# git_describe_working_tree( [ ...]) -# -# Returns the results of git describe on the working tree (--dirty option), -# and adjusting the output so that it tests false if an error occurs. -# -# git_get_exact_tag( [ ...]) -# -# Returns the results of git describe --exact-match on the source tree, -# and adjusting the output so that it tests false if there was no exact -# matching tag. -# -# git_local_changes() -# -# Returns either "CLEAN" or "DIRTY" with respect to uncommitted changes. -# Uses the return code of "git diff-index --quiet HEAD --". -# Does not regard untracked files. -# -# Requires CMake 2.6 or newer (uses the 'function' command) -# -# Original Author: -# 2009-2020 Ryan Pavlik -# http://academic.cleardefinition.com -# -# Copyright 2009-2013, Iowa State University. -# Copyright 2013-2020, Ryan Pavlik -# Copyright 2013-2020, Contributors -# SPDX-License-Identifier: BSL-1.0 -# Distributed under the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) - -if(__get_git_revision_description) - return() -endif() -set(__get_git_revision_description YES) - -# We must run the following at "include" time, not at function call time, -# to find the path to this module rather than the path to a calling list file -get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH) - -# Function _git_find_closest_git_dir finds the next closest .git directory -# that is part of any directory in the path defined by _start_dir. -# The result is returned in the parent scope variable whose name is passed -# as variable _git_dir_var. If no .git directory can be found, the -# function returns an empty string via _git_dir_var. -# -# Example: Given a path C:/bla/foo/bar and assuming C:/bla/.git exists and -# neither foo nor bar contain a file/directory .git. This wil return -# C:/bla/.git -# -function(_git_find_closest_git_dir _start_dir _git_dir_var) - set(cur_dir "${_start_dir}") - set(git_dir "${_start_dir}/.git") - while(NOT EXISTS "${git_dir}") - # .git dir not found, search parent directories - set(git_previous_parent "${cur_dir}") - get_filename_component(cur_dir "${cur_dir}" DIRECTORY) - if(cur_dir STREQUAL git_previous_parent) - # We have reached the root directory, we are not in git - set(${_git_dir_var} - "" - PARENT_SCOPE) - return() - endif() - set(git_dir "${cur_dir}/.git") - endwhile() - set(${_git_dir_var} - "${git_dir}" - PARENT_SCOPE) -endfunction() - -function(get_git_head_revision _refspecvar _hashvar) - _git_find_closest_git_dir("${CMAKE_CURRENT_SOURCE_DIR}" GIT_DIR) - - if("${ARGN}" STREQUAL "ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR") - set(ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR TRUE) - else() - set(ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR FALSE) - endif() - if(NOT "${GIT_DIR}" STREQUAL "") - file(RELATIVE_PATH _relative_to_source_dir "${CMAKE_SOURCE_DIR}" - "${GIT_DIR}") - if("${_relative_to_source_dir}" MATCHES "[.][.]" AND NOT ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR) - # We've gone above the CMake root dir. - set(GIT_DIR "") - endif() - endif() - if("${GIT_DIR}" STREQUAL "") - set(${_refspecvar} - "GITDIR-NOTFOUND" - PARENT_SCOPE) - set(${_hashvar} - "GITDIR-NOTFOUND" - PARENT_SCOPE) - return() - endif() - - # Check if the current source dir is a git submodule or a worktree. - # In both cases .git is a file instead of a directory. - # - if(NOT IS_DIRECTORY ${GIT_DIR}) - # The following git command will return a non empty string that - # points to the super project working tree if the current - # source dir is inside a git submodule. - # Otherwise the command will return an empty string. - # - execute_process( - COMMAND "${GIT_EXECUTABLE}" rev-parse - --show-superproject-working-tree - WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" - OUTPUT_VARIABLE out - ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) - if(NOT "${out}" STREQUAL "") - # If out is empty, GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a submodule - file(READ ${GIT_DIR} submodule) - string(REGEX REPLACE "gitdir: (.*)$" "\\1" GIT_DIR_RELATIVE - ${submodule}) - string(STRIP ${GIT_DIR_RELATIVE} GIT_DIR_RELATIVE) - get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH) - get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} - ABSOLUTE) - set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD") - else() - # GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a worktree - file(READ ${GIT_DIR} worktree_ref) - # The .git directory contains a path to the worktree information directory - # inside the parent git repo of the worktree. - # - string(REGEX REPLACE "gitdir: (.*)$" "\\1" git_worktree_dir - ${worktree_ref}) - string(STRIP ${git_worktree_dir} git_worktree_dir) - _git_find_closest_git_dir("${git_worktree_dir}" GIT_DIR) - set(HEAD_SOURCE_FILE "${git_worktree_dir}/HEAD") - endif() - else() - set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD") - endif() - set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data") - if(NOT EXISTS "${GIT_DATA}") - file(MAKE_DIRECTORY "${GIT_DATA}") - endif() - - if(NOT EXISTS "${HEAD_SOURCE_FILE}") - return() - endif() - set(HEAD_FILE "${GIT_DATA}/HEAD") - configure_file("${HEAD_SOURCE_FILE}" "${HEAD_FILE}" COPYONLY) - - configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in" - "${GIT_DATA}/grabRef.cmake" @ONLY) - include("${GIT_DATA}/grabRef.cmake") - - set(${_refspecvar} - "${HEAD_REF}" - PARENT_SCOPE) - set(${_hashvar} - "${HEAD_HASH}" - PARENT_SCOPE) -endfunction() - -function(git_describe _var) - if(NOT GIT_FOUND) - find_package(Git QUIET) - endif() - get_git_head_revision(refspec hash) - if(NOT GIT_FOUND) - set(${_var} - "GIT-NOTFOUND" - PARENT_SCOPE) - return() - endif() - if(NOT hash) - set(${_var} - "HEAD-HASH-NOTFOUND" - PARENT_SCOPE) - return() - endif() - - # TODO sanitize - #if((${ARGN}" MATCHES "&&") OR - # (ARGN MATCHES "||") OR - # (ARGN MATCHES "\\;")) - # message("Please report the following error to the project!") - # message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}") - #endif() - - #message(STATUS "Arguments to execute_process: ${ARGN}") - - execute_process( - COMMAND "${GIT_EXECUTABLE}" describe --tags --always ${hash} ${ARGN} - WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" - RESULT_VARIABLE res - OUTPUT_VARIABLE out - ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) - if(NOT res EQUAL 0) - set(out "${out}-${res}-NOTFOUND") - endif() - - set(${_var} - "${out}" - PARENT_SCOPE) -endfunction() - -function(git_describe_working_tree _var) - if(NOT GIT_FOUND) - find_package(Git QUIET) - endif() - if(NOT GIT_FOUND) - set(${_var} - "GIT-NOTFOUND" - PARENT_SCOPE) - return() - endif() - - execute_process( - COMMAND "${GIT_EXECUTABLE}" describe --dirty ${ARGN} - WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" - RESULT_VARIABLE res - OUTPUT_VARIABLE out - ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) - if(NOT res EQUAL 0) - set(out "${out}-${res}-NOTFOUND") - endif() - - set(${_var} - "${out}" - PARENT_SCOPE) -endfunction() - -function(git_get_exact_tag _var) - git_describe(out --exact-match ${ARGN}) - set(${_var} - "${out}" - PARENT_SCOPE) -endfunction() - -function(git_local_changes _var) - if(NOT GIT_FOUND) - find_package(Git QUIET) - endif() - get_git_head_revision(refspec hash) - if(NOT GIT_FOUND) - set(${_var} - "GIT-NOTFOUND" - PARENT_SCOPE) - return() - endif() - if(NOT hash) - set(${_var} - "HEAD-HASH-NOTFOUND" - PARENT_SCOPE) - return() - endif() - - execute_process( - COMMAND "${GIT_EXECUTABLE}" diff-index --quiet HEAD -- - WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" - RESULT_VARIABLE res - OUTPUT_VARIABLE out - ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) - if(res EQUAL 0) - set(${_var} - "CLEAN" - PARENT_SCOPE) - else() - set(${_var} - "DIRTY" - PARENT_SCOPE) - endif() -endfunction() diff --git a/cmake/cmake-modules/CodeCoverage.cmake b/cmake/cmake-modules/CodeCoverage.cmake new file mode 100644 index 00000000..aef3d943 --- /dev/null +++ b/cmake/cmake-modules/CodeCoverage.cmake @@ -0,0 +1,719 @@ +# Copyright (c) 2012 - 2017, Lars Bilke +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors +# may be used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# CHANGES: +# +# 2012-01-31, Lars Bilke +# - Enable Code Coverage +# +# 2013-09-17, Joakim Söderberg +# - Added support for Clang. +# - Some additional usage instructions. +# +# 2016-02-03, Lars Bilke +# - Refactored functions to use named parameters +# +# 2017-06-02, Lars Bilke +# - Merged with modified version from github.com/ufz/ogs +# +# 2019-05-06, Anatolii Kurotych +# - Remove unnecessary --coverage flag +# +# 2019-12-13, FeRD (Frank Dana) +# - Deprecate COVERAGE_LCOVR_EXCLUDES and COVERAGE_GCOVR_EXCLUDES lists in favor +# of tool-agnostic COVERAGE_EXCLUDES variable, or EXCLUDE setup arguments. +# - CMake 3.4+: All excludes can be specified relative to BASE_DIRECTORY +# - All setup functions: accept BASE_DIRECTORY, EXCLUDE list +# - Set lcov basedir with -b argument +# - Add automatic --demangle-cpp in lcovr, if 'c++filt' is available (can be +# overridden with NO_DEMANGLE option in setup_target_for_coverage_lcovr().) +# - Delete output dir, .info file on 'make clean' +# - Remove Python detection, since version mismatches will break gcovr +# - Minor cleanup (lowercase function names, update examples...) +# +# 2019-12-19, FeRD (Frank Dana) +# - Rename Lcov outputs, make filtered file canonical, fix cleanup for targets +# +# 2020-01-19, Bob Apthorpe +# - Added gfortran support +# +# 2020-02-17, FeRD (Frank Dana) +# - Make all add_custom_target()s VERBATIM to auto-escape wildcard characters +# in EXCLUDEs, and remove manual escaping from gcovr targets +# +# 2021-01-19, Robin Mueller +# - Add CODE_COVERAGE_VERBOSE option which will allow to print out commands which are run +# - Added the option for users to set the GCOVR_ADDITIONAL_ARGS variable to supply additional +# flags to the gcovr command +# +# 2020-05-04, Mihchael Davis +# - Add -fprofile-abs-path to make gcno files contain absolute paths +# - Fix BASE_DIRECTORY not working when defined +# - Change BYPRODUCT from folder to index.html to stop ninja from complaining about double defines +# +# 2021-05-10, Martin Stump +# - Check if the generator is multi-config before warning about non-Debug builds +# +# 2022-02-22, Marko Wehle +# - Change gcovr output from -o for --xml and --html output respectively. +# This will allow for Multiple Output Formats at the same time by making use of GCOVR_ADDITIONAL_ARGS, e.g. GCOVR_ADDITIONAL_ARGS "--txt". +# +# USAGE: +# +# 1. Copy this file into your cmake modules path. +# +# 2. Add the following line to your CMakeLists.txt (best inside an if-condition +# using a CMake option() to enable it just optionally): +# include(CodeCoverage) +# +# 3. Append necessary compiler flags for all supported source files: +# append_coverage_compiler_flags() +# Or for specific target: +# append_coverage_compiler_flags_to_target(YOUR_TARGET_NAME) +# +# 3.a (OPTIONAL) Set appropriate optimization flags, e.g. -O0, -O1 or -Og +# +# 4. If you need to exclude additional directories from the report, specify them +# using full paths in the COVERAGE_EXCLUDES variable before calling +# setup_target_for_coverage_*(). +# Example: +# set(COVERAGE_EXCLUDES +# '${PROJECT_SOURCE_DIR}/src/dir1/*' +# '/path/to/my/src/dir2/*') +# Or, use the EXCLUDE argument to setup_target_for_coverage_*(). +# Example: +# setup_target_for_coverage_lcov( +# NAME coverage +# EXECUTABLE testrunner +# EXCLUDE "${PROJECT_SOURCE_DIR}/src/dir1/*" "/path/to/my/src/dir2/*") +# +# 4.a NOTE: With CMake 3.4+, COVERAGE_EXCLUDES or EXCLUDE can also be set +# relative to the BASE_DIRECTORY (default: PROJECT_SOURCE_DIR) +# Example: +# set(COVERAGE_EXCLUDES "dir1/*") +# setup_target_for_coverage_gcovr_html( +# NAME coverage +# EXECUTABLE testrunner +# BASE_DIRECTORY "${PROJECT_SOURCE_DIR}/src" +# EXCLUDE "dir2/*") +# +# 5. Use the functions described below to create a custom make target which +# runs your test executable and produces a code coverage report. +# +# 6. Build a Debug build: +# cmake -DCMAKE_BUILD_TYPE=Debug .. +# make +# make my_coverage_target +# + +include(CMakeParseArguments) + +option(CODE_COVERAGE_VERBOSE "Verbose information" FALSE) + +# Check prereqs +find_program( GCOV_PATH gcov ) +find_program( LCOV_PATH NAMES lcov lcov.bat lcov.exe lcov.perl) +find_program( FASTCOV_PATH NAMES fastcov fastcov.py ) +find_program( GENHTML_PATH NAMES genhtml genhtml.perl genhtml.bat ) +find_program( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/scripts/test) +find_program( CPPFILT_PATH NAMES c++filt ) + +if(NOT GCOV_PATH) + message(FATAL_ERROR "gcov not found! Aborting...") +endif() # NOT GCOV_PATH + +get_property(LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) +list(GET LANGUAGES 0 LANG) + +if("${CMAKE_${LANG}_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang") + if("${CMAKE_${LANG}_COMPILER_VERSION}" VERSION_LESS 3) + message(FATAL_ERROR "Clang version must be 3.0.0 or greater! Aborting...") + endif() +elseif(NOT CMAKE_COMPILER_IS_GNUCXX) + if("${CMAKE_Fortran_COMPILER_ID}" MATCHES "[Ff]lang") + # Do nothing; exit conditional without error if true + elseif("${CMAKE_Fortran_COMPILER_ID}" MATCHES "GNU") + # Do nothing; exit conditional without error if true + else() + message(FATAL_ERROR "Compiler is not GNU gcc! Aborting...") + endif() +endif() + +set(COVERAGE_COMPILER_FLAGS "-g -fprofile-arcs -ftest-coverage" + CACHE INTERNAL "") +if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)") + include(CheckCXXCompilerFlag) + check_cxx_compiler_flag(-fprofile-abs-path HAVE_fprofile_abs_path) + if(HAVE_fprofile_abs_path) + set(COVERAGE_COMPILER_FLAGS "${COVERAGE_COMPILER_FLAGS} -fprofile-abs-path") + endif() +endif() + +set(CMAKE_Fortran_FLAGS_COVERAGE + ${COVERAGE_COMPILER_FLAGS} + CACHE STRING "Flags used by the Fortran compiler during coverage builds." + FORCE ) +set(CMAKE_CXX_FLAGS_COVERAGE + ${COVERAGE_COMPILER_FLAGS} + CACHE STRING "Flags used by the C++ compiler during coverage builds." + FORCE ) +set(CMAKE_C_FLAGS_COVERAGE + ${COVERAGE_COMPILER_FLAGS} + CACHE STRING "Flags used by the C compiler during coverage builds." + FORCE ) +set(CMAKE_EXE_LINKER_FLAGS_COVERAGE + "" + CACHE STRING "Flags used for linking binaries during coverage builds." + FORCE ) +set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE + "" + CACHE STRING "Flags used by the shared libraries linker during coverage builds." + FORCE ) +mark_as_advanced( + CMAKE_Fortran_FLAGS_COVERAGE + CMAKE_CXX_FLAGS_COVERAGE + CMAKE_C_FLAGS_COVERAGE + CMAKE_EXE_LINKER_FLAGS_COVERAGE + CMAKE_SHARED_LINKER_FLAGS_COVERAGE ) + +get_property(GENERATOR_IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(NOT (CMAKE_BUILD_TYPE STREQUAL "Debug" OR GENERATOR_IS_MULTI_CONFIG)) + message(WARNING "Code coverage results with an optimised (non-Debug) build may be misleading") +endif() # NOT (CMAKE_BUILD_TYPE STREQUAL "Debug" OR GENERATOR_IS_MULTI_CONFIG) + +if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_Fortran_COMPILER_ID STREQUAL "GNU") + link_libraries(gcov) +endif() + +# Defines a target for running and collection code coverage information +# Builds dependencies, runs the given executable and outputs reports. +# NOTE! The executable should always have a ZERO as exit code otherwise +# the coverage generation will not complete. +# +# setup_target_for_coverage_lcov( +# NAME testrunner_coverage # New target name +# EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR +# DEPENDENCIES testrunner # Dependencies to build first +# BASE_DIRECTORY "../" # Base directory for report +# # (defaults to PROJECT_SOURCE_DIR) +# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative +# # to BASE_DIRECTORY, with CMake 3.4+) +# NO_DEMANGLE # Don't demangle C++ symbols +# # even if c++filt is found +# ) +function(setup_target_for_coverage_lcov) + + set(options NO_DEMANGLE) + set(oneValueArgs BASE_DIRECTORY NAME) + set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES LCOV_ARGS GENHTML_ARGS) + cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if(NOT LCOV_PATH) + message(FATAL_ERROR "lcov not found! Aborting...") + endif() # NOT LCOV_PATH + + if(NOT GENHTML_PATH) + message(FATAL_ERROR "genhtml not found! Aborting...") + endif() # NOT GENHTML_PATH + + # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR + if(DEFINED Coverage_BASE_DIRECTORY) + get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE) + else() + set(BASEDIR ${PROJECT_SOURCE_DIR}) + endif() + + # Collect excludes (CMake 3.4+: Also compute absolute paths) + set(LCOV_EXCLUDES "") + foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_LCOV_EXCLUDES}) + if(CMAKE_VERSION VERSION_GREATER 3.4) + get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR}) + endif() + list(APPEND LCOV_EXCLUDES "${EXCLUDE}") + endforeach() + list(REMOVE_DUPLICATES LCOV_EXCLUDES) + + # Conditional arguments + if(CPPFILT_PATH AND NOT ${Coverage_NO_DEMANGLE}) + set(GENHTML_EXTRA_ARGS "--demangle-cpp") + endif() + + # Setting up commands which will be run to generate coverage data. + # Cleanup lcov + set(LCOV_CLEAN_CMD + ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -directory . + -b ${BASEDIR} --zerocounters + ) + # Create baseline to make sure untouched files show up in the report + set(LCOV_BASELINE_CMD + ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -c -i -d . -b + ${BASEDIR} -o ${Coverage_NAME}.base + ) + # Run tests + set(LCOV_EXEC_TESTS_CMD + ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS} + ) + # Capturing lcov counters and generating report + set(LCOV_CAPTURE_CMD + ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --directory . -b + ${BASEDIR} --capture --output-file ${Coverage_NAME}.capture + ) + # add baseline counters + set(LCOV_BASELINE_COUNT_CMD + ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -a ${Coverage_NAME}.base + -a ${Coverage_NAME}.capture --output-file ${Coverage_NAME}.total + ) + # filter collected data to final coverage report + set(LCOV_FILTER_CMD + ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --remove + ${Coverage_NAME}.total ${LCOV_EXCLUDES} --output-file ${Coverage_NAME}.info + ) + # Generate HTML output + set(LCOV_GEN_HTML_CMD + ${GENHTML_PATH} ${GENHTML_EXTRA_ARGS} ${Coverage_GENHTML_ARGS} -o + ${Coverage_NAME} ${Coverage_NAME}.info + ) + + + if(CODE_COVERAGE_VERBOSE) + message(STATUS "Executed command report") + message(STATUS "Command to clean up lcov: ") + string(REPLACE ";" " " LCOV_CLEAN_CMD_SPACED "${LCOV_CLEAN_CMD}") + message(STATUS "${LCOV_CLEAN_CMD_SPACED}") + + message(STATUS "Command to create baseline: ") + string(REPLACE ";" " " LCOV_BASELINE_CMD_SPACED "${LCOV_BASELINE_CMD}") + message(STATUS "${LCOV_BASELINE_CMD_SPACED}") + + message(STATUS "Command to run the tests: ") + string(REPLACE ";" " " LCOV_EXEC_TESTS_CMD_SPACED "${LCOV_EXEC_TESTS_CMD}") + message(STATUS "${LCOV_EXEC_TESTS_CMD_SPACED}") + + message(STATUS "Command to capture counters and generate report: ") + string(REPLACE ";" " " LCOV_CAPTURE_CMD_SPACED "${LCOV_CAPTURE_CMD}") + message(STATUS "${LCOV_CAPTURE_CMD_SPACED}") + + message(STATUS "Command to add baseline counters: ") + string(REPLACE ";" " " LCOV_BASELINE_COUNT_CMD_SPACED "${LCOV_BASELINE_COUNT_CMD}") + message(STATUS "${LCOV_BASELINE_COUNT_CMD_SPACED}") + + message(STATUS "Command to filter collected data: ") + string(REPLACE ";" " " LCOV_FILTER_CMD_SPACED "${LCOV_FILTER_CMD}") + message(STATUS "${LCOV_FILTER_CMD_SPACED}") + + message(STATUS "Command to generate lcov HTML output: ") + string(REPLACE ";" " " LCOV_GEN_HTML_CMD_SPACED "${LCOV_GEN_HTML_CMD}") + message(STATUS "${LCOV_GEN_HTML_CMD_SPACED}") + endif() + + # Setup target + add_custom_target(${Coverage_NAME} + COMMAND ${LCOV_CLEAN_CMD} + COMMAND ${LCOV_BASELINE_CMD} + COMMAND ${LCOV_EXEC_TESTS_CMD} + COMMAND ${LCOV_CAPTURE_CMD} + COMMAND ${LCOV_BASELINE_COUNT_CMD} + COMMAND ${LCOV_FILTER_CMD} + COMMAND ${LCOV_GEN_HTML_CMD} + + # Set output files as GENERATED (will be removed on 'make clean') + BYPRODUCTS + ${Coverage_NAME}.base + ${Coverage_NAME}.capture + ${Coverage_NAME}.total + ${Coverage_NAME}.info + ${Coverage_NAME}/index.html + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + DEPENDS ${Coverage_DEPENDENCIES} + VERBATIM # Protect arguments to commands + COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report." + ) + + # Show where to find the lcov info report + add_custom_command(TARGET ${Coverage_NAME} POST_BUILD + COMMAND ; + COMMENT "Lcov code coverage info report saved in ${Coverage_NAME}.info." + ) + + # Show info where to find the report + add_custom_command(TARGET ${Coverage_NAME} POST_BUILD + COMMAND ; + COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report." + ) + +endfunction() # setup_target_for_coverage_lcov + +# Defines a target for running and collection code coverage information +# Builds dependencies, runs the given executable and outputs reports. +# NOTE! The executable should always have a ZERO as exit code otherwise +# the coverage generation will not complete. +# +# setup_target_for_coverage_gcovr_xml( +# NAME ctest_coverage # New target name +# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR +# DEPENDENCIES executable_target # Dependencies to build first +# BASE_DIRECTORY "../" # Base directory for report +# # (defaults to PROJECT_SOURCE_DIR) +# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative +# # to BASE_DIRECTORY, with CMake 3.4+) +# ) +# The user can set the variable GCOVR_ADDITIONAL_ARGS to supply additional flags to the +# GCVOR command. +function(setup_target_for_coverage_gcovr_xml) + + set(options NONE) + set(oneValueArgs BASE_DIRECTORY NAME) + set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES) + cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if(NOT GCOVR_PATH) + message(FATAL_ERROR "gcovr not found! Aborting...") + endif() # NOT GCOVR_PATH + + # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR + if(DEFINED Coverage_BASE_DIRECTORY) + get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE) + else() + set(BASEDIR ${PROJECT_SOURCE_DIR}) + endif() + + # Collect excludes (CMake 3.4+: Also compute absolute paths) + set(GCOVR_EXCLUDES "") + foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES}) + if(CMAKE_VERSION VERSION_GREATER 3.4) + get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR}) + endif() + list(APPEND GCOVR_EXCLUDES "${EXCLUDE}") + endforeach() + list(REMOVE_DUPLICATES GCOVR_EXCLUDES) + + # Combine excludes to several -e arguments + set(GCOVR_EXCLUDE_ARGS "") + foreach(EXCLUDE ${GCOVR_EXCLUDES}) + list(APPEND GCOVR_EXCLUDE_ARGS "-e") + list(APPEND GCOVR_EXCLUDE_ARGS "${EXCLUDE}") + endforeach() + + # Set up commands which will be run to generate coverage data + # Run tests + set(GCOVR_XML_EXEC_TESTS_CMD + ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS} + ) + # Running gcovr + set(GCOVR_XML_CMD + ${GCOVR_PATH} --xml ${Coverage_NAME}.xml -r ${BASEDIR} ${GCOVR_ADDITIONAL_ARGS} + ${GCOVR_EXCLUDE_ARGS} --object-directory=${PROJECT_BINARY_DIR} + ) + + if(CODE_COVERAGE_VERBOSE) + message(STATUS "Executed command report") + + message(STATUS "Command to run tests: ") + string(REPLACE ";" " " GCOVR_XML_EXEC_TESTS_CMD_SPACED "${GCOVR_XML_EXEC_TESTS_CMD}") + message(STATUS "${GCOVR_XML_EXEC_TESTS_CMD_SPACED}") + + message(STATUS "Command to generate gcovr XML coverage data: ") + string(REPLACE ";" " " GCOVR_XML_CMD_SPACED "${GCOVR_XML_CMD}") + message(STATUS "${GCOVR_XML_CMD_SPACED}") + endif() + + add_custom_target(${Coverage_NAME} + COMMAND ${GCOVR_XML_EXEC_TESTS_CMD} + COMMAND ${GCOVR_XML_CMD} + + BYPRODUCTS ${Coverage_NAME}.xml + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + DEPENDS ${Coverage_DEPENDENCIES} + VERBATIM # Protect arguments to commands + COMMENT "Running gcovr to produce Cobertura code coverage report." + ) + + # Show info where to find the report + add_custom_command(TARGET ${Coverage_NAME} POST_BUILD + COMMAND ; + COMMENT "Cobertura code coverage report saved in ${Coverage_NAME}.xml." + ) +endfunction() # setup_target_for_coverage_gcovr_xml + +# Defines a target for running and collection code coverage information +# Builds dependencies, runs the given executable and outputs reports. +# NOTE! The executable should always have a ZERO as exit code otherwise +# the coverage generation will not complete. +# +# setup_target_for_coverage_gcovr_html( +# NAME ctest_coverage # New target name +# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR +# DEPENDENCIES executable_target # Dependencies to build first +# BASE_DIRECTORY "../" # Base directory for report +# # (defaults to PROJECT_SOURCE_DIR) +# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative +# # to BASE_DIRECTORY, with CMake 3.4+) +# ) +# The user can set the variable GCOVR_ADDITIONAL_ARGS to supply additional flags to the +# GCVOR command. +function(setup_target_for_coverage_gcovr_html) + + set(options NONE) + set(oneValueArgs BASE_DIRECTORY NAME) + set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES) + cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if(NOT GCOVR_PATH) + message(FATAL_ERROR "gcovr not found! Aborting...") + endif() # NOT GCOVR_PATH + + # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR + if(DEFINED Coverage_BASE_DIRECTORY) + get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE) + else() + set(BASEDIR ${PROJECT_SOURCE_DIR}) + endif() + + # Collect excludes (CMake 3.4+: Also compute absolute paths) + set(GCOVR_EXCLUDES "") + foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES}) + if(CMAKE_VERSION VERSION_GREATER 3.4) + get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR}) + endif() + list(APPEND GCOVR_EXCLUDES "${EXCLUDE}") + endforeach() + list(REMOVE_DUPLICATES GCOVR_EXCLUDES) + + # Combine excludes to several -e arguments + set(GCOVR_EXCLUDE_ARGS "") + foreach(EXCLUDE ${GCOVR_EXCLUDES}) + list(APPEND GCOVR_EXCLUDE_ARGS "-e") + list(APPEND GCOVR_EXCLUDE_ARGS "${EXCLUDE}") + endforeach() + + # Set up commands which will be run to generate coverage data + # Run tests + set(GCOVR_HTML_EXEC_TESTS_CMD + ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS} + ) + # Create folder + set(GCOVR_HTML_FOLDER_CMD + ${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/${Coverage_NAME} + ) + # Running gcovr + set(GCOVR_HTML_CMD + ${GCOVR_PATH} --html ${Coverage_NAME}/index.html --html-details -r ${BASEDIR} ${GCOVR_ADDITIONAL_ARGS} + ${GCOVR_EXCLUDE_ARGS} --object-directory=${PROJECT_BINARY_DIR} + ) + + if(CODE_COVERAGE_VERBOSE) + message(STATUS "Executed command report") + + message(STATUS "Command to run tests: ") + string(REPLACE ";" " " GCOVR_HTML_EXEC_TESTS_CMD_SPACED "${GCOVR_HTML_EXEC_TESTS_CMD}") + message(STATUS "${GCOVR_HTML_EXEC_TESTS_CMD_SPACED}") + + message(STATUS "Command to create a folder: ") + string(REPLACE ";" " " GCOVR_HTML_FOLDER_CMD_SPACED "${GCOVR_HTML_FOLDER_CMD}") + message(STATUS "${GCOVR_HTML_FOLDER_CMD_SPACED}") + + message(STATUS "Command to generate gcovr HTML coverage data: ") + string(REPLACE ";" " " GCOVR_HTML_CMD_SPACED "${GCOVR_HTML_CMD}") + message(STATUS "${GCOVR_HTML_CMD_SPACED}") + endif() + + add_custom_target(${Coverage_NAME} + COMMAND ${GCOVR_HTML_EXEC_TESTS_CMD} + COMMAND ${GCOVR_HTML_FOLDER_CMD} + COMMAND ${GCOVR_HTML_CMD} + + BYPRODUCTS ${PROJECT_BINARY_DIR}/${Coverage_NAME}/index.html # report directory + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + DEPENDS ${Coverage_DEPENDENCIES} + VERBATIM # Protect arguments to commands + COMMENT "Running gcovr to produce HTML code coverage report." + ) + + # Show info where to find the report + add_custom_command(TARGET ${Coverage_NAME} POST_BUILD + COMMAND ; + COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report." + ) + +endfunction() # setup_target_for_coverage_gcovr_html + +# Defines a target for running and collection code coverage information +# Builds dependencies, runs the given executable and outputs reports. +# NOTE! The executable should always have a ZERO as exit code otherwise +# the coverage generation will not complete. +# +# setup_target_for_coverage_fastcov( +# NAME testrunner_coverage # New target name +# EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR +# DEPENDENCIES testrunner # Dependencies to build first +# BASE_DIRECTORY "../" # Base directory for report +# # (defaults to PROJECT_SOURCE_DIR) +# EXCLUDE "src/dir1/" "src/dir2/" # Patterns to exclude. +# NO_DEMANGLE # Don't demangle C++ symbols +# # even if c++filt is found +# SKIP_HTML # Don't create html report +# POST_CMD perl -i -pe s!${PROJECT_SOURCE_DIR}/!!g ctest_coverage.json # E.g. for stripping source dir from file paths +# ) +function(setup_target_for_coverage_fastcov) + + set(options NO_DEMANGLE SKIP_HTML) + set(oneValueArgs BASE_DIRECTORY NAME) + set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES FASTCOV_ARGS GENHTML_ARGS POST_CMD) + cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if(NOT FASTCOV_PATH) + message(FATAL_ERROR "fastcov not found! Aborting...") + endif() + + if(NOT Coverage_SKIP_HTML AND NOT GENHTML_PATH) + message(FATAL_ERROR "genhtml not found! Aborting...") + endif() + + # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR + if(Coverage_BASE_DIRECTORY) + get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE) + else() + set(BASEDIR ${PROJECT_SOURCE_DIR}) + endif() + + # Collect excludes (Patterns, not paths, for fastcov) + set(FASTCOV_EXCLUDES "") + foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_FASTCOV_EXCLUDES}) + list(APPEND FASTCOV_EXCLUDES "${EXCLUDE}") + endforeach() + list(REMOVE_DUPLICATES FASTCOV_EXCLUDES) + + # Conditional arguments + if(CPPFILT_PATH AND NOT ${Coverage_NO_DEMANGLE}) + set(GENHTML_EXTRA_ARGS "--demangle-cpp") + endif() + + # Set up commands which will be run to generate coverage data + set(FASTCOV_EXEC_TESTS_CMD ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}) + + set(FASTCOV_CAPTURE_CMD ${FASTCOV_PATH} ${Coverage_FASTCOV_ARGS} --gcov ${GCOV_PATH} + --search-directory ${BASEDIR} + --process-gcno + --output ${Coverage_NAME}.json + --exclude ${FASTCOV_EXCLUDES} + --exclude ${FASTCOV_EXCLUDES} + ) + + set(FASTCOV_CONVERT_CMD ${FASTCOV_PATH} + -C ${Coverage_NAME}.json --lcov --output ${Coverage_NAME}.info + ) + + if(Coverage_SKIP_HTML) + set(FASTCOV_HTML_CMD ";") + else() + set(FASTCOV_HTML_CMD ${GENHTML_PATH} ${GENHTML_EXTRA_ARGS} ${Coverage_GENHTML_ARGS} + -o ${Coverage_NAME} ${Coverage_NAME}.info + ) + endif() + + set(FASTCOV_POST_CMD ";") + if(Coverage_POST_CMD) + set(FASTCOV_POST_CMD ${Coverage_POST_CMD}) + endif() + + if(CODE_COVERAGE_VERBOSE) + message(STATUS "Code coverage commands for target ${Coverage_NAME} (fastcov):") + + message(" Running tests:") + string(REPLACE ";" " " FASTCOV_EXEC_TESTS_CMD_SPACED "${FASTCOV_EXEC_TESTS_CMD}") + message(" ${FASTCOV_EXEC_TESTS_CMD_SPACED}") + + message(" Capturing fastcov counters and generating report:") + string(REPLACE ";" " " FASTCOV_CAPTURE_CMD_SPACED "${FASTCOV_CAPTURE_CMD}") + message(" ${FASTCOV_CAPTURE_CMD_SPACED}") + + message(" Converting fastcov .json to lcov .info:") + string(REPLACE ";" " " FASTCOV_CONVERT_CMD_SPACED "${FASTCOV_CONVERT_CMD}") + message(" ${FASTCOV_CONVERT_CMD_SPACED}") + + if(NOT Coverage_SKIP_HTML) + message(" Generating HTML report: ") + string(REPLACE ";" " " FASTCOV_HTML_CMD_SPACED "${FASTCOV_HTML_CMD}") + message(" ${FASTCOV_HTML_CMD_SPACED}") + endif() + if(Coverage_POST_CMD) + message(" Running post command: ") + string(REPLACE ";" " " FASTCOV_POST_CMD_SPACED "${FASTCOV_POST_CMD}") + message(" ${FASTCOV_POST_CMD_SPACED}") + endif() + endif() + + # Setup target + add_custom_target(${Coverage_NAME} + + # Cleanup fastcov + COMMAND ${FASTCOV_PATH} ${Coverage_FASTCOV_ARGS} --gcov ${GCOV_PATH} + --search-directory ${BASEDIR} + --zerocounters + + COMMAND ${FASTCOV_EXEC_TESTS_CMD} + COMMAND ${FASTCOV_CAPTURE_CMD} + COMMAND ${FASTCOV_CONVERT_CMD} + COMMAND ${FASTCOV_HTML_CMD} + COMMAND ${FASTCOV_POST_CMD} + + # Set output files as GENERATED (will be removed on 'make clean') + BYPRODUCTS + ${Coverage_NAME}.info + ${Coverage_NAME}.json + ${Coverage_NAME}/index.html # report directory + + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + DEPENDS ${Coverage_DEPENDENCIES} + VERBATIM # Protect arguments to commands + COMMENT "Resetting code coverage counters to zero. Processing code coverage counters and generating report." + ) + + set(INFO_MSG "fastcov code coverage info report saved in ${Coverage_NAME}.info and ${Coverage_NAME}.json.") + if(NOT Coverage_SKIP_HTML) + string(APPEND INFO_MSG " Open ${PROJECT_BINARY_DIR}/${Coverage_NAME}/index.html in your browser to view the coverage report.") + endif() + # Show where to find the fastcov info report + add_custom_command(TARGET ${Coverage_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E echo ${INFO_MSG} + ) + +endfunction() # setup_target_for_coverage_fastcov + +function(append_coverage_compiler_flags) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE) + set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE) + message(STATUS "Appending code coverage compiler flags: ${COVERAGE_COMPILER_FLAGS}") +endfunction() # append_coverage_compiler_flags + +# Setup coverage for specific library +function(append_coverage_compiler_flags_to_target name) + target_compile_options(${name} + PRIVATE ${COVERAGE_COMPILER_FLAGS}) +endfunction() diff --git a/cmake/cmake-modules/GetGitRevisionDescription.cmake b/cmake/cmake-modules/GetGitRevisionDescription.cmake new file mode 100644 index 00000000..1175e673 --- /dev/null +++ b/cmake/cmake-modules/GetGitRevisionDescription.cmake @@ -0,0 +1,141 @@ +# - Returns a version string from Git +# +# These functions force a re-configure on each git commit so that you can +# trust the values of the variables in your build system. +# +# get_git_head_revision( [ ...]) +# +# Returns the refspec and sha hash of the current head revision +# +# git_describe( [ ...]) +# +# Returns the results of git describe on the source tree, and adjusting +# the output so that it tests false if an error occurs. +# +# git_get_exact_tag( [ ...]) +# +# Returns the results of git describe --exact-match on the source tree, +# and adjusting the output so that it tests false if there was no exact +# matching tag. +# +# Requires CMake 2.6 or newer (uses the 'function' command) +# +# Original Author: +# 2009-2010 Ryan Pavlik +# http://academic.cleardefinition.com +# Iowa State University HCI Graduate Program/VRAC +# +# Copyright Iowa State University 2009-2010. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +if(__get_git_revision_description) + return() +endif() +set(__get_git_revision_description YES) + +# We must run the following at "include" time, not at function call time, +# to find the path to this module rather than the path to a calling list file +get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH) + +function(get_git_head_revision _refspecvar _hashvar) + set(GIT_PARENT_DIR "${CMAKE_CURRENT_SOURCE_DIR}") + set(GIT_DIR "${GIT_PARENT_DIR}/.git") + while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories + set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}") + get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH) + if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT) + # We have reached the root directory, we are not in git + set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE) + set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE) + return() + endif() + set(GIT_DIR "${GIT_PARENT_DIR}/.git") + endwhile() + # check if this is a submodule + if(NOT IS_DIRECTORY ${GIT_DIR}) + file(READ ${GIT_DIR} submodule) + string(REGEX REPLACE "gitdir: (.*)\n$" "\\1" GIT_DIR_RELATIVE ${submodule}) + get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH) + + if (IS_ABSOLUTE ${GIT_DIR_RELATIVE}) + set(GIT_DIR ${GIT_DIR_RELATIVE}) + else() + get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE) + endif() + + endif() + set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data") + if(NOT EXISTS "${GIT_DATA}") + file(MAKE_DIRECTORY "${GIT_DATA}") + endif() + + if(NOT EXISTS "${GIT_DIR}/HEAD") + return() + endif() + set(HEAD_FILE "${GIT_DATA}/HEAD") + configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY) + + configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in" + "${GIT_DATA}/grabRef.cmake" + @ONLY) + include("${GIT_DATA}/grabRef.cmake") + + set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE) + set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE) +endfunction() + +function(git_describe _var) + if(NOT GIT_FOUND) + find_package(Git QUIET) + endif() + get_git_head_revision(refspec hash) + if(NOT GIT_FOUND) + set(${_var} "GIT-NOTFOUND" PARENT_SCOPE) + return() + endif() + if(NOT hash) + set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE) + return() + endif() + + # TODO sanitize + #if((${ARGN}" MATCHES "&&") OR + # (ARGN MATCHES "||") OR + # (ARGN MATCHES "\\;")) + # message("Please report the following error to the project!") + # message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}") + #endif() + + #message(STATUS "Arguments to execute_process: ${ARGN}") + + execute_process(COMMAND + ${GIT_EXECUTABLE} + describe + ${hash} + ${ARGN} + WORKING_DIRECTORY + "${CMAKE_SOURCE_DIR}" + RESULT_VARIABLE + res + OUTPUT_VARIABLE + out + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + if(NOT res EQUAL 0) + set(out "${out}-${res}-NOTFOUND") + endif() + + set(${_var} "${out}" PARENT_SCOPE) +endfunction() + +function(git_get_exact_tag _var) + git_describe(out --exact-match ${ARGN}) + set(${_var} "${out}" PARENT_SCOPE) +endfunction() + +function(git_get_tag _var) + git_describe(out --tags ${ARGN}) + set(${_var} "${out}" PARENT_SCOPE) +endfunction() diff --git a/cmake/GetGitRevisionDescription.cmake.in b/cmake/cmake-modules/GetGitRevisionDescription.cmake.in similarity index 59% rename from cmake/GetGitRevisionDescription.cmake.in rename to cmake/cmake-modules/GetGitRevisionDescription.cmake.in index 66eee637..ae19652b 100644 --- a/cmake/GetGitRevisionDescription.cmake.in +++ b/cmake/cmake-modules/GetGitRevisionDescription.cmake.in @@ -1,4 +1,4 @@ -# +# # Internal file for GetGitRevisionDescription.cmake # # Requires CMake 2.6 or newer (uses the 'function' command) @@ -8,12 +8,10 @@ # http://academic.cleardefinition.com # Iowa State University HCI Graduate Program/VRAC # -# Copyright 2009-2012, Iowa State University -# Copyright 2011-2015, Contributors +# Copyright Iowa State University 2009-2010. # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) -# SPDX-License-Identifier: BSL-1.0 set(HEAD_HASH) @@ -24,13 +22,10 @@ if(HEAD_CONTENTS MATCHES "ref") # named branch string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}") if(EXISTS "@GIT_DIR@/${HEAD_REF}") - configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) - else() - configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY) - file(READ "@GIT_DATA@/packed-refs" PACKED_REFS) - if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}") - set(HEAD_HASH "${CMAKE_MATCH_1}") - endif() + configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) + elseif(EXISTS "@GIT_DIR@/logs/${HEAD_REF}") + configure_file("@GIT_DIR@/logs/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) + set(HEAD_HASH "${HEAD_REF}") endif() else() # detached HEAD @@ -38,6 +33,6 @@ else() endif() if(NOT HEAD_HASH) - file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024) - string(STRIP "${HEAD_HASH}" HEAD_HASH) +file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024) +string(STRIP "${HEAD_HASH}" HEAD_HASH) endif() diff --git a/cmake/cmake-modules/LICENSE_1_0.txt b/cmake/cmake-modules/LICENSE_1_0.txt new file mode 100644 index 00000000..36b7cd93 --- /dev/null +++ b/cmake/cmake-modules/LICENSE_1_0.txt @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/cmake/cmake-modules/README.md b/cmake/cmake-modules/README.md new file mode 100644 index 00000000..4692eddb --- /dev/null +++ b/cmake/cmake-modules/README.md @@ -0,0 +1,5 @@ +The files in these folder were manually copy and pasted from the +[cmake-modules repository](https://github.com/bilke/cmake-modules). It was decided to do +this because only a small subset of its provided functions are needed. + +The license file in included here as well. diff --git a/cmake/helpers.cmake b/cmake/helpers.cmake index 530926a6..3f22ebde 100644 --- a/cmake/helpers.cmake +++ b/cmake/helpers.cmake @@ -6,7 +6,7 @@ # 4. Revision # 5. git SHA hash and commits since tag function(determine_version_with_git) - include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/GetGitRevisionDescription.cmake) + include(GetGitRevisionDescription) git_describe(VERSION ${ARGN}) string(FIND ${VERSION} "." VALID_VERSION) if(VALID_VERSION EQUAL -1) From 513ae9dc105755307b12c66111708a386f9aac52 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 22 Apr 2022 14:38:32 +0200 Subject: [PATCH 35/52] prefixed git info variable --- CMakeLists.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 282eadcc..e54a4b80 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,12 +45,12 @@ add_library(${LIB_FSFW_NAME}) # Version handling include(helpers) -determine_version_with_git("--exclude" "docker_*") -set(GIT_INFO ${GIT_INFO} CACHE STRING "Version information retrieved with git describe") -list(GET GIT_INFO 1 FSFW_VERSION) -list(GET GIT_INFO 2 FSFW_SUBVERSION) -list(GET GIT_INFO 3 FSFW_REVISION) -list(GET GIT_INFO 4 FSFW_VERSION_CST_GIT_SHA1) +determine_version_with_git() +set(FSFW_GIT_INFO ${GIT_INFO} CACHE STRING "Version information retrieved with git describe") +list(GET FSFW_GIT_INFO 1 FSFW_VERSION) +list(GET FSFW_GIT_INFO 2 FSFW_SUBVERSION) +list(GET FSFW_GIT_INFO 3 FSFW_REVISION) +list(GET FSFW_GIT_INFO 4 FSFW_VERSION_CST_GIT_SHA1) if(NOT FSFW_VERSION) set(FSFW_VERSION -1) endif() From 9c7eba4431cef294e96ec6544013ce082c596ba6 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 22 Apr 2022 14:47:28 +0200 Subject: [PATCH 36/52] git version handler more robust now --- CMakeLists.txt | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e54a4b80..9066cec2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,9 @@ cmake_minimum_required(VERSION 3.13) +set(FSFW_VERSION_IF_GIT_FAILS 4) +set(FSFW_SUBVERSION_IF_GIT_FAILS 0) +set(FSFW_REVISION_IF_GIT_FAILS 0) + # Add the cmake folder so the FindSphinx module is found list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake-modules") @@ -44,21 +48,27 @@ project(${LIB_FSFW_NAME}) add_library(${LIB_FSFW_NAME}) # Version handling -include(helpers) -determine_version_with_git() -set(FSFW_GIT_INFO ${GIT_INFO} CACHE STRING "Version information retrieved with git describe") -list(GET FSFW_GIT_INFO 1 FSFW_VERSION) -list(GET FSFW_GIT_INFO 2 FSFW_SUBVERSION) -list(GET FSFW_GIT_INFO 3 FSFW_REVISION) -list(GET FSFW_GIT_INFO 4 FSFW_VERSION_CST_GIT_SHA1) -if(NOT FSFW_VERSION) - set(FSFW_VERSION -1) -endif() -if(NOT FSFW_SUBVERSION) - set(FSFW_SUBVERSION -1) -endif() -if(NOT FSFW_REVISION) - set(FSFW_REVISION -1) +if(EXISTS .git) + include(helpers) + determine_version_with_git("--exclude" "docker_*") + set(FSFW_GIT_INFO ${GIT_INFO} CACHE STRING "Version information retrieved with git describe") + list(GET FSFW_GIT_INFO 1 FSFW_VERSION) + list(GET FSFW_GIT_INFO 2 FSFW_SUBVERSION) + list(GET FSFW_GIT_INFO 3 FSFW_REVISION) + list(GET FSFW_GIT_INFO 4 FSFW_VERSION_CST_GIT_SHA1) + if(NOT FSFW_VERSION) + set(FSFW_VERSION ${FSFW_VERSION_IF_GIT_FAILS}) + endif() + if(NOT FSFW_SUBVERSION) + set(FSFW_SUBVERSION ${FSFW_SUBVERSION_IF_GIT_FAILS}) + endif() + if(NOT FSFW_REVISION) + set(FSFW_REVISION ${FSFW_REVISION_IF_GIT_FAILS}) + endif() +else() + set(FSFW_VERSION ${FSFW_VERSION_IF_GIT_FAILS}) + set(FSFW_SUBVERSION ${FSFW_SUBVERSION_IF_GIT_FAILS}) + set(FSFW_REVISION ${FSFW_REVISION_IF_GIT_FAILS}) endif() if(FSFW_BUILD_UNITTESTS) From a569990ca2683c537acb88b4866962e57f9a054c Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 22 Apr 2022 14:50:50 +0200 Subject: [PATCH 37/52] fix tests --- tests/src/fsfw_tests/unit/version.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/src/fsfw_tests/unit/version.cpp b/tests/src/fsfw_tests/unit/version.cpp index 2967dfa5..f9170a4d 100644 --- a/tests/src/fsfw_tests/unit/version.cpp +++ b/tests/src/fsfw_tests/unit/version.cpp @@ -10,12 +10,12 @@ TEST_CASE("Version API Tests", "[TestVersionAPI]") { // Check that major version is non-zero REQUIRE(fsfw::FSFW_VERSION.major > 0); uint32_t fsfwMajor = fsfw::FSFW_VERSION.major; - REQUIRE(fsfw::Version(255, 0, 0) > fsfw::FSFW_VERSION); - REQUIRE(fsfw::Version(255, 0, 0) >= fsfw::FSFW_VERSION); - REQUIRE(fsfw::Version(0, 0, 0) < fsfw::FSFW_VERSION); - REQUIRE(fsfw::Version(0, 0, 0) <= fsfw::FSFW_VERSION); - fsfw::Version v1 = fsfw::Version(1, 1, 1); - fsfw::Version v2 = fsfw::Version(1, 1, 1); + REQUIRE(Version(255, 0, 0) > fsfw::FSFW_VERSION); + REQUIRE(Version(255, 0, 0) >= fsfw::FSFW_VERSION); + REQUIRE(Version(0, 0, 0) < fsfw::FSFW_VERSION); + REQUIRE(Version(0, 0, 0) <= fsfw::FSFW_VERSION); + Version v1 = fsfw::Version(1, 1, 1); + Version v2 = fsfw::Version(1, 1, 1); REQUIRE(v1 == v2); REQUIRE(not(v1 < v2)); REQUIRE(not(v1 > v2)); From 4079edc80e57bd29394b28b7d0119367960b3fff Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 22 Apr 2022 14:52:55 +0200 Subject: [PATCH 38/52] update changelog --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 85f6ef28..975375f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,18 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - `oneShotAction` flag in the `TestTask` class is not static anymore - HAL Linux Uart: Baudrate and bits per word are enums now, avoiding misconfigurations PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/585 +- Major update for version handling, using `git describe` to fetch version information with git. + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/601 + - Place `Version` class outside of `fsfw` namespace. It is generic + - Add helper functions provided by [`cmake-modules`](https://github.com/bilke/cmake-modules) manually now. Those should not change too often and only a small subset is needed + - Separate folder for easier update and for distintion + - LICENSE file included + - use `int` for version numbers to allow unset or uninitialized version + - Initialize Version object with numbers set to -1 + - Instead of hardcoding the git hash, it is now retrieved from git + - `Version` now allows specifying additional version information like the git SHA1 hash and the versions since the last tag + - Additional information is set to the last part of the git describe output for `FSFW_VERSION` now. + - Version still need to be hand-updated if the FSFW is not included as a submodule for now. ## Removed From 539e01deee7df2c0f3cf220b77eb29b80ec92cb8 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 22 Apr 2022 14:53:12 +0200 Subject: [PATCH 39/52] minor form change --- CHANGELOG.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 975375f2..8badeea4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,13 +27,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Major update for version handling, using `git describe` to fetch version information with git. PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/601 - Place `Version` class outside of `fsfw` namespace. It is generic - - Add helper functions provided by [`cmake-modules`](https://github.com/bilke/cmake-modules) manually now. Those should not change too often and only a small subset is needed + - Add helper functions provided by [`cmake-modules`](https://github.com/bilke/cmake-modules) + manually now. Those should not change too often and only a small subset is needed - Separate folder for easier update and for distintion - LICENSE file included - use `int` for version numbers to allow unset or uninitialized version - Initialize Version object with numbers set to -1 - Instead of hardcoding the git hash, it is now retrieved from git - - `Version` now allows specifying additional version information like the git SHA1 hash and the versions since the last tag + - `Version` now allows specifying additional version information like the git SHA1 hash and the + versions since the last tag - Additional information is set to the last part of the git describe output for `FSFW_VERSION` now. - Version still need to be hand-updated if the FSFW is not included as a submodule for now. From 750369b0a6ddae3d301054dd6c91a79db27e5acc Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 22 Apr 2022 14:55:17 +0200 Subject: [PATCH 40/52] small addition and possible fix --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9066cec2..5d401046 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,7 +48,8 @@ project(${LIB_FSFW_NAME}) add_library(${LIB_FSFW_NAME}) # Version handling -if(EXISTS .git) +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git) + message(STATUS "${MSG_PREFIX} Determining version information with git") include(helpers) determine_version_with_git("--exclude" "docker_*") set(FSFW_GIT_INFO ${GIT_INFO} CACHE STRING "Version information retrieved with git describe") From cccdced74dec589b8566c641a599f978844864c1 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 22 Apr 2022 15:00:04 +0200 Subject: [PATCH 41/52] unique helper file name --- CMakeLists.txt | 2 +- cmake/{helpers.cmake => FsfwHelpers.cmake} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename cmake/{helpers.cmake => FsfwHelpers.cmake} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5d401046..3dc3a16a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,7 +50,7 @@ add_library(${LIB_FSFW_NAME}) # Version handling if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git) message(STATUS "${MSG_PREFIX} Determining version information with git") - include(helpers) + include(FsfwHelpers) determine_version_with_git("--exclude" "docker_*") set(FSFW_GIT_INFO ${GIT_INFO} CACHE STRING "Version information retrieved with git describe") list(GET FSFW_GIT_INFO 1 FSFW_VERSION) diff --git a/cmake/helpers.cmake b/cmake/FsfwHelpers.cmake similarity index 100% rename from cmake/helpers.cmake rename to cmake/FsfwHelpers.cmake From 617d41c7d5e709e07e59decb93a0b469d1c9337d Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 22 Apr 2022 15:08:16 +0200 Subject: [PATCH 42/52] maybe this fixed CI/CD issues --- CMakeLists.txt | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3dc3a16a..ead7f531 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,26 +47,33 @@ set(FSFW_DUMMY_TGT fsfw-dummy) project(${LIB_FSFW_NAME}) add_library(${LIB_FSFW_NAME}) +set(FSFW_GIT_VER_HANDLING_OK FALSE) # Version handling if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git) message(STATUS "${MSG_PREFIX} Determining version information with git") include(FsfwHelpers) determine_version_with_git("--exclude" "docker_*") - set(FSFW_GIT_INFO ${GIT_INFO} CACHE STRING "Version information retrieved with git describe") - list(GET FSFW_GIT_INFO 1 FSFW_VERSION) - list(GET FSFW_GIT_INFO 2 FSFW_SUBVERSION) - list(GET FSFW_GIT_INFO 3 FSFW_REVISION) - list(GET FSFW_GIT_INFO 4 FSFW_VERSION_CST_GIT_SHA1) - if(NOT FSFW_VERSION) - set(FSFW_VERSION ${FSFW_VERSION_IF_GIT_FAILS}) - endif() - if(NOT FSFW_SUBVERSION) - set(FSFW_SUBVERSION ${FSFW_SUBVERSION_IF_GIT_FAILS}) - endif() - if(NOT FSFW_REVISION) - set(FSFW_REVISION ${FSFW_REVISION_IF_GIT_FAILS}) - endif() -else() + if(GIT_INFO) + set(FSFW_GIT_INFO ${GIT_INFO} CACHE STRING "Version information retrieved with git describe") + list(GET FSFW_GIT_INFO 1 FSFW_VERSION) + list(GET FSFW_GIT_INFO 2 FSFW_SUBVERSION) + list(GET FSFW_GIT_INFO 3 FSFW_REVISION) + list(GET FSFW_GIT_INFO 4 FSFW_VERSION_CST_GIT_SHA1) + if(NOT FSFW_VERSION) + set(FSFW_VERSION ${FSFW_VERSION_IF_GIT_FAILS}) + endif() + if(NOT FSFW_SUBVERSION) + set(FSFW_SUBVERSION ${FSFW_SUBVERSION_IF_GIT_FAILS}) + endif() + if(NOT FSFW_REVISION) + set(FSFW_REVISION ${FSFW_REVISION_IF_GIT_FAILS}) + endif() + set(FSFW_GIT_VER_HANDLING_OK TRUE) + else() + set(FSFW_GIT_VER_HANDLING_OK FALSE) + endif() +endif() +if(NOT FSFW_GIT_VER_HANDLING_OK) set(FSFW_VERSION ${FSFW_VERSION_IF_GIT_FAILS}) set(FSFW_SUBVERSION ${FSFW_SUBVERSION_IF_GIT_FAILS}) set(FSFW_REVISION ${FSFW_REVISION_IF_GIT_FAILS}) From 85e849ca002d594bb5d68b037f139e9a6630d32d Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 22 Apr 2022 15:10:08 +0200 Subject: [PATCH 43/52] small remaining fix --- tests/src/fsfw_tests/unit/version.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/src/fsfw_tests/unit/version.cpp b/tests/src/fsfw_tests/unit/version.cpp index f9170a4d..a95c1ea9 100644 --- a/tests/src/fsfw_tests/unit/version.cpp +++ b/tests/src/fsfw_tests/unit/version.cpp @@ -14,8 +14,8 @@ TEST_CASE("Version API Tests", "[TestVersionAPI]") { REQUIRE(Version(255, 0, 0) >= fsfw::FSFW_VERSION); REQUIRE(Version(0, 0, 0) < fsfw::FSFW_VERSION); REQUIRE(Version(0, 0, 0) <= fsfw::FSFW_VERSION); - Version v1 = fsfw::Version(1, 1, 1); - Version v2 = fsfw::Version(1, 1, 1); + Version v1 = Version(1, 1, 1); + Version v2 = Version(1, 1, 1); REQUIRE(v1 == v2); REQUIRE(not(v1 < v2)); REQUIRE(not(v1 > v2)); From 68231db9a1dd6d1de153b2ecb03e911f05a1a4ec Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 22 Apr 2022 15:37:14 +0200 Subject: [PATCH 44/52] changelog typo --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8badeea4..3907c5b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,7 +29,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Place `Version` class outside of `fsfw` namespace. It is generic - Add helper functions provided by [`cmake-modules`](https://github.com/bilke/cmake-modules) manually now. Those should not change too often and only a small subset is needed - - Separate folder for easier update and for distintion + - Separate folder for easier update and for distinction - LICENSE file included - use `int` for version numbers to allow unset or uninitialized version - Initialize Version object with numbers set to -1 From 18f99583321c2e0726e7e65573cb985b8999f197 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 22 Apr 2022 15:39:44 +0200 Subject: [PATCH 45/52] add git CST and sha info to version ctor --- src/fsfw/FSFWVersion.h.in | 3 ++- src/fsfw/version.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/fsfw/FSFWVersion.h.in b/src/fsfw/FSFWVersion.h.in index 79d1f130..3b93bee5 100644 --- a/src/fsfw/FSFWVersion.h.in +++ b/src/fsfw/FSFWVersion.h.in @@ -1,10 +1,11 @@ #ifndef FSFW_VERSION_H_ #define FSFW_VERSION_H_ -// Versioning is kept in project CMakeLists.txt file +// Versioning is managed in project CMakeLists.txt file static constexpr int FSFW_VERSION_MAJOR = @FSFW_VERSION@; static constexpr int FSFW_VERSION_MINOR = @FSFW_SUBVERSION@; static constexpr int FSFW_VERSION_REVISION = @FSFW_REVISION@; +// Also contains CST (Commits since tag) information static const char FSFW_VERSION_CST_GIT_SHA1[] = "@FSFW_VERSION_CST_GIT_SHA1@"; #endif /* FSFW_VERSION_H_ */ diff --git a/src/fsfw/version.cpp b/src/fsfw/version.cpp index 7355fc1d..0b2ee60c 100644 --- a/src/fsfw/version.cpp +++ b/src/fsfw/version.cpp @@ -12,7 +12,8 @@ #undef minor #endif -const Version fsfw::FSFW_VERSION = {FSFW_VERSION_MAJOR, FSFW_VERSION_MINOR, FSFW_VERSION_REVISION}; +const Version fsfw::FSFW_VERSION = {FSFW_VERSION_MAJOR, FSFW_VERSION_MINOR, FSFW_VERSION_REVISION, + FSFW_VERSION_CST_GIT_SHA1}; Version::Version(int major, int minor, int revision, const char* addInfo) : major(major), minor(minor), revision(revision), addInfo(addInfo) {} From 29015b340b66ffd84dfae9755219fcc96be9af15 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 25 Apr 2022 15:10:50 +0200 Subject: [PATCH 46/52] update changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2091ed75..87927357 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/). creation call. It allows passing context information and an arbitrary user argument into the message queue. Also streamlined and simplified `MessageQueue` implementation for all OSALs PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/583 +- Clock: + - `timeval` to `TimeOfDay_t` + - Added Mutex for gmtime calls: (compare http://www.opengate.at/blog/2020/01/timeless/) + - Moved the statics used by Clock in ClockCommon.cpp to this file + - Better check for leap seconds + - Added Unittests for Clock (only getter) ## Removed From 1739edd9b07933ddbdfcbfd19cf98146815ebe3f Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 26 Apr 2022 10:32:37 +0200 Subject: [PATCH 47/52] warning fix for modern compilers --- src/fsfw/globalfunctions/DleParser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fsfw/globalfunctions/DleParser.cpp b/src/fsfw/globalfunctions/DleParser.cpp index b68dbde1..71da7e6a 100644 --- a/src/fsfw/globalfunctions/DleParser.cpp +++ b/src/fsfw/globalfunctions/DleParser.cpp @@ -187,7 +187,7 @@ void DleParser::defaultErrorHandler(ErrorTypes err, ErrorInfo ctx) { case (ErrorTypes::ENCODED_BUF_TOO_SMALL): case (ErrorTypes::DECODING_BUF_TOO_SMALL): { char opt[64]; - snprintf(opt, sizeof(opt), ": Too small for packet with length %d", ctx.len); + snprintf(opt, sizeof(opt), ": Too small for packet with length %zu", ctx.len); if (err == ErrorTypes::ENCODED_BUF_TOO_SMALL) { errorPrinter("Encoded buf too small", opt); } else { From 3d047f9629c3a6fe25514f92dd008bd34d0784dd Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 26 Apr 2022 11:15:24 +0200 Subject: [PATCH 48/52] trying to export ETL lib --- CMakeLists.txt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3cc1671c..003b9723 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ set(MSG_PREFIX "fsfw |") set(FSFW_ETL_LIB_MAJOR_VERSION 20 CACHE STRING "ETL library major version requirement" ) -set(FSFW_ETL_LIB_VERSION ${FSFW_ETL_LIB_MAJOR_VERSION}.27.2 CACHE STRING +set(FSFW_ETL_LIB_VERSION ${FSFW_ETL_LIB_MAJOR_VERSION}.27.3 CACHE STRING "ETL library exact version requirement" ) @@ -132,7 +132,7 @@ if(FSFW_BUILD_UNITTESTS) endif() endif() -message(STATUS "Finding and/or providing ETL library") +message(STATUS "Finding and/or providing ETL library with version ${FSFW_ETL_LIB_MAJOR_VERSION}") # Check whether the user has already installed ETL first find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} QUIET) @@ -153,6 +153,11 @@ if(NOT ${FSFW_ETL_LIB_NAME}_FOUND) FetchContent_MakeAvailable(etl) endif() +export(EXPORT etl + FILE "${CMAKE_CURRENT_BINARY_DIR}/cmake/etl.cmake" + NAMESPACE fsfw:: +) + set(FSFW_CORE_INC_PATH "inc") set_property(CACHE FSFW_OSAL PROPERTY STRINGS host linux rtems freertos) From 6a8da303fbfb9dd9c0178b0b68d1d08ab1880d49 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 26 Apr 2022 14:06:30 +0200 Subject: [PATCH 49/52] exporting etl target --- CMakeLists.txt | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 003b9723..e5b945f4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -153,10 +153,18 @@ if(NOT ${FSFW_ETL_LIB_NAME}_FOUND) FetchContent_MakeAvailable(etl) endif() -export(EXPORT etl - FILE "${CMAKE_CURRENT_BINARY_DIR}/cmake/etl.cmake" - NAMESPACE fsfw:: +# Export the ETL library and make it available in the fsfw namespace. This allows user code +# to use the same ETL dependency the framework is using +# You can do this by using the two following directives +# include(fsfw-etl) +# target_link_libraries(${TARGET_NAME} PRIVATE fsfw::etl) +export( + TARGETS ${FSFW_ETL_LIB_NAME} + FILE "${CMAKE_CURRENT_BINARY_DIR}/cmake/fsfw-etl.cmake" + NAMESPACE fsfw:: ) +# Append the export directory to the module path +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_BINARY_DIR}/cmake") set(FSFW_CORE_INC_PATH "inc") From c5a7b98a7dc7c53b5dffbbcf2869c05be29a1208 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 26 Apr 2022 16:24:14 +0200 Subject: [PATCH 50/52] name correction --- CMakeLists.txt | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e5b945f4..25d9bb93 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -132,14 +132,14 @@ if(FSFW_BUILD_UNITTESTS) endif() endif() -message(STATUS "Finding and/or providing ETL library with version ${FSFW_ETL_LIB_MAJOR_VERSION}") +message(STATUS "Finding and/or providing etl library with version ${FSFW_ETL_LIB_MAJOR_VERSION}") # Check whether the user has already installed ETL first find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} QUIET) # Not installed, so use FetchContent to download and provide etl if(NOT ${FSFW_ETL_LIB_NAME}_FOUND) message(STATUS - "No ETL installation was found with find_package. Installing and providing " + "No etl installation was found with find_package. Installing and providing " "etl with FindPackage" ) include(FetchContent) @@ -153,19 +153,6 @@ if(NOT ${FSFW_ETL_LIB_NAME}_FOUND) FetchContent_MakeAvailable(etl) endif() -# Export the ETL library and make it available in the fsfw namespace. This allows user code -# to use the same ETL dependency the framework is using -# You can do this by using the two following directives -# include(fsfw-etl) -# target_link_libraries(${TARGET_NAME} PRIVATE fsfw::etl) -export( - TARGETS ${FSFW_ETL_LIB_NAME} - FILE "${CMAKE_CURRENT_BINARY_DIR}/cmake/fsfw-etl.cmake" - NAMESPACE fsfw:: -) -# Append the export directory to the module path -list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_BINARY_DIR}/cmake") - set(FSFW_CORE_INC_PATH "inc") set_property(CACHE FSFW_OSAL PROPERTY STRINGS host linux rtems freertos) From ec2e274f22e3e254469abc9819bc906f03fe590a Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 26 Apr 2022 16:31:45 +0200 Subject: [PATCH 51/52] find_package call for Catch2 quiet --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 25d9bb93..2354f504 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -98,7 +98,7 @@ endif() if(FSFW_BUILD_UNITTESTS) message(STATUS "${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") From c1be1fe2320eed167e808eecf3e582c87b688cde Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 26 Apr 2022 20:06:26 +0200 Subject: [PATCH 52/52] update CMakeLists.txt etl handling --- CMakeLists.txt | 34 +++++++++---------- .../devicehandlers/MgmLIS3MDLHandler.cpp | 2 +- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2354f504..337a56f4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,5 @@ cmake_minimum_required(VERSION 3.13) +project(${LIB_FSFW_NAME}) set(FSFW_VERSION_IF_GIT_FAILS 4) set(FSFW_SUBVERSION_IF_GIT_FAILS 0) @@ -60,7 +61,6 @@ set(LIB_FSFW_NAME fsfw) set(FSFW_TEST_TGT fsfw-tests) set(FSFW_DUMMY_TGT fsfw-dummy) -project(${LIB_FSFW_NAME}) add_library(${LIB_FSFW_NAME}) set(FSFW_GIT_VER_HANDLING_OK FALSE) @@ -98,7 +98,7 @@ endif() if(FSFW_BUILD_UNITTESTS) message(STATUS "${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} QUIET) + find_package(Catch2 ${FSFW_CATCH2_LIB_MAJOR_VERSION} CONFIG 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") @@ -135,23 +135,23 @@ endif() message(STATUS "Finding and/or providing etl library with version ${FSFW_ETL_LIB_MAJOR_VERSION}") # Check whether the user has already installed ETL first -find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} QUIET) +# find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} CONFIG QUIET) # Not installed, so use FetchContent to download and provide etl -if(NOT ${FSFW_ETL_LIB_NAME}_FOUND) - message(STATUS - "No etl installation was found with find_package. Installing and providing " - "etl with FindPackage" - ) - include(FetchContent) +# if(NOT ${FSFW_ETL_LIB_NAME}_FOUND) +message(STATUS + "No etl installation was found with find_package. Installing and providing " + "etl with FetchContent" +) +include(FetchContent) - FetchContent_Declare( - ${FSFW_ETL_LIB_NAME} - GIT_REPOSITORY https://github.com/ETLCPP/etl - GIT_TAG ${FSFW_ETL_LIB_VERSION} - ) +FetchContent_Declare( + ${FSFW_ETL_LIB_NAME} + GIT_REPOSITORY https://github.com/ETLCPP/etl + GIT_TAG ${FSFW_ETL_LIB_VERSION} +) - FetchContent_MakeAvailable(etl) -endif() +FetchContent_MakeAvailable(${FSFW_ETL_LIB_NAME}) +# endif() set(FSFW_CORE_INC_PATH "inc") @@ -414,7 +414,7 @@ target_compile_options(${LIB_FSFW_NAME} PRIVATE ) target_link_libraries(${LIB_FSFW_NAME} PRIVATE - ${FSFW_ETL_LIB_NAME} + etl ${FSFW_ADDITIONAL_LINK_LIBS} ) diff --git a/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp b/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp index a887934d..a13ae791 100644 --- a/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp +++ b/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp @@ -375,7 +375,7 @@ float MgmLIS3MDLHandler::getSensitivityFactor(MGMLIS3MDL::Sensitivies sens) { ReturnValue_t MgmLIS3MDLHandler::enableTemperatureSensor(const uint8_t *commandData, size_t commandDataLen) { - if(commandData == nullptr) { + if (commandData == nullptr) { return INVALID_COMMAND_PARAMETER; } triggerEvent(CHANGE_OF_SETUP_PARAMETER);