From 94f23e794909e087bbf193289a9e05106855e453 Mon Sep 17 00:00:00 2001 From: Patrick Kappl Date: Sat, 16 Nov 2024 15:58:07 +0000 Subject: [PATCH] Add golden test for SPI supervisor --- .../CobcSoftware/FlashStartupTestThread.cpp | 2 +- .../CobcSoftware/FramEpsStartupTestThread.cpp | 2 +- .../CobcSoftware/RfStartupTestThread.cpp | 2 +- .../SpiStartupTestAndSupervisorThread.cpp | 9 +- Tests/CMakeLists.txt | 2 +- Tests/GoldenTests/CMakeLists.txt | 11 ++ .../ExpectedOutputs/SpiSupervisor.txt | 16 +++ Tests/GoldenTests/SpiSupervisor.test.cpp | 100 ++++++++++++++++++ 8 files changed, 138 insertions(+), 6 deletions(-) create mode 100644 Tests/GoldenTests/ExpectedOutputs/SpiSupervisor.txt create mode 100644 Tests/GoldenTests/SpiSupervisor.test.cpp diff --git a/Sts1CobcSw/CobcSoftware/FlashStartupTestThread.cpp b/Sts1CobcSw/CobcSoftware/FlashStartupTestThread.cpp index 34070c1c..642594f4 100644 --- a/Sts1CobcSw/CobcSoftware/FlashStartupTestThread.cpp +++ b/Sts1CobcSw/CobcSoftware/FlashStartupTestThread.cpp @@ -32,8 +32,8 @@ class FlashStartupTestThread : public RODOS::StaticThread void run() override { - DEBUG_PRINT("Flash start-up test ..."); SuspendUntil(endOfTime); + DEBUG_PRINT("Flash start-up test ..."); flash::Initialize(); auto jedecId = flash::ReadJedecId(); if(jedecId.deviceId == flash::correctJedecId.deviceId diff --git a/Sts1CobcSw/CobcSoftware/FramEpsStartupTestThread.cpp b/Sts1CobcSw/CobcSoftware/FramEpsStartupTestThread.cpp index b07335df..7ccc44d4 100644 --- a/Sts1CobcSw/CobcSoftware/FramEpsStartupTestThread.cpp +++ b/Sts1CobcSw/CobcSoftware/FramEpsStartupTestThread.cpp @@ -37,8 +37,8 @@ class FramEpsStartupTestThread : public RODOS::StaticThread void run() override { - DEBUG_PRINT("FRAM/EPS start-up test ..."); SuspendUntil(endOfTime); + DEBUG_PRINT("FRAM/EPS start-up test ..."); fram::Initialize(); auto deviceId = fram::ReadDeviceId(); if(deviceId == fram::correctDeviceId) diff --git a/Sts1CobcSw/CobcSoftware/RfStartupTestThread.cpp b/Sts1CobcSw/CobcSoftware/RfStartupTestThread.cpp index 138a8adb..65c7584b 100644 --- a/Sts1CobcSw/CobcSoftware/RfStartupTestThread.cpp +++ b/Sts1CobcSw/CobcSoftware/RfStartupTestThread.cpp @@ -31,8 +31,8 @@ class RfStartupTestThread : public RODOS::StaticThread void run() override { - DEBUG_PRINT("RF start-up test ..."); SuspendUntil(endOfTime); + DEBUG_PRINT("RF start-up test ..."); rf::Initialize(rf::TxType::packet); auto partNumber = rf::ReadPartNumber(); if(partNumber == rf::correctPartNumber) diff --git a/Sts1CobcSw/CobcSoftware/SpiStartupTestAndSupervisorThread.cpp b/Sts1CobcSw/CobcSoftware/SpiStartupTestAndSupervisorThread.cpp index 462b7d99..f0d636cf 100644 --- a/Sts1CobcSw/CobcSoftware/SpiStartupTestAndSupervisorThread.cpp +++ b/Sts1CobcSw/CobcSoftware/SpiStartupTestAndSupervisorThread.cpp @@ -25,7 +25,9 @@ namespace sts1cobcsw { -constexpr auto stackSize = 100U; +// Running the integration test for the supervisor thread showed that at least 850 bytes are needed +constexpr auto stackSize = 900U; +constexpr auto initialSleepTime = 10 * ms; // TODO: Measure how long the startup tests really take to determine the correct timeout constexpr auto startupTestTimeout = 100 * ms; // TODO: Think about how often the supervision should run @@ -52,6 +54,10 @@ class SpiStartupTestAndSupervisorThread : public RODOS::StaticThread void run() override { + // Briefly go to sleep to ensure that the low-priority startup test threads have started and + // are waiting for the high-priority supervisor thread to resume them + SuspendFor(initialSleepTime); + static constexpr auto errorMessage = " failed to complete in time\n"; static constexpr auto successMessage = " completed in time\n"; @@ -118,7 +124,6 @@ class SpiStartupTestAndSupervisorThread : public RODOS::StaticThread } if(timeoutHappened) { - DEBUG_PRINT("Hardware reset and reboot"); RODOS::hwResetAndReboot(); } } diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 739987e0..985e6b41 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -16,7 +16,7 @@ add_custom_target(AllTests) if(CMAKE_SYSTEM_NAME STREQUAL Linux) add_subdirectory(GoldenTests EXCLUDE_FROM_ALL) add_subdirectory(UnitTests EXCLUDE_FROM_ALL) - add_dependencies(AllTests AllUnitTests AllGoldenTests) + add_dependencies(AllTests AllGoldenTests AllUnitTests) elseif(CMAKE_SYSTEM_NAME STREQUAL Generic) add_subdirectory(HardwareTests EXCLUDE_FROM_ALL) add_dependencies(AllTests AllHardwareTests) diff --git a/Tests/GoldenTests/CMakeLists.txt b/Tests/GoldenTests/CMakeLists.txt index 7111bef7..d71aee0a 100644 --- a/Tests/GoldenTests/CMakeLists.txt +++ b/Tests/GoldenTests/CMakeLists.txt @@ -6,6 +6,17 @@ target_link_libraries(Sts1CobcSwTests_HelloWorld PRIVATE rodos::rodos) add_golden_test(HelloDummy.test.cpp) target_link_libraries(Sts1CobcSwTests_HelloDummy PRIVATE rodos::rodos etl::etl Sts1CobcSw_Dummy) +add_golden_test(SpiSupervisor.test.cpp) +target_sources( + Sts1CobcSwTests_SpiSupervisor + PRIVATE ${CMAKE_SOURCE_DIR}/Sts1CobcSw/CobcSoftware/StartupTestThreadStubs.cpp + ${CMAKE_SOURCE_DIR}/Sts1CobcSw/CobcSoftware/SpiStartupTestAndSupervisorThread.cpp +) +target_link_libraries( + Sts1CobcSwTests_SpiSupervisor PRIVATE rodos::rodos Sts1CobcSw_FramSections Sts1CobcSw_Hal + Sts1CobcSw_Periphery Sts1CobcSw_Serial Sts1CobcSw_Utility +) + # --- All golden tests --- get_property( diff --git a/Tests/GoldenTests/ExpectedOutputs/SpiSupervisor.txt b/Tests/GoldenTests/ExpectedOutputs/SpiSupervisor.txt new file mode 100644 index 00000000..c08b527a --- /dev/null +++ b/Tests/GoldenTests/ExpectedOutputs/SpiSupervisor.txt @@ -0,0 +1,16 @@ +FRAM/EPS start-up test ... + completed in time +Flash start-up test ... + completed in time +RF start-up test ... + completed in time + +SPI supervisor test + +Writing with implementation that finishes in time ... + -> works +Writing with implementation that never finishes ... +FRAM/EPS SPI timeout occurred +Flash SPI timeout occurred +RF SPI timeout occurred +hw_resetAndReboot() -> exit diff --git a/Tests/GoldenTests/SpiSupervisor.test.cpp b/Tests/GoldenTests/SpiSupervisor.test.cpp new file mode 100644 index 00000000..67c57f3e --- /dev/null +++ b/Tests/GoldenTests/SpiSupervisor.test.cpp @@ -0,0 +1,100 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + + +namespace sts1cobcsw +{ +using RODOS::PRINTF; + + +auto WriteThatFinishesInTime([[maybe_unused]] void const * data, + [[maybe_unused]] std::size_t nBytes, + Duration duration) -> void; +auto WriteThatNeverFinishes([[maybe_unused]] void const * data, + [[maybe_unused]] std::size_t nBytes, + Duration duration) -> void; + + +auto transferEnd = endOfTime; + + +class SpiSupervisorTest : public RODOS::StaticThread<> +{ + // We cannot use dynamic_cast because RTTI is disabled + // NOLINTBEGIN(*static-cast-downcast) + hal::SpiMock & flashSpi_ = static_cast(flashSpi); + hal::SpiMock & framEpsSpi_ = static_cast(framEpsSpi); + hal::SpiMock & rfSpi_ = static_cast(rfSpi); + // NOLINTEND(*static-cast-downcast) + + +public: + SpiSupervisorTest() : StaticThread("SpiSupervisorTest", 200) + { + } + + void init() override + { + flashSpi_.SetTransferEnd([]() { return transferEnd; }); + flashSpi_.SetWrite(WriteThatFinishesInTime); + framEpsSpi_.SetTransferEnd([]() { return transferEnd; }); + framEpsSpi_.SetWrite(WriteThatFinishesInTime); + rfSpi_.SetTransferEnd([]() { return transferEnd; }); + rfSpi_.SetWrite(WriteThatFinishesInTime); + fram::ram::SetAllDoFunctions(); + fram::Initialize(); + } + + void run() override + { + SuspendFor(1 * s); + + PRINTF("\nSPI supervisor test\n\n"); + + PRINTF("Writing with implementation that finishes in time ...\n"); + WriteTo(&flashSpi_, Span(0x00_b), 10 * ms); + WriteTo(&framEpsSpi_, Span(0x00_b), 100 * ms); + // The supervision period is 1 s so this write will definitely be checked at least once by + // the supervisor thread + WriteTo(&rfSpi_, Span(0x00_b), 1500 * ms); + PRINTF(" -> works\n"); + + PRINTF("Writing with implementation that never finishes ...\n"); + flashSpi_.SetWrite(WriteThatNeverFinishes); + WriteTo(&flashSpi_, Span(0x00_b), 1 * ms); + } +} spiSupervisorTest; + + +auto WriteThatFinishesInTime([[maybe_unused]] void const * data, + [[maybe_unused]] std::size_t nBytes, + Duration duration) -> void +{ + transferEnd = CurrentRodosTime() + duration; + SuspendFor(duration / 10 * 9); + transferEnd = endOfTime; +} + + +auto WriteThatNeverFinishes([[maybe_unused]] void const * data, + [[maybe_unused]] std::size_t nBytes, + Duration duration) -> void +{ + transferEnd = CurrentRodosTime() + duration; + SuspendUntil(endOfTime); +} +}