diff --git a/.clang-tidy b/.clang-tidy index 34f35c27..86780767 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -65,6 +65,8 @@ CheckOptions: value: '' - key: 'cppcoreguidelines-narrowing-conversions.PedanticMode' value: 'true' + - key: 'cppcoreguidelines-pro-type-member-init.UseAssignment' + value: 'true' - key: 'readability-else-after-return.WarnOnUnfixable' value: 'true' - key: 'readability-else-after-return.WarnOnConditionVariables' diff --git a/CMakeLists.txt b/CMakeLists.txt index e7e7cc72..c1379d06 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,7 @@ add_library(Sts1CobcSw_Outcome INTERFACE) add_library(Sts1CobcSw_ProgramId INTERFACE) add_library(Sts1CobcSw_Periphery STATIC) add_library(Sts1CobcSw_Serial INTERFACE) +add_library(Sts1CobcSw_Telemetry STATIC) add_library(Sts1CobcSw_Utility STATIC) add_program(HelloDummy) diff --git a/Sts1CobcSw/CMakeLists.txt b/Sts1CobcSw/CMakeLists.txt index 128f09e9..87581307 100644 --- a/Sts1CobcSw/CMakeLists.txt +++ b/Sts1CobcSw/CMakeLists.txt @@ -5,6 +5,7 @@ add_subdirectory(Hal) add_subdirectory(Outcome) add_subdirectory(Periphery) add_subdirectory(Serial) +add_subdirectory(Telemetry) add_subdirectory(Utility) add_subdirectory(CobcSoftware) diff --git a/Sts1CobcSw/CobcSoftware/CommandParser.hpp b/Sts1CobcSw/CobcSoftware/CommandParser.hpp index ad10e115..2682b8a2 100644 --- a/Sts1CobcSw/CobcSoftware/CommandParser.hpp +++ b/Sts1CobcSw/CobcSoftware/CommandParser.hpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/Sts1CobcSw/CobcSoftware/EduProgramQueueThread.cpp b/Sts1CobcSw/CobcSoftware/EduProgramQueueThread.cpp index 43034c28..f7c759b7 100644 --- a/Sts1CobcSw/CobcSoftware/EduProgramQueueThread.cpp +++ b/Sts1CobcSw/CobcSoftware/EduProgramQueueThread.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include diff --git a/Sts1CobcSw/CobcSoftware/TopicsAndSubscribers.cpp b/Sts1CobcSw/CobcSoftware/TopicsAndSubscribers.cpp index c437baf9..3d5bface 100644 --- a/Sts1CobcSw/CobcSoftware/TopicsAndSubscribers.cpp +++ b/Sts1CobcSw/CobcSoftware/TopicsAndSubscribers.cpp @@ -9,6 +9,7 @@ RODOS::Topic eduIsAliveTopic(-1, "eduIsAliveTopic"); RODOS::CommBuffer eduIsAliveBufferForPowerManagement{}; RODOS::CommBuffer eduIsAliveBufferForCommunicationError{}; RODOS::CommBuffer eduIsAliveBufferForListener{}; +RODOS::CommBuffer eduIsAliveBufferForTelemetry{}; RODOS::Subscriber eduIsAliveSubscriberForPowerManagement(eduIsAliveTopic, eduIsAliveBufferForPowerManagement, @@ -19,6 +20,9 @@ RODOS::Subscriber eduIsAliveSubscriberForCommunicationError(eduIsAliveTopic, RODOS::Subscriber eduIsAliveSubscriberForListener(eduIsAliveTopic, eduIsAliveBufferForListener, "eduIsAliveSubscriber"); +RODOS::Subscriber eduIsAliveSubscriberForTelemetry(eduIsAliveTopic, + eduIsAliveBufferForListener, + "eduIsAliveSubscriber"); RODOS::Topic nextProgramStartDelayTopic(-1, "nextProgramStartDelayTopic"); RODOS::CommBuffer nextProgramStartDelayBuffer{}; diff --git a/Sts1CobcSw/CobcSoftware/TopicsAndSubscribers.hpp b/Sts1CobcSw/CobcSoftware/TopicsAndSubscribers.hpp index 81cb9686..04bc782c 100644 --- a/Sts1CobcSw/CobcSoftware/TopicsAndSubscribers.hpp +++ b/Sts1CobcSw/CobcSoftware/TopicsAndSubscribers.hpp @@ -14,6 +14,7 @@ extern RODOS::Topic eduIsAliveTopic; extern RODOS::CommBuffer eduIsAliveBufferForListener; extern RODOS::CommBuffer eduIsAliveBufferForPowerManagement; extern RODOS::CommBuffer eduIsAliveBufferForCommunicationError; +extern RODOS::CommBuffer eduIsAliveBufferForTelemetry; extern RODOS::Topic nextProgramStartDelayTopic; extern RODOS::CommBuffer nextProgramStartDelayBuffer; } diff --git a/Sts1CobcSw/Edu/CMakeLists.txt b/Sts1CobcSw/Edu/CMakeLists.txt index de6691da..36bb5b13 100644 --- a/Sts1CobcSw/Edu/CMakeLists.txt +++ b/Sts1CobcSw/Edu/CMakeLists.txt @@ -1,4 +1,4 @@ -target_sources(Sts1CobcSw_Edu PRIVATE ProgramQueue.cpp ProgramStatusHistory.cpp) +target_sources(Sts1CobcSw_Edu PRIVATE ProgramStatusHistory.cpp) target_link_libraries( Sts1CobcSw_Edu PUBLIC rodos::without_main_on_linux etl::etl Sts1CobcSw_FramSections Sts1CobcSw_Outcome Sts1CobcSw_ProgramId Sts1CobcSw_Serial diff --git a/Sts1CobcSw/Edu/ProgramQueue.cpp b/Sts1CobcSw/Edu/ProgramQueue.cpp deleted file mode 100644 index e91bb395..00000000 --- a/Sts1CobcSw/Edu/ProgramQueue.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include - - -namespace sts1cobcsw::edu -{ -using sts1cobcsw::DeserializeFrom; -using sts1cobcsw::SerializeTo; - - -sts1cobcsw:: - FramVector(), nCachedProgramQueueEntries> - programQueue; - - -template -auto DeserializeFrom(void const * source, ProgramQueueEntry * data) -> void const * -{ - source = DeserializeFrom(source, &(data->programId)); - source = DeserializeFrom(source, &(data->startTime)); - source = DeserializeFrom(source, &(data->timeout)); - return source; -} - - -// Explicit template specializations to keep everything in .cpp file -template auto DeserializeFrom(void const *, ProgramQueueEntry *) -> void const *; -template auto DeserializeFrom(void const *, ProgramQueueEntry *) - -> void const *; - - -template -auto SerializeTo(void * destination, ProgramQueueEntry const & data) -> void * -{ - destination = SerializeTo(destination, data.programId); - destination = SerializeTo(destination, data.startTime); - destination = SerializeTo(destination, data.timeout); - return destination; -} - - -// Explicit template specializations to keep everything in .cpp file -template auto SerializeTo(void *, ProgramQueueEntry const &) -> void *; -template auto SerializeTo(void *, ProgramQueueEntry const &) -> void *; -} diff --git a/Sts1CobcSw/Edu/ProgramQueue.hpp b/Sts1CobcSw/Edu/ProgramQueue.hpp index 3c111230..763df454 100644 --- a/Sts1CobcSw/Edu/ProgramQueue.hpp +++ b/Sts1CobcSw/Edu/ProgramQueue.hpp @@ -1,50 +1,16 @@ #pragma once +#include #include #include #include -#include -#include -#include -#include -#include -#include - -namespace sts1cobcsw -{ -namespace edu -{ -struct ProgramQueueEntry -{ - ProgramId programId = ProgramId(0); - RealTime startTime = RealTime(0); - std::int16_t timeout = 0; -}; -} - - -template<> -inline constexpr std::size_t serialSize = - totalSerialSize; - - -namespace edu +namespace sts1cobcsw::edu { inline constexpr auto nCachedProgramQueueEntries = 10; -extern FramVector(), - nCachedProgramQueueEntries> - programQueue; - - -template -[[nodiscard]] auto DeserializeFrom(void const * source, ProgramQueueEntry * data) -> void const *; -template -[[nodiscard]] auto SerializeTo(void * destination, ProgramQueueEntry const & data) -> void *; -} +inline constexpr auto programQueue = FramVector(), + nCachedProgramQueueEntries>{}; } diff --git a/Sts1CobcSw/Edu/ProgramStatusHistory.cpp b/Sts1CobcSw/Edu/ProgramStatusHistory.cpp index 325ffca2..30c70b15 100644 --- a/Sts1CobcSw/Edu/ProgramStatusHistory.cpp +++ b/Sts1CobcSw/Edu/ProgramStatusHistory.cpp @@ -7,16 +7,6 @@ namespace sts1cobcsw::edu { -using sts1cobcsw::DeserializeFrom; -using sts1cobcsw::SerializeTo; - - -sts1cobcsw::FramRingArray(), - nCachedProgramStatusHistoryEntries> - programStatusHistory; - - auto UpdateProgramStatusHistory(ProgramId programId, RealTime startTime, ProgramStatus newStatus) -> void { @@ -25,32 +15,4 @@ auto UpdateProgramStatusHistory(ProgramId programId, RealTime startTime, Program { return entry.programId == programId and entry.startTime == startTime; }, ProgramStatusHistoryEntry{programId, startTime, newStatus}); } - - -template -auto DeserializeFrom(void const * source, ProgramStatusHistoryEntry * data) -> void const * -{ - source = DeserializeFrom(source, &(data->programId)); - source = DeserializeFrom(source, &(data->startTime)); - source = DeserializeFrom(source, &(data->status)); - return source; -} - - -template -auto SerializeTo(void * destination, ProgramStatusHistoryEntry const & data) -> void * -{ - destination = SerializeTo(destination, data.programId); - destination = SerializeTo(destination, data.startTime); - destination = SerializeTo(destination, data.status); - return destination; -} - - -template auto DeserializeFrom(void const *, ProgramStatusHistoryEntry *) - -> void const *; -template auto DeserializeFrom(void const *, ProgramStatusHistoryEntry *) - -> void const *; -template auto SerializeTo(void *, ProgramStatusHistoryEntry const &) -> void *; -template auto SerializeTo(void *, ProgramStatusHistoryEntry const &) -> void *; } diff --git a/Sts1CobcSw/Edu/ProgramStatusHistory.hpp b/Sts1CobcSw/Edu/ProgramStatusHistory.hpp index 35be9d6d..bce717be 100644 --- a/Sts1CobcSw/Edu/ProgramStatusHistory.hpp +++ b/Sts1CobcSw/Edu/ProgramStatusHistory.hpp @@ -1,68 +1,23 @@ #pragma once +#include #include #include #include #include -#include #include -#include -#include -#include - -namespace sts1cobcsw -{ -namespace edu -{ -enum class ProgramStatus : std::uint8_t -{ - programRunning, - programCouldNotBeStarted, - programExecutionFailed, - programExecutionSucceeded, - resultFileTransfered, - resultFileSentToRf, - ackFromGround, - resultFileDeleted -}; - - -struct ProgramStatusHistoryEntry -{ - ProgramId programId = ProgramId(0); - RealTime startTime = RealTime(0); - ProgramStatus status = ProgramStatus::programRunning; -}; -} - - -template<> -inline constexpr std::size_t serialSize = - totalSerialSize; - - -namespace edu +namespace sts1cobcsw::edu { inline constexpr auto nCachedProgramStatusHistoryEntries = 10; -extern FramRingArray(), - nCachedProgramStatusHistoryEntries> - programStatusHistory; +inline constexpr auto programStatusHistory = + FramRingArray(), + nCachedProgramStatusHistoryEntries>{}; auto UpdateProgramStatusHistory(ProgramId programId, RealTime startTime, ProgramStatus newStatus) -> void; - -template -[[nodiscard]] auto DeserializeFrom(void const * source, ProgramStatusHistoryEntry * data) - -> void const *; -template -[[nodiscard]] auto SerializeTo(void * destination, ProgramStatusHistoryEntry const & data) - -> void *; -} } diff --git a/Sts1CobcSw/Edu/Types.hpp b/Sts1CobcSw/Edu/Types.hpp index 98e635a5..64cc5f2a 100644 --- a/Sts1CobcSw/Edu/Types.hpp +++ b/Sts1CobcSw/Edu/Types.hpp @@ -32,6 +32,19 @@ enum class ErrorCode }; +enum class ProgramStatus : std::uint8_t +{ + programRunning, + programCouldNotBeStarted, + programExecutionFailed, + programExecutionSucceeded, + resultFileTransfered, + resultFileSentToRf, + ackFromGround, + resultFileDeleted +}; + + enum class StatusType { noEvent, @@ -41,6 +54,22 @@ enum class StatusType }; +struct ProgramQueueEntry +{ + ProgramId programId = ProgramId(0); + RealTime startTime = RealTime(0); + std::int16_t timeout = 0; +}; + + +struct ProgramStatusHistoryEntry +{ + ProgramId programId = ProgramId(0); + RealTime startTime = RealTime(0); + ProgramStatus status = ProgramStatus::programRunning; +}; + + struct StoreProgramData { static constexpr auto id = 0x01_b; @@ -124,6 +153,18 @@ struct ResultInfo } +template<> +inline constexpr std::size_t serialSize = + totalSerialSize; + +template<> +inline constexpr std::size_t serialSize = + totalSerialSize; + template<> inline constexpr std::size_t serialSize = totalSerialSize = namespace edu { template +[[nodiscard]] auto SerializeTo(void * destination, ProgramQueueEntry const & data) -> void *; +template +[[nodiscard]] auto SerializeTo(void * destination, ProgramStatusHistoryEntry const & data) + -> void *; +template [[nodiscard]] auto SerializeTo(void * destination, StoreProgramData const & data) -> void *; template [[nodiscard]] auto SerializeTo(void * destination, ExecuteProgramData const & data) -> void *; @@ -187,6 +233,11 @@ template template [[nodiscard]] auto SerializeTo(void * destination, UpdateTimeData const & data) -> void *; +template +[[nodiscard]] auto DeserializeFrom(void const * source, ProgramQueueEntry * data) -> void const *; +template +[[nodiscard]] auto DeserializeFrom(void const * source, ProgramStatusHistoryEntry * data) + -> void const *; template [[nodiscard]] auto DeserializeFrom(void const * source, NoEventData * data) -> void const *; template diff --git a/Sts1CobcSw/Edu/Types.ipp b/Sts1CobcSw/Edu/Types.ipp index a2711b15..9cbed356 100644 --- a/Sts1CobcSw/Edu/Types.ipp +++ b/Sts1CobcSw/Edu/Types.ipp @@ -6,13 +6,35 @@ namespace sts1cobcsw::edu { -using sts1cobcsw::DeserializeFrom; -using sts1cobcsw::SerializeTo; +template +auto SerializeTo(void * destination, ProgramQueueEntry const & data) -> void * +{ + using sts1cobcsw::SerializeTo; + + destination = SerializeTo(destination, data.programId); + destination = SerializeTo(destination, data.startTime); + destination = SerializeTo(destination, data.timeout); + return destination; +} + + +template +auto SerializeTo(void * destination, ProgramStatusHistoryEntry const & data) -> void * +{ + using sts1cobcsw::SerializeTo; + + destination = SerializeTo(destination, data.programId); + destination = SerializeTo(destination, data.startTime); + destination = SerializeTo(destination, data.status); + return destination; +} template auto SerializeTo(void * destination, StoreProgramData const & data) -> void * { + using sts1cobcsw::SerializeTo; + destination = SerializeTo(destination, StoreProgramData::id); destination = SerializeTo(destination, data.programId); return destination; @@ -22,6 +44,8 @@ auto SerializeTo(void * destination, StoreProgramData const & data) -> void * template auto SerializeTo(void * destination, ExecuteProgramData const & data) -> void * { + using sts1cobcsw::SerializeTo; + destination = SerializeTo(destination, ExecuteProgramData::id); destination = SerializeTo(destination, data.programId); destination = SerializeTo(destination, data.startTime); @@ -33,6 +57,8 @@ auto SerializeTo(void * destination, ExecuteProgramData const & data) -> void * template auto SerializeTo(void * destination, [[maybe_unused]] StopProgramData const & data) -> void * { + using sts1cobcsw::SerializeTo; + destination = SerializeTo(destination, StopProgramData::id); return destination; } @@ -41,6 +67,8 @@ auto SerializeTo(void * destination, [[maybe_unused]] StopProgramData const & da template auto SerializeTo(void * destination, [[maybe_unused]] GetStatusData const & data) -> void * { + using sts1cobcsw::SerializeTo; + destination = SerializeTo(destination, GetStatusData::id); return destination; } @@ -49,6 +77,8 @@ auto SerializeTo(void * destination, [[maybe_unused]] GetStatusData const & data template auto SerializeTo(void * destination, ReturnResultData const & data) -> void * { + using sts1cobcsw::SerializeTo; + destination = SerializeTo(destination, ReturnResultData::id); destination = SerializeTo(destination, data.programId); destination = SerializeTo(destination, data.startTime); @@ -59,15 +89,43 @@ auto SerializeTo(void * destination, ReturnResultData const & data) -> void * template auto SerializeTo(void * destination, UpdateTimeData const & data) -> void * { + using sts1cobcsw::SerializeTo; + destination = SerializeTo(destination, UpdateTimeData::id); destination = SerializeTo(destination, data.currentTime); return destination; } +template +auto DeserializeFrom(void const * source, ProgramQueueEntry * data) -> void const * +{ + using sts1cobcsw::DeserializeFrom; + + source = DeserializeFrom(source, &(data->programId)); + source = DeserializeFrom(source, &(data->startTime)); + source = DeserializeFrom(source, &(data->timeout)); + return source; +} + + +template +auto DeserializeFrom(void const * source, ProgramStatusHistoryEntry * data) -> void const * +{ + using sts1cobcsw::DeserializeFrom; + + source = DeserializeFrom(source, &(data->programId)); + source = DeserializeFrom(source, &(data->startTime)); + source = DeserializeFrom(source, &(data->status)); + return source; +} + + template auto DeserializeFrom(void const * source, [[maybe_unused]] NoEventData * data) -> void const * { + using sts1cobcsw::DeserializeFrom; + auto dummy = NoEventData::id; source = DeserializeFrom(source, &dummy); return source; @@ -77,6 +135,8 @@ auto DeserializeFrom(void const * source, [[maybe_unused]] NoEventData * data) - template auto DeserializeFrom(void const * source, ProgramFinishedData * data) -> void const * { + using sts1cobcsw::DeserializeFrom; + auto dummy = ProgramFinishedData::id; source = DeserializeFrom(source, &dummy); source = DeserializeFrom(source, &(data->programId)); @@ -89,6 +149,8 @@ auto DeserializeFrom(void const * source, ProgramFinishedData * data) -> void co template auto DeserializeFrom(void const * source, ResultsReadyData * data) -> void const * { + using sts1cobcsw::DeserializeFrom; + auto dummy = ResultsReadyData::id; source = DeserializeFrom(source, &dummy); source = DeserializeFrom(source, &(data->programId)); diff --git a/Sts1CobcSw/FramSections/FramLayout.hpp b/Sts1CobcSw/FramSections/FramLayout.hpp index f651e05d..4c9275f5 100644 --- a/Sts1CobcSw/FramSections/FramLayout.hpp +++ b/Sts1CobcSw/FramSections/FramLayout.hpp @@ -12,18 +12,26 @@ namespace sts1cobcsw { +inline constexpr auto persistentVariablesSize = fram::Size(300); +inline constexpr auto eduProgramQueueSize = fram::Size(20 * 8); +inline constexpr auto eduProgramStatusHistorySize = fram::Size(50 * 7); +inline constexpr auto testMemorySize = fram::Size(1000); +inline constexpr auto telemetrySize = fram::memorySize - persistentVariablesSize + - eduProgramQueueSize - eduProgramStatusHistorySize + - testMemorySize; + inline constexpr auto framMemory = Section{}; inline constexpr auto framSections = Subsections, - SubsectionInfo<"eduProgramQueue", fram::Size(20 * 8)>, - SubsectionInfo<"eduProgramStatusHistory", fram::Size(50 * 7)>, - SubsectionInfo<"testMemory", fram::Size(1000)>, - SubsectionInfo<"telemetry", fram::Size(26'168 * 40)>>{}; + SubsectionInfo<"persistentVariables", persistentVariablesSize>, + SubsectionInfo<"eduProgramQueue", eduProgramQueueSize>, + SubsectionInfo<"eduProgramStatusHistory", eduProgramStatusHistorySize>, + SubsectionInfo<"testMemory", testMemorySize>, + SubsectionInfo<"telemetry", telemetrySize>>{}; inline constexpr auto persistentVariables = PersistentVariables(), // Bootloader - PersistentVariableInfo<"nResetsSinceRf", std::uint16_t>, + PersistentVariableInfo<"nResetsSinceRf", std::uint8_t>, PersistentVariableInfo<"activeSecondaryFwPartition", std::int8_t>, PersistentVariableInfo<"backupSecondaryFwPartition", std::int8_t>, // COBC state @@ -36,10 +44,10 @@ inline constexpr auto persistentVariables = PersistentVariableInfo<"realTimeOffset", Duration>, PersistentVariableInfo<"epsIsWorking", bool>, PersistentVariableInfo<"flashIsWorking", bool>, - PersistentVariableInfo<"nFlashErrors", std::uint16_t>, PersistentVariableInfo<"rfIsWorking", bool>, - PersistentVariableInfo<"nRfErrors", std::uint16_t>, - PersistentVariableInfo<"nFileSystemErrors", std::uint16_t>, + PersistentVariableInfo<"nFlashErrors", std::uint8_t>, + PersistentVariableInfo<"nRfErrors", std::uint8_t>, + PersistentVariableInfo<"nFileSystemErrors", std::uint8_t>, PersistentVariableInfo<"eduShouldBePowered", bool>, - PersistentVariableInfo<"nEduCommunicationErrors", std::uint16_t>>{}; + PersistentVariableInfo<"nEduCommunicationErrors", std::uint8_t>>{}; } diff --git a/Sts1CobcSw/ProgramId/ProgramId.hpp b/Sts1CobcSw/ProgramId/ProgramId.hpp index 18aca3e6..98838d16 100644 --- a/Sts1CobcSw/ProgramId/ProgramId.hpp +++ b/Sts1CobcSw/ProgramId/ProgramId.hpp @@ -10,8 +10,11 @@ namespace sts1cobcsw { -using ProgramId = - strong::type; +using ProgramId = strong::type; template<> diff --git a/Sts1CobcSw/Telemetry/CMakeLists.txt b/Sts1CobcSw/Telemetry/CMakeLists.txt new file mode 100644 index 00000000..7f584ee0 --- /dev/null +++ b/Sts1CobcSw/Telemetry/CMakeLists.txt @@ -0,0 +1,5 @@ +target_sources(Sts1CobcSw_Telemetry PRIVATE TelemetryRecord.cpp) +target_link_libraries( + Sts1CobcSw_Telemetry PUBLIC Sts1CobcSw_FramSections Sts1CobcSw_ProgramId Sts1CobcSw_Serial + Sts1CobcSw_Utility +) diff --git a/Sts1CobcSw/Telemetry/TelemetryMemory.hpp b/Sts1CobcSw/Telemetry/TelemetryMemory.hpp new file mode 100644 index 00000000..63d248e8 --- /dev/null +++ b/Sts1CobcSw/Telemetry/TelemetryMemory.hpp @@ -0,0 +1,16 @@ +#pragma once + + +#include +#include +#include +#include + + +namespace sts1cobcsw +{ +inline constexpr auto nCachedTelemetryRecords = 10; +inline constexpr auto telemetryMemory = FramRingArray(), + nCachedTelemetryRecords>{}; +} diff --git a/Sts1CobcSw/Telemetry/TelemetryRecord.cpp b/Sts1CobcSw/Telemetry/TelemetryRecord.cpp new file mode 100644 index 00000000..756c0776 --- /dev/null +++ b/Sts1CobcSw/Telemetry/TelemetryRecord.cpp @@ -0,0 +1,114 @@ +#include + + +namespace sts1cobcsw +{ +template +auto DeserializeFrom(void const * source, TelemetryRecord * data) -> void const * +{ + // NOLINTBEGIN(*init-variables, *magic-numbers) + std::uint8_t booleans1; + source = DeserializeFrom(source, &booleans1); + data->fwChecksumsAreOk = booleans1 & 1U; + data->eduShouldBePowered = booleans1 & (1U << 1U); + data->eduHeartBeats = booleans1 & (1U << 2U); + data->newResultIsAvailable = booleans1 & (1U << 3U); + std::uint8_t booleans2; + source = DeserializeFrom(source, &booleans2); + data->antennasShouldBeDeployed = booleans2 & 1U; + data->framIsWorking = booleans2 & (1U << 1U); + data->epsIsWorking = booleans2 & (1U << 2U); + data->flashIsWorking = booleans2 & (1U << 3U); + data->rfIsWorking = booleans2 & (1U << 4U); + data->lastTeleCommandIdWasInvalid = booleans2 & (1U << 5U); + data->lastTeleCommandArgumentsWereInvalid = booleans2 & (1U << 6U); + // NOLINTEND(*init-variables, *magic-numbers) + source = DeserializeFrom(source, &(data->nResetsSinceRf)); + source = DeserializeFrom(source, &(data->activeSecondaryFwPartition)); + source = DeserializeFrom(source, &(data->backupSecondaryFwPartition)); + source = DeserializeFrom(source, &(data->eduProgramQueueIndex)); + source = DeserializeFrom(source, &(data->programIdOfCurrentEduProgramQueueEntry)); + source = DeserializeFrom(source, &(data->nEduCommunicationErrors)); + source = DeserializeFrom(source, &(data->nTotalResets)); + source = DeserializeFrom(source, &(data->lastResetReason)); + source = DeserializeFrom(source, &(data->rodosTimeInSeconds)); + source = DeserializeFrom(source, &(data->realTime)); + source = DeserializeFrom(source, &(data->nFlashErrors)); + source = DeserializeFrom(source, &(data->nRfErrors)); + source = DeserializeFrom(source, &(data->nFileSystemErrors)); + source = DeserializeFrom(source, &(data->batteryPackVoltage)); + source = DeserializeFrom(source, &(data->batteryCenterTapVoltage)); + source = DeserializeFrom(source, &(data->batteryTemperature)); + source = DeserializeFrom(source, &(data->cobcTemperature)); + source = DeserializeFrom(source, &(data->cubeSatBusVoltage)); + source = DeserializeFrom(source, &(data->sidepanelXPlusTemperature)); + source = DeserializeFrom(source, &(data->sidepanelYPlusTemperature)); + source = DeserializeFrom(source, &(data->sidepanelYMinusTemperature)); + source = DeserializeFrom(source, &(data->sidepanelZPlusTemperature)); + source = DeserializeFrom(source, &(data->sidepanelZMinusTemperature)); + source = DeserializeFrom(source, &(data->rfBaudRate)); + source = DeserializeFrom(source, &(data->nCorrectableUplinkErrors)); + source = DeserializeFrom(source, &(data->nUncorrectableUplinkErrors)); + source = DeserializeFrom(source, &(data->nBadRfpackets)); + source = DeserializeFrom(source, &(data->nGoodRfpackets)); + source = DeserializeFrom(source, &(data->lastReceivedCommandId)); + return source; +} + + +template +auto SerializeTo(void * destination, TelemetryRecord const & data) -> void * +{ + // NOLINTBEGIN(*signed-bitwise, *magic-numbers) + std::uint8_t booleans1 = data.fwChecksumsAreOk; + booleans1 |= data.eduShouldBePowered << 1; + booleans1 |= data.eduHeartBeats << 2; + booleans1 |= data.newResultIsAvailable << 3; + std::uint8_t booleans2 = data.antennasShouldBeDeployed; + booleans2 |= data.framIsWorking << 1; + booleans2 |= data.epsIsWorking << 2; + booleans2 |= data.flashIsWorking << 3; + booleans2 |= data.rfIsWorking << 4; + booleans2 |= data.lastTeleCommandIdWasInvalid << 5; + booleans2 |= data.lastTeleCommandArgumentsWereInvalid << 6; + // NOLINTEND(*signed-bitwise, *magic-numbers) + destination = SerializeTo(destination, booleans1); + destination = SerializeTo(destination, booleans2); + destination = SerializeTo(destination, data.nResetsSinceRf); + destination = SerializeTo(destination, data.activeSecondaryFwPartition); + destination = SerializeTo(destination, data.backupSecondaryFwPartition); + destination = SerializeTo(destination, data.eduProgramQueueIndex); + destination = SerializeTo(destination, data.programIdOfCurrentEduProgramQueueEntry); + destination = SerializeTo(destination, data.nEduCommunicationErrors); + destination = SerializeTo(destination, data.nTotalResets); + destination = SerializeTo(destination, data.lastResetReason); + destination = SerializeTo(destination, data.rodosTimeInSeconds); + destination = SerializeTo(destination, data.realTime); + destination = SerializeTo(destination, data.nFlashErrors); + destination = SerializeTo(destination, data.nRfErrors); + destination = SerializeTo(destination, data.nFileSystemErrors); + destination = SerializeTo(destination, data.batteryPackVoltage); + destination = SerializeTo(destination, data.batteryCenterTapVoltage); + destination = SerializeTo(destination, data.batteryTemperature); + destination = SerializeTo(destination, data.cobcTemperature); + destination = SerializeTo(destination, data.cubeSatBusVoltage); + destination = SerializeTo(destination, data.sidepanelXPlusTemperature); + destination = SerializeTo(destination, data.sidepanelYPlusTemperature); + destination = SerializeTo(destination, data.sidepanelYMinusTemperature); + destination = SerializeTo(destination, data.sidepanelZPlusTemperature); + destination = SerializeTo(destination, data.sidepanelZMinusTemperature); + destination = SerializeTo(destination, data.rfBaudRate); + destination = SerializeTo(destination, data.nCorrectableUplinkErrors); + destination = SerializeTo(destination, data.nUncorrectableUplinkErrors); + destination = SerializeTo(destination, data.nBadRfpackets); + destination = SerializeTo(destination, data.nGoodRfpackets); + destination = SerializeTo(destination, data.lastReceivedCommandId); + return destination; +} + + +template auto DeserializeFrom(void const *, TelemetryRecord *) -> void const *; +template auto DeserializeFrom(void const *, TelemetryRecord *) -> void const *; +template auto SerializeTo(void *, TelemetryRecord const &) -> void *; +template auto SerializeTo(void *, TelemetryRecord const &) -> void *; +} diff --git a/Sts1CobcSw/Telemetry/TelemetryRecord.hpp b/Sts1CobcSw/Telemetry/TelemetryRecord.hpp new file mode 100644 index 00000000..ee136ccb --- /dev/null +++ b/Sts1CobcSw/Telemetry/TelemetryRecord.hpp @@ -0,0 +1,119 @@ +#pragma once + + +#include +#include +#include + +#include +#include +#include + + +namespace sts1cobcsw +{ +// TODO: Merge the bools into bitfields +struct TelemetryRecord +{ + // Booleans: byte 1: bootloader and EDU + bool fwChecksumsAreOk = false; + bool eduShouldBePowered = false; + bool eduHeartBeats = false; + bool newResultIsAvailable = false; + // Booleans: byte 2: housekeeping and communication + bool antennasShouldBeDeployed = false; + bool framIsWorking = false; + bool epsIsWorking = false; + bool flashIsWorking = false; + bool rfIsWorking = false; + bool lastTeleCommandIdWasInvalid = false; + bool lastTeleCommandArgumentsWereInvalid = false; + + // BootLoader + std::uint8_t nResetsSinceRf = 0U; + std::int8_t activeSecondaryFwPartition = 0; + std::int8_t backupSecondaryFwPartition = 0; + + // EDU + std::int8_t eduProgramQueueIndex = 0; + ProgramId programIdOfCurrentEduProgramQueueEntry; + std::uint8_t nEduCommunicationErrors = 0U; + + // Housekeeping + std::uint32_t nTotalResets = 0U; + std::uint8_t lastResetReason = 0U; + std::int32_t rodosTimeInSeconds = 0; + RealTime realTime; + std::uint8_t nFlashErrors = 0U; + std::uint8_t nRfErrors = 0U; + std::uint8_t nFileSystemErrors = 0U; + + // Sensor data + std::uint8_t batteryPackVoltage = 0U; + std::uint8_t batteryCenterTapVoltage = 0U; + std::uint8_t batteryTemperature = 0U; + std::uint8_t cobcTemperature = 0U; + std::uint8_t cubeSatBusVoltage = 0U; + std::uint8_t sidepanelXPlusTemperature = 0U; + std::uint8_t sidepanelYPlusTemperature = 0U; + std::uint8_t sidepanelYMinusTemperature = 0U; + std::uint8_t sidepanelZPlusTemperature = 0U; + std::uint8_t sidepanelZMinusTemperature = 0U; + + // Communication + std::uint8_t rfBaudRate = 0U; + std::uint16_t nCorrectableUplinkErrors = 0U; + std::uint16_t nUncorrectableUplinkErrors = 0U; + std::uint16_t nBadRfpackets = 0U; + std::uint16_t nGoodRfpackets = 0U; + std::uint8_t lastReceivedCommandId = 0U; + + friend auto operator==(TelemetryRecord const &, TelemetryRecord const &) -> bool = default; +}; + + +template<> +inline constexpr std::size_t serialSize = + 2 + + totalSerialSize< + // Bootloader + decltype(TelemetryRecord::nResetsSinceRf), + decltype(TelemetryRecord::activeSecondaryFwPartition), + decltype(TelemetryRecord::backupSecondaryFwPartition), + // EDU + decltype(TelemetryRecord::eduProgramQueueIndex), + decltype(TelemetryRecord::programIdOfCurrentEduProgramQueueEntry), + decltype(TelemetryRecord::nEduCommunicationErrors), + // Housekeeping + decltype(TelemetryRecord::nTotalResets), + decltype(TelemetryRecord::lastResetReason), + decltype(TelemetryRecord::rodosTimeInSeconds), + decltype(TelemetryRecord::realTime), + decltype(TelemetryRecord::nFlashErrors), + decltype(TelemetryRecord::nRfErrors), + decltype(TelemetryRecord::nFileSystemErrors), + // Sensor data + decltype(TelemetryRecord::batteryPackVoltage), + decltype(TelemetryRecord::batteryCenterTapVoltage), + decltype(TelemetryRecord::batteryTemperature), + decltype(TelemetryRecord::cobcTemperature), + decltype(TelemetryRecord::cubeSatBusVoltage), + decltype(TelemetryRecord::sidepanelXPlusTemperature), + decltype(TelemetryRecord::sidepanelYPlusTemperature), + decltype(TelemetryRecord::sidepanelYMinusTemperature), + decltype(TelemetryRecord::sidepanelZPlusTemperature), + decltype(TelemetryRecord::sidepanelZMinusTemperature), + // Communication + decltype(TelemetryRecord::rfBaudRate), + decltype(TelemetryRecord::nCorrectableUplinkErrors), + decltype(TelemetryRecord::nUncorrectableUplinkErrors), + decltype(TelemetryRecord::nBadRfpackets), + decltype(TelemetryRecord::nGoodRfpackets), + decltype(TelemetryRecord::lastReceivedCommandId)>; + + +template +[[nodiscard]] auto DeserializeFrom(void const * source, TelemetryRecord * data) -> void const *; +template +[[nodiscard]] auto SerializeTo(void * destination, TelemetryRecord const & data) -> void *; +} diff --git a/Tests/UnitTests/CMakeLists.txt b/Tests/UnitTests/CMakeLists.txt index a31c8c2e..19a51f38 100644 --- a/Tests/UnitTests/CMakeLists.txt +++ b/Tests/UnitTests/CMakeLists.txt @@ -58,6 +58,12 @@ target_link_libraries( Sts1CobcSw_Periphery Sts1CobcSw_Utility ) +add_program(TelemetryRecord TelemetryRecord.test.cpp) +target_link_libraries( + Sts1CobcSwTests_TelemetryRecord PRIVATE Catch2::Catch2WithMain Sts1CobcSw_Serial + Sts1CobcSw_Telemetry +) + get_property( all_catch2_unit_test_targets DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY BUILDSYSTEM_TARGETS ) diff --git a/Tests/UnitTests/TelemetryRecord.test.cpp b/Tests/UnitTests/TelemetryRecord.test.cpp new file mode 100644 index 00000000..fdcf7b34 --- /dev/null +++ b/Tests/UnitTests/TelemetryRecord.test.cpp @@ -0,0 +1,100 @@ +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + + +using sts1cobcsw::Deserialize; +using sts1cobcsw::ProgramId; +using sts1cobcsw::RealTime; +using sts1cobcsw::Serialize; +using sts1cobcsw::TelemetryRecord; +using sts1cobcsw::edu::ProgramStatus; + + +TEST_CASE("(De-)Serialization of TelemetryRecord") +{ + SECTION("Example record is serialized and deserialized correctly") + { + static constexpr auto originalRecord = + TelemetryRecord{.fwChecksumsAreOk = true, + .eduShouldBePowered = true, + .eduHeartBeats = true, + .newResultIsAvailable = true, + .antennasShouldBeDeployed = true, + .framIsWorking = true, + .epsIsWorking = true, + .flashIsWorking = true, + .rfIsWorking = true, + .lastTeleCommandIdWasInvalid = true, + .lastTeleCommandArgumentsWereInvalid = true, + .nResetsSinceRf = 1U, + .activeSecondaryFwPartition = 2, + .backupSecondaryFwPartition = 3, + .eduProgramQueueIndex = 4, + .programIdOfCurrentEduProgramQueueEntry = ProgramId(5), + .nEduCommunicationErrors = 7U, + .nTotalResets = 8U, + .lastResetReason = 9U, + .rodosTimeInSeconds = 10, + .realTime = RealTime(11), + .nFlashErrors = 12U, + .nRfErrors = 13U, + .nFileSystemErrors = 14U, + .batteryPackVoltage = 15U, + .batteryCenterTapVoltage = 16U, + .batteryTemperature = 17U, + .cobcTemperature = 18U, + .cubeSatBusVoltage = 19U, + .sidepanelXPlusTemperature = 20U, + .sidepanelYPlusTemperature = 21U, + .sidepanelYMinusTemperature = 22U, + .sidepanelZPlusTemperature = 23U, + .sidepanelZMinusTemperature = 24U, + .rfBaudRate = 25U, + .nCorrectableUplinkErrors = 26U, + .nUncorrectableUplinkErrors = 27U, + .nBadRfpackets = 28U, + .nGoodRfpackets = 29U, + .lastReceivedCommandId = 30U}; + auto serializedRecord = Serialize(originalRecord); + auto deserializedRecord = Deserialize(serializedRecord); + CHECK(originalRecord == deserializedRecord); + } + + SECTION("All booleans are serialized and deserialized correctly") + { + static constexpr auto nBooleans1 = 4U; + static constexpr auto nBooleans2 = 7U; + static constexpr auto nBooleans = nBooleans1 + nBooleans2; + // We loop over all records where a single boolean set to true + for(auto i = 0U; i < nBooleans; ++i) + { + auto booleans1 = static_cast((1U << i) & ((1U << nBooleans1) - 1U)); + auto booleans2 = static_cast((1U << i) >> nBooleans1); + auto originalRecord = TelemetryRecord{ + .fwChecksumsAreOk = static_cast(booleans1 & 1U), + .eduShouldBePowered = static_cast(booleans1 & (1U << 1U)), + .eduHeartBeats = static_cast(booleans1 & (1U << 2U)), + .newResultIsAvailable = static_cast(booleans1 & (1U << 3U)), + .antennasShouldBeDeployed = static_cast(booleans2 & 1U), + .framIsWorking = static_cast(booleans2 & (1U << 1U)), + .epsIsWorking = static_cast(booleans2 & (1U << 2U)), + .flashIsWorking = static_cast(booleans2 & (1U << 3U)), + .rfIsWorking = static_cast(booleans2 & (1U << 4U)), + .lastTeleCommandIdWasInvalid = static_cast(booleans2 & (1U << 5U)), + .lastTeleCommandArgumentsWereInvalid = static_cast(booleans2 & (1U << 6U))}; + auto serializedRecord = Serialize(originalRecord); + auto deserializedRecord = Deserialize(serializedRecord); + CHECK(originalRecord == deserializedRecord); + } + } +} diff --git a/cmake/coverage.cmake b/cmake/coverage.cmake index 625ac79b..469c3e68 100644 --- a/cmake/coverage.cmake +++ b/cmake/coverage.cmake @@ -1,8 +1,9 @@ # ---- Variables ---- # We use variables separate from what CTest uses, because those have customization issues -set(COVERAGE_TRACE_COMMAND lcov -c -q -o "${PROJECT_BINARY_DIR}/coverage.info" -d - "${PROJECT_BINARY_DIR}" --include "${PROJECT_SOURCE_DIR}/*" +set(COVERAGE_TRACE_COMMAND + lcov -c -q -o "${PROJECT_BINARY_DIR}/coverage.info" -d "${PROJECT_BINARY_DIR}" --include + "${PROJECT_SOURCE_DIR}/*" --ignore-errors negative CACHE STRING "; separated command to generate a trace for the 'coverage' target" )