diff --git a/CMakeLists.txt b/CMakeLists.txt index a26dbb4e..e7e7cc72 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ include(cmake/prelude.cmake) project( Sts1CobcSw VERSION 0.1.0 - DESCRIPTION "Software for the Communication and onboard computer of SpaceTeamSat1" + DESCRIPTION "Software for the communication and onboard computer of SpaceTeamSat1" HOMEPAGE_URL "https://github.com/SpaceTeam/STS1_COBC_SW" LANGUAGES CXX ) @@ -30,16 +30,15 @@ add_library(Sts1CobcSw_Dummy STATIC) add_library(Sts1CobcSw_Edu STATIC) add_library(Sts1CobcSw_FileSystem STATIC) add_library(Sts1CobcSw_FramSections INTERFACE) +add_library(Sts1CobcSw_Hal STATIC) add_library(Sts1CobcSw_Outcome INTERFACE) add_library(Sts1CobcSw_ProgramId INTERFACE) add_library(Sts1CobcSw_Periphery STATIC) add_library(Sts1CobcSw_Serial INTERFACE) add_library(Sts1CobcSw_Utility STATIC) add_program(HelloDummy) -# add_program(Heartbeat) if(CMAKE_SYSTEM_NAME STREQUAL Generic) - add_library(Sts1CobcSw_Hal STATIC) add_program(CobcSoftware) endif() diff --git a/Sts1CobcSw/CMakeLists.txt b/Sts1CobcSw/CMakeLists.txt index 8227f17c..128f09e9 100644 --- a/Sts1CobcSw/CMakeLists.txt +++ b/Sts1CobcSw/CMakeLists.txt @@ -1,9 +1,7 @@ -if(CMAKE_SYSTEM_NAME STREQUAL Generic) - add_subdirectory(Hal) -endif() add_subdirectory(Edu) add_subdirectory(FileSystem) add_subdirectory(FramSections) +add_subdirectory(Hal) add_subdirectory(Outcome) add_subdirectory(Periphery) add_subdirectory(Serial) @@ -15,7 +13,3 @@ target_link_libraries(Sts1CobcSw_Dummy PUBLIC etl::etl Sts1CobcSw_Utility) target_sources(Sts1CobcSw_HelloDummy PRIVATE HelloDummy.cpp) target_link_libraries(Sts1CobcSw_HelloDummy PRIVATE Sts1CobcSw_Dummy rodos::rodos) - -# target_sources(Sts1CobcSw_Heartbeat PRIVATE EduHeartbeatThread.cpp TopicsAndSubscribers.cpp) -# target_link_libraries(Sts1CobcSw_Heartbeat PRIVATE etl::etl rodos::rodos Sts1CobcSw_Hal -# Sts1CobcSw_Utility Sts1CobcSw_Periphery) diff --git a/Sts1CobcSw/CobcSoftware/CMakeLists.txt b/Sts1CobcSw/CobcSoftware/CMakeLists.txt index af52ed5f..09639ba4 100644 --- a/Sts1CobcSw/CobcSoftware/CMakeLists.txt +++ b/Sts1CobcSw/CobcSoftware/CMakeLists.txt @@ -19,6 +19,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL Generic) PRIVATE etl::etl rodos::rodos Sts1CobcSw_Edu + Sts1CobcSw_FramSections Sts1CobcSw_Hal Sts1CobcSw_Periphery Sts1CobcSw_Serial diff --git a/Sts1CobcSw/CobcSoftware/CommandParser.cpp b/Sts1CobcSw/CobcSoftware/CommandParser.cpp index 1ffd8bf2..95719759 100644 --- a/Sts1CobcSw/CobcSoftware/CommandParser.cpp +++ b/Sts1CobcSw/CobcSoftware/CommandParser.cpp @@ -9,10 +9,9 @@ #include // IWYU pragma: keep + namespace sts1cobcsw { - - auto DispatchCommand(etl::vector const & command) -> void { auto gsCommandHeader = diff --git a/Sts1CobcSw/CobcSoftware/EduCommunicationErrorThread.cpp b/Sts1CobcSw/CobcSoftware/EduCommunicationErrorThread.cpp index 0c1512ca..d463c1b1 100644 --- a/Sts1CobcSw/CobcSoftware/EduCommunicationErrorThread.cpp +++ b/Sts1CobcSw/CobcSoftware/EduCommunicationErrorThread.cpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include diff --git a/Sts1CobcSw/CobcSoftware/EduHeartbeatThread.cpp b/Sts1CobcSw/CobcSoftware/EduHeartbeatThread.cpp index 3d632f36..74f8c7b9 100644 --- a/Sts1CobcSw/CobcSoftware/EduHeartbeatThread.cpp +++ b/Sts1CobcSw/CobcSoftware/EduHeartbeatThread.cpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include diff --git a/Sts1CobcSw/CobcSoftware/EduListenerThread.cpp b/Sts1CobcSw/CobcSoftware/EduListenerThread.cpp index 2f9431f2..48c08331 100644 --- a/Sts1CobcSw/CobcSoftware/EduListenerThread.cpp +++ b/Sts1CobcSw/CobcSoftware/EduListenerThread.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include diff --git a/Sts1CobcSw/CobcSoftware/EduPowerManagementThread.cpp b/Sts1CobcSw/CobcSoftware/EduPowerManagementThread.cpp index c0db4929..fc02768a 100644 --- a/Sts1CobcSw/CobcSoftware/EduPowerManagementThread.cpp +++ b/Sts1CobcSw/CobcSoftware/EduPowerManagementThread.cpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include diff --git a/Sts1CobcSw/CobcSoftware/EduProgramQueueThread.cpp b/Sts1CobcSw/CobcSoftware/EduProgramQueueThread.cpp index 0f6dd75b..b4e8ad1d 100644 --- a/Sts1CobcSw/CobcSoftware/EduProgramQueueThread.cpp +++ b/Sts1CobcSw/CobcSoftware/EduProgramQueueThread.cpp @@ -9,7 +9,8 @@ #include #include // IWYU pragma: keep #include -#include +#include +#include #include #include diff --git a/Sts1CobcSw/CobcSoftware/FlashStartupTestThread.cpp b/Sts1CobcSw/CobcSoftware/FlashStartupTestThread.cpp index f1622ff5..642594f4 100644 --- a/Sts1CobcSw/CobcSoftware/FlashStartupTestThread.cpp +++ b/Sts1CobcSw/CobcSoftware/FlashStartupTestThread.cpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include @@ -30,16 +32,22 @@ class FlashStartupTestThread : public RODOS::StaticThread void run() override { - RODOS::AT(RODOS::END_OF_TIME); + SuspendUntil(endOfTime); + DEBUG_PRINT("Flash start-up test ..."); flash::Initialize(); auto jedecId = flash::ReadJedecId(); - if(jedecId.deviceId != flash::correctJedecId.deviceId - || jedecId.manufacturerId != flash::correctJedecId.manufacturerId) + if(jedecId.deviceId == flash::correctJedecId.deviceId + && jedecId.manufacturerId == flash::correctJedecId.manufacturerId) { + persistentVariables.template Store<"flashIsWorking">(true); + } + else + { + DEBUG_PRINT(" failed to read correct flash JEDEC ID"); persistentVariables.template Store<"flashIsWorking">(false); } ResumeSpiStartupTestAndSupervisorThread(); - RODOS::AT(RODOS::END_OF_TIME); + SuspendUntil(endOfTime); } } flashStartupTestThread; diff --git a/Sts1CobcSw/CobcSoftware/FramEpsStartupTestThread.cpp b/Sts1CobcSw/CobcSoftware/FramEpsStartupTestThread.cpp index 11b0755d..7ccc44d4 100644 --- a/Sts1CobcSw/CobcSoftware/FramEpsStartupTestThread.cpp +++ b/Sts1CobcSw/CobcSoftware/FramEpsStartupTestThread.cpp @@ -1,12 +1,17 @@ #include #include #include +#include +#include #include #include +#include #include +#include #include +#include #include @@ -32,17 +37,24 @@ class FramEpsStartupTestThread : public RODOS::StaticThread void run() override { - RODOS::AT(RODOS::END_OF_TIME); + SuspendUntil(endOfTime); + DEBUG_PRINT("FRAM/EPS start-up test ..."); fram::Initialize(); auto deviceId = fram::ReadDeviceId(); - if(deviceId != fram::correctDeviceId) + if(deviceId == fram::correctDeviceId) { + fram::framIsWorking.Store(true); + } + else + { + DEBUG_PRINT(" failed to read correct FRAM device ID"); fram::framIsWorking.Store(false); } eps::Initialize(); (void)eps::Read(); + persistentVariables.template Store<"epsIsWorking">(true); ResumeSpiStartupTestAndSupervisorThread(); - RODOS::AT(RODOS::END_OF_TIME); + SuspendUntil(endOfTime); } } framEpsStartupTestThread; diff --git a/Sts1CobcSw/CobcSoftware/RfStartupTestThread.cpp b/Sts1CobcSw/CobcSoftware/RfStartupTestThread.cpp index 8d9a6e6c..65c7584b 100644 --- a/Sts1CobcSw/CobcSoftware/RfStartupTestThread.cpp +++ b/Sts1CobcSw/CobcSoftware/RfStartupTestThread.cpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include @@ -29,15 +31,21 @@ class RfStartupTestThread : public RODOS::StaticThread void run() override { - RODOS::AT(RODOS::END_OF_TIME); + SuspendUntil(endOfTime); + DEBUG_PRINT("RF start-up test ..."); rf::Initialize(rf::TxType::packet); auto partNumber = rf::ReadPartNumber(); - if(partNumber != rf::correctPartNumber) + if(partNumber == rf::correctPartNumber) { + persistentVariables.template Store<"rfIsWorking">(true); + } + else + { + DEBUG_PRINT(" failed to read correct RF part number"); persistentVariables.template Store<"rfIsWorking">(false); } ResumeSpiStartupTestAndSupervisorThread(); - RODOS::AT(RODOS::END_OF_TIME); + SuspendUntil(endOfTime); } } rfStartupTestThread; diff --git a/Sts1CobcSw/CobcSoftware/SpiStartupTestAndSupervisorThread.cpp b/Sts1CobcSw/CobcSoftware/SpiStartupTestAndSupervisorThread.cpp index f44b7329..b3dc9766 100644 --- a/Sts1CobcSw/CobcSoftware/SpiStartupTestAndSupervisorThread.cpp +++ b/Sts1CobcSw/CobcSoftware/SpiStartupTestAndSupervisorThread.cpp @@ -6,22 +6,32 @@ #include #include #include -#include #include -#include -#include +#include +#include #include +#include +#include + +#include +#include +#include +#include #include +#include + 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 * RODOS::MILLISECONDS; +constexpr auto startupTestTimeout = 100 * ms; // TODO: Think about how often the supervision should run -constexpr auto supervisionPeriod = 1 * RODOS::SECONDS; +constexpr auto supervisionPeriod = 1 * s; auto ExecuteStartupTest(void (*startupTestThreadResumeFuntion)()) -> bool; @@ -44,50 +54,77 @@ class SpiStartupTestAndSupervisorThread : public RODOS::StaticThread void run() override { - using RODOS::AT; - using RODOS::NOW; + // 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"; - // TODO: Test if this works auto testWasSuccessful = ExecuteStartupTest(ResumeFramEpsStartupTestThread); + DEBUG_PRINT(fram::framIsWorking.Load() ? "\n" : " and"); if(not testWasSuccessful) { + DEBUG_PRINT("%s", errorMessage); fram::framIsWorking.Store(false); persistentVariables.template Store<"epsIsWorking">(false); } + else + { + DEBUG_PRINT("%s", successMessage); + } + testWasSuccessful = ExecuteStartupTest(ResumeFlashStartupTestThread); + DEBUG_PRINT(persistentVariables.template Load<"flashIsWorking">() ? "\n" : " and"); if(not testWasSuccessful) { + DEBUG_PRINT("%s", errorMessage); persistentVariables.template Store<"flashIsWorking">(false); persistentVariables.template Increment<"nFlashErrors">(); } + else + { + DEBUG_PRINT("%s", successMessage); + } + testWasSuccessful = ExecuteStartupTest(ResumeRfStartupTestThread); + DEBUG_PRINT(persistentVariables.template Load<"rfIsWorking">() ? "\n" : " and"); if(not testWasSuccessful) { + DEBUG_PRINT("%s", errorMessage); persistentVariables.template Store<"rfIsWorking">(false); persistentVariables.template Increment<"nRfErrors">(); - AT(NOW() + 2 * RODOS::SECONDS); + SuspendFor(2 * s); RODOS::hwResetAndReboot(); } + else + { + DEBUG_PRINT("%s", successMessage); + } - TIME_LOOP(0, supervisionPeriod) + TIME_LOOP(0, value_of(supervisionPeriod)) { auto timeoutHappened = false; - if(NOW() > framEpsSpi.TransferEnd()) + if(CurrentRodosTime() > framEpsSpi.TransferEnd()) { + DEBUG_PRINT("FRAM/EPS SPI timeout occurred\n"); timeoutHappened = true; } - if(NOW() > flash::spi.TransferEnd()) + if(CurrentRodosTime() > flashSpi.TransferEnd()) { + DEBUG_PRINT("Flash SPI timeout occurred\n"); timeoutHappened = true; persistentVariables.template Increment<"nFlashErrors">(); } - if(NOW() > rf::spi.TransferEnd()) + if(CurrentRodosTime() > rfSpi.TransferEnd()) { + DEBUG_PRINT("RF SPI timeout occurred\n"); timeoutHappened = true; persistentVariables.template Increment<"nRfErrors">(); } if(timeoutHappened) { + DEBUG_PRINT("Hardware reset and reboot"); RODOS::hwResetAndReboot(); } } @@ -103,9 +140,9 @@ auto ResumeSpiStartupTestAndSupervisorThread() -> void auto ExecuteStartupTest(void (*startupTestThreadResumeFuntion)()) -> bool { - auto testEnd = RODOS::NOW() + startupTestTimeout; + auto testEnd = CurrentRodosTime() + startupTestTimeout; startupTestThreadResumeFuntion(); - RODOS::AT(testEnd); - return RODOS::NOW() <= testEnd; + SuspendUntil(testEnd); + return CurrentRodosTime() <= testEnd; } } diff --git a/Sts1CobcSw/CobcSoftware/StartupTestThreadStubs.cpp b/Sts1CobcSw/CobcSoftware/StartupTestThreadStubs.cpp new file mode 100644 index 00000000..85736f5b --- /dev/null +++ b/Sts1CobcSw/CobcSoftware/StartupTestThreadStubs.cpp @@ -0,0 +1,106 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +namespace sts1cobcsw +{ +auto const stackSize = 800U; + + +class FramEpsStartupTestThread : public RODOS::StaticThread +{ +public: + FramEpsStartupTestThread() + : StaticThread("FramEpsStartupTestThread", framEpsStartupTestThreadPriority) + { + } + +private: + void init() override + { + } + + void run() override + { + SuspendUntil(endOfTime); + DEBUG_PRINT("FRAM/EPS start-up test ..."); + fram::framIsWorking.Store(true); + persistentVariables.template Store<"epsIsWorking">(true); + ResumeSpiStartupTestAndSupervisorThread(); + SuspendUntil(endOfTime); + } +} framEpsStartupTestThread; + + +class FlashStartupTestThread : public RODOS::StaticThread +{ +public: + FlashStartupTestThread() + : StaticThread("FlashStartupTestThread", flashStartupTestThreadPriority) + { + } + +private: + void init() override + { + } + + void run() override + { + SuspendUntil(endOfTime); + DEBUG_PRINT("Flash start-up test ..."); + persistentVariables.template Store<"flashIsWorking">(true); + ResumeSpiStartupTestAndSupervisorThread(); + SuspendUntil(endOfTime); + } +} flashStartupTestThread; + + +class RfStartupTestThread : public RODOS::StaticThread +{ +public: + RfStartupTestThread() : StaticThread("RfStartupTestThread", rfStartupTestThreadPriority) + { + } + +private: + void init() override + { + } + + void run() override + { + SuspendUntil(endOfTime); + DEBUG_PRINT("RF start-up test ..."); + persistentVariables.template Store<"rfIsWorking">(true); + ResumeSpiStartupTestAndSupervisorThread(); + SuspendUntil(endOfTime); + } +} rfStartupTestThread; + + +auto ResumeFramEpsStartupTestThread() -> void +{ + framEpsStartupTestThread.resume(); +} + + +auto ResumeFlashStartupTestThread() -> void +{ + flashStartupTestThread.resume(); +} + + +auto ResumeRfStartupTestThread() -> void +{ + rfStartupTestThread.resume(); +} +} diff --git a/Sts1CobcSw/Edu/Edu.cpp b/Sts1CobcSw/Edu/Edu.cpp index 9806ddd4..94d7fce1 100644 --- a/Sts1CobcSw/Edu/Edu.cpp +++ b/Sts1CobcSw/Edu/Edu.cpp @@ -10,8 +10,8 @@ #include #include #include +#include #include -#include #include diff --git a/Sts1CobcSw/Edu/Types.hpp b/Sts1CobcSw/Edu/Types.hpp index ce7fea7a..98e635a5 100644 --- a/Sts1CobcSw/Edu/Types.hpp +++ b/Sts1CobcSw/Edu/Types.hpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include diff --git a/Sts1CobcSw/FileSystem/FileSystem.cpp b/Sts1CobcSw/FileSystem/FileSystem.cpp index 7894342a..833ec0c7 100644 --- a/Sts1CobcSw/FileSystem/FileSystem.cpp +++ b/Sts1CobcSw/FileSystem/FileSystem.cpp @@ -1,6 +1,9 @@ #include #include #include +#include + +#include #include @@ -64,9 +67,9 @@ lfs_config const lfsConfig{.context = nullptr, // TODO: Test with real HW // max. 3.5 ms acc. W25Q01JV datasheet -constexpr auto pageProgramTimeout = 5 * RODOS::MILLISECONDS; +constexpr auto pageProgramTimeout = 5 * ms; // max. 400 ms acc. W25Q01JV datasheet (lfs_config.block_size = flash::sectorSize) -constexpr auto blockEraseTimeout = 500 * RODOS::MILLISECONDS; +constexpr auto blockEraseTimeout = 500 * ms; // --- Public function definitions --- diff --git a/Sts1CobcSw/FileSystem/LfsFlash.cpp b/Sts1CobcSw/FileSystem/LfsFlash.cpp index 20b0508e..93c4e87a 100644 --- a/Sts1CobcSw/FileSystem/LfsFlash.cpp +++ b/Sts1CobcSw/FileSystem/LfsFlash.cpp @@ -4,8 +4,9 @@ #include // IWYU pragma: associated #include #include +#include -#include +#include #include #include @@ -65,9 +66,9 @@ lfs_config const lfsConfig = lfs_config{.context = nullptr, // TODO: Test with real HW // max. 3.5 ms acc. W25Q01JV datasheet -constexpr auto pageProgramTimeout = 5 * RODOS::MILLISECONDS; +constexpr auto pageProgramTimeout = 5 * ms; // max. 400 ms acc. W25Q01JV datasheet (lfs_config.block_size = flash::sectorSize) -constexpr auto blockEraseTimeout = 500 * RODOS::MILLISECONDS; +constexpr auto blockEraseTimeout = 500 * ms; auto Initialize() -> void diff --git a/Sts1CobcSw/FramSections/PersistentVariables.hpp b/Sts1CobcSw/FramSections/PersistentVariables.hpp index dbce9a98..dcd7f2b1 100644 --- a/Sts1CobcSw/FramSections/PersistentVariables.hpp +++ b/Sts1CobcSw/FramSections/PersistentVariables.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -60,7 +61,7 @@ class PersistentVariables Subsections(), PersistentVariableInfos...>(); // With a baud rate of 48 MHz we can read 6000 bytes in 1 ms, which should be more than enough - static constexpr auto spiTimeout = 1 * RODOS::MILLISECONDS; + static constexpr auto spiTimeout = 1 * ms; static RODOS::Semaphore semaphore; }; diff --git a/Sts1CobcSw/FramSections/RingArray.hpp b/Sts1CobcSw/FramSections/RingArray.hpp index 1dd53ac2..42bc7889 100644 --- a/Sts1CobcSw/FramSections/RingArray.hpp +++ b/Sts1CobcSw/FramSections/RingArray.hpp @@ -8,9 +8,8 @@ #include #include #include +#include #include -#include -#include #include diff --git a/Sts1CobcSw/FramSections/RingArray.ipp b/Sts1CobcSw/FramSections/RingArray.ipp index 1ff05ac8..85d06fe5 100644 --- a/Sts1CobcSw/FramSections/RingArray.ipp +++ b/Sts1CobcSw/FramSections/RingArray.ipp @@ -241,7 +241,7 @@ template auto RingArray::ReadElement(RingIndex index) -> T { auto address = subsections.template Get<"array">().begin + index.get() * elementSize; - return Deserialize(fram::ReadFrom>(address, value_of(spiTimeout))); + return Deserialize(fram::ReadFrom>(address, spiTimeout)); } @@ -252,6 +252,6 @@ auto RingArray::WriteElement(RingIndex ind -> void { auto address = subsections.template Get<"array">().begin + index.get() * elementSize; - fram::WriteTo(address, Span(Serialize(t)), value_of(spiTimeout)); + fram::WriteTo(address, Span(Serialize(t)), spiTimeout); } } diff --git a/Sts1CobcSw/Hal/CMakeLists.txt b/Sts1CobcSw/Hal/CMakeLists.txt index 09634516..f5f81437 100644 --- a/Sts1CobcSw/Hal/CMakeLists.txt +++ b/Sts1CobcSw/Hal/CMakeLists.txt @@ -1,6 +1,12 @@ -target_sources(Sts1CobcSw_Hal PRIVATE Uart.cpp Spi.cpp) +target_sources(Sts1CobcSw_Hal PRIVATE Spi.cpp) +target_compile_definitions(Sts1CobcSw_Hal PUBLIC HW_VERSION=${HW_VERSION}) target_link_libraries( - Sts1CobcSw_Hal PUBLIC etl::etl rodos::without_main_on_linux Sts1CobcSw_Utility - Sts1CobcSw_Outcome + Sts1CobcSw_Hal PUBLIC rodos::without_main_on_linux Sts1CobcSw_Outcome Sts1CobcSw_Utility ) -target_compile_definitions(Sts1CobcSw_Hal PUBLIC HW_VERSION=${HW_VERSION}) +target_link_libraries(Sts1CobcSw_Hal PRIVATE strong_type::strong_type) +if(CMAKE_SYSTEM_NAME STREQUAL Generic) + target_sources(Sts1CobcSw_Hal PRIVATE HardwareSpi.cpp Uart.cpp) + target_link_libraries(Sts1CobcSw_Hal PRIVATE etl::etl) +else() + target_sources(Sts1CobcSw_Hal PRIVATE SpiMock.cpp) +endif() diff --git a/Sts1CobcSw/Hal/HardwareSpi.cpp b/Sts1CobcSw/Hal/HardwareSpi.cpp new file mode 100644 index 00000000..55b4a976 --- /dev/null +++ b/Sts1CobcSw/Hal/HardwareSpi.cpp @@ -0,0 +1,72 @@ +#include + +#include + + +namespace sts1cobcsw::hal +{ +HardwareSpi::HardwareSpi(RODOS::SPI_IDX spiIndex, + RODOS::GPIO_PIN sckPin, + RODOS::GPIO_PIN misoPin, + RODOS::GPIO_PIN mosiPin) + : spi_(spiIndex, sckPin, misoPin, mosiPin) +{ +} + + +auto HardwareSpi::DoInitialize(std::uint32_t baudRate) -> void +{ + // spi.init() only returns -1 if the SPI_IDX is out of range. Since we can check that statically + // we do not need to report that error at runtime. + spi_.init(baudRate, /*slave=*/false, /*tiMode=*/false); + auto protector = RODOS::ScopeProtector(&transferEndSemaphore_); + transferEnd_ = endOfTime; +} + + +auto HardwareSpi::Read(void * data, std::size_t nBytes, Duration timeout) -> void +{ + // spi.read() only returns -1 or the given buffer length. It only returns -1 if the SPI is not + // initialized, which we can check/ensure statically. Therefore, we do not need to check the + // return value at runtime. + { + auto protector = RODOS::ScopeProtector(&transferEndSemaphore_); + transferEnd_ = CurrentRodosTime() + timeout; + } + spi_.read(data, nBytes); + { + auto protector = RODOS::ScopeProtector(&transferEndSemaphore_); + transferEnd_ = endOfTime; + } +} + + +auto HardwareSpi::Write(void const * data, std::size_t nBytes, Duration timeout) -> void +{ + // spi.write() only returns -1 or the given buffer length. It only returns -1 if the SPI is not + // initialized, which we can check/ensure statically. Therefore, we do not need to check the + // return value at runtime. + { + auto protector = RODOS::ScopeProtector(&transferEndSemaphore_); + transferEnd_ = CurrentRodosTime() + timeout; + } + spi_.write(data, nBytes); + { + auto protector = RODOS::ScopeProtector(&transferEndSemaphore_); + transferEnd_ = endOfTime; + } +} + + +auto HardwareSpi::DoTransferEnd() const -> RodosTime +{ + auto protector = RODOS::ScopeProtector(&transferEndSemaphore_); + return transferEnd_; +} + + +auto HardwareSpi::DoBaudRate() const -> std::int32_t +{ + return spi_.status(RODOS::SPI_STATUS_BAUDRATE); +} +} diff --git a/Sts1CobcSw/Hal/HardwareSpi.hpp b/Sts1CobcSw/Hal/HardwareSpi.hpp new file mode 100644 index 00000000..082b8b60 --- /dev/null +++ b/Sts1CobcSw/Hal/HardwareSpi.hpp @@ -0,0 +1,43 @@ +#pragma once + + +#include +#include +#include + +#include + +#include +#include + + +namespace sts1cobcsw::hal +{ +class HardwareSpi : public Spi +{ +public: + HardwareSpi(RODOS::SPI_IDX spiIndex, + RODOS::GPIO_PIN sckPin, + RODOS::GPIO_PIN misoPin, + RODOS::GPIO_PIN mosiPin); + HardwareSpi(HardwareSpi const &) = delete; + HardwareSpi(HardwareSpi &&) = delete; + auto operator=(HardwareSpi const &) -> HardwareSpi & = delete; + auto operator=(HardwareSpi &&) -> HardwareSpi & = delete; + ~HardwareSpi() override = default; + + +private: + auto DoInitialize(std::uint32_t baudRate) -> void override; + auto Read(void * data, std::size_t nBytes, Duration timeout) -> void override; + auto Write(void const * data, std::size_t nBytes, Duration timeout) -> void override; + [[nodiscard]] auto DoTransferEnd() const -> RodosTime override; + [[nodiscard]] auto DoBaudRate() const -> std::int32_t override; + + mutable RODOS::HAL_SPI spi_; + // This should actually be an atomic variable. Since they don't exist in Rodos, we protect it + // with a semaphore instead. + mutable RodosTime transferEnd_ = endOfTime; + mutable RODOS::Semaphore transferEndSemaphore_; +}; +} diff --git a/Sts1CobcSw/Hal/Spi.cpp b/Sts1CobcSw/Hal/Spi.cpp index 501c7532..b97c2d49 100644 --- a/Sts1CobcSw/Hal/Spi.cpp +++ b/Sts1CobcSw/Hal/Spi.cpp @@ -1,48 +1,22 @@ -#include #include -#include - namespace sts1cobcsw::hal { -Spi::Spi(RODOS::SPI_IDX spiIndex, - RODOS::GPIO_PIN sckPin, - RODOS::GPIO_PIN misoPin, - RODOS::GPIO_PIN mosiPin) - : spi_(spiIndex, sckPin, misoPin, mosiPin, spiNssDummyPin) -{ - transferEnd_.put(RODOS::END_OF_TIME); -} - - auto Initialize(Spi * spi, std::uint32_t baudRate) -> void { - // spi.init() only returns -1 if the SPI_IDX is out of range. Since we can check that statically - // we do not need to report that error at runtime. - spi->spi_.init(baudRate, /*slave=*/false, /*tiMode=*/false); - spi->transferEnd_.put(RODOS::END_OF_TIME); -} - - -auto Spi::TransferEnd() const -> std::int64_t -{ - std::int64_t transferEnd = 0; - this->transferEnd_.get(transferEnd); - return transferEnd; + spi->DoInitialize(baudRate); } -auto Spi::BaudRate() -> std::int32_t +[[nodiscard]] auto Spi::TransferEnd() const -> RodosTime { - return this->spi_.status(RODOS::SPI_STATUS_BAUDRATE); + return DoTransferEnd(); } -auto Initialize(RODOS::HAL_SPI * spi, std::uint32_t baudRate) -> void +[[nodiscard]] auto Spi::BaudRate() const -> std::int32_t { - // spi.init() only returns -1 if the SPI_IDX is out of range. Since we can check that statically - // we do not need to report that error at runtime. - spi->init(baudRate, /*slave=*/false, /*tiMode=*/false); + return DoBaudRate(); } } diff --git a/Sts1CobcSw/Hal/Spi.hpp b/Sts1CobcSw/Hal/Spi.hpp index 83946c68..a0893b5b 100644 --- a/Sts1CobcSw/Hal/Spi.hpp +++ b/Sts1CobcSw/Hal/Spi.hpp @@ -1,7 +1,7 @@ #pragma once -#include +#include #include #include @@ -10,42 +10,43 @@ namespace sts1cobcsw::hal { +// TODO: I used pImpl wrong. I used it to hide the private members of Spi to be able to include +// Spi.hpp in tests that should run on Linux (there is no RODOS::HAL_SPI there). What I really +// wanted to do though is to separate the interface from the implementation in a way that allows me +// to have a "real" implementation for the COBC target and a mock that I can use for tests. Since I +// want to test the SPI supervisor thread which requires the global SPI variables I cannot use +// compile-time polymorphism but really need runtime polymorphism. Therefore, I should have turned +// Spi into an abstract base class and implemented a "HwSpi" and an "SpiMock". Obviously we'll use +// the NVI idiom for the polymorphic SPI class. class Spi { public: - Spi() = delete; - Spi(RODOS::SPI_IDX spiIndex, - RODOS::GPIO_PIN sckPin, - RODOS::GPIO_PIN misoPin, - RODOS::GPIO_PIN mosiPin); - + Spi() = default; + Spi(Spi const &) = delete; + Spi(Spi &&) = default; + auto operator=(Spi const &) -> Spi & = delete; + auto operator=(Spi &&) -> Spi & = default; + virtual ~Spi() = default; + + // The following functions are friends and not members to keep the interface coherent with the + // rest of the low-level code. friend auto Initialize(Spi * spi, std::uint32_t baudRate) -> void; - template - friend auto WriteTo(Spi * spi, std::span data, std::int64_t timeout) -> void; - + friend auto ReadFrom(Spi * spi, std::span data, Duration timeout) -> void; template - friend auto ReadFrom(Spi * spi, std::span data, std::int64_t timeout) -> void; + friend auto WriteTo(Spi * spi, std::span data, Duration timeout) -> void; - auto TransferEnd() const -> std::int64_t; - auto BaudRate() -> std::int32_t; + [[nodiscard]] auto TransferEnd() const -> RodosTime; + [[nodiscard]] auto BaudRate() const -> std::int32_t; private: - RODOS::HAL_SPI spi_; - mutable RODOS::CommBuffer transferEnd_; + virtual auto DoInitialize(std::uint32_t baudRate) -> void = 0; + virtual auto Read(void * data, std::size_t nBytes, Duration timeout) -> void = 0; + virtual auto Write(void const * data, std::size_t nBytes, Duration timeout) -> void = 0; + [[nodiscard]] virtual auto DoTransferEnd() const -> RodosTime = 0; + [[nodiscard]] virtual auto DoBaudRate() const -> std::int32_t = 0; }; - - -auto Initialize(RODOS::HAL_SPI * spi, std::uint32_t baudRate) -> void; - -// TODO: Maybe remove extent to reduce code bloat, or probably build time since it is just a single -// call to the Rodos function, which is trivial to inline. -template -auto WriteTo(RODOS::HAL_SPI * spi, std::span data) -> void; - -template -auto ReadFrom(RODOS::HAL_SPI * spi, std::span data) -> void; } diff --git a/Sts1CobcSw/Hal/Spi.ipp b/Sts1CobcSw/Hal/Spi.ipp index ffa37ce4..e0eaeff2 100644 --- a/Sts1CobcSw/Hal/Spi.ipp +++ b/Sts1CobcSw/Hal/Spi.ipp @@ -1,53 +1,23 @@ #pragma once -#include +// IWYU pragma: private, include -#include +#include namespace sts1cobcsw::hal { template -auto WriteTo(Spi * spi, std::span data, std::int64_t timeout) -> void -{ - // spi.write() only returns -1 or the given buffer length. It only returns -1 if the SPI is not - // initialized, which we can check/ensure statically. Therefore, we do not need to check the - // return value at runtime. - spi->transferEnd_.put(RODOS::NOW() + timeout); - spi->spi_.write(data.data(), data.size_bytes()); - spi->transferEnd_.put(RODOS::END_OF_TIME); -} - - -template -auto ReadFrom(Spi * spi, std::span data, std::int64_t timeout) -> void -{ - // spi.read() only returns -1 or the given buffer length. It only returns -1 if the SPI is not - // initialized, which we can check/ensure statically. Therefore, we do not need to check the - // return value at runtime. - spi->transferEnd_.put(RODOS::NOW() + timeout); - spi->spi_.read(data.data(), data.size_bytes()); - spi->transferEnd_.put(RODOS::END_OF_TIME); -} - - -template -inline auto WriteTo(RODOS::HAL_SPI * spi, std::span data) -> void +auto WriteTo(Spi * spi, std::span data, Duration timeout) -> void { - // spi.write() only returns -1 or the given buffer length. It only returns -1 if the SPI is not - // initialized, which we can check/ensure statically. Therefore, we do not need to check the - // return value at runtime. - spi->write(data.data(), data.size_bytes()); + spi->Write(data.data(), data.size_bytes(), timeout); } template -inline auto ReadFrom(RODOS::HAL_SPI * spi, std::span data) -> void +auto ReadFrom(Spi * spi, std::span data, Duration timeout) -> void { - // spi.read() only returns -1 or the given buffer length. It only returns -1 if the SPI is not - // initialized, which we can check/ensure statically. Therefore, we do not need to check the - // return value at runtime. - spi->read(data.data(), data.size_bytes()); + spi->Read(data.data(), data.size_bytes(), timeout); } } diff --git a/Sts1CobcSw/Hal/SpiMock.cpp b/Sts1CobcSw/Hal/SpiMock.cpp new file mode 100644 index 00000000..36e8f686 --- /dev/null +++ b/Sts1CobcSw/Hal/SpiMock.cpp @@ -0,0 +1,64 @@ +#include + + +namespace sts1cobcsw::hal +{ +auto SpiMock::SetInitialize(void (*initialize)(std::uint32_t)) -> void +{ + initialize_ = initialize; +} + + +auto SpiMock::SetRead(void (*read)(void *, std::size_t, Duration)) -> void +{ + read_ = read; +} + + +auto SpiMock::SetWrite(void (*write)(void const *, std::size_t, Duration)) -> void +{ + write_ = write; +} + + +auto SpiMock::SetTransferEnd(RodosTime (*transferEnd)()) -> void +{ + transferEnd_ = transferEnd; +} + + +auto SpiMock::SetBaudRate(std::int32_t (*baudRate)()) -> void +{ + baudRate_ = baudRate; +} + + +auto SpiMock::DoInitialize(std::uint32_t baudRate) -> void +{ + initialize_(baudRate); +} + + +auto SpiMock::Read(void * data, std::size_t nBytes, Duration timeout) -> void +{ + read_(data, nBytes, timeout); +} + + +auto SpiMock::Write(void const * data, std::size_t nBytes, Duration timeout) -> void +{ + write_(data, nBytes, timeout); +} + + +auto SpiMock::DoTransferEnd() const -> RodosTime +{ + return transferEnd_(); +} + + +auto SpiMock::DoBaudRate() const -> std::int32_t +{ + return baudRate_(); +} +} diff --git a/Sts1CobcSw/Hal/SpiMock.hpp b/Sts1CobcSw/Hal/SpiMock.hpp new file mode 100644 index 00000000..81d83dcd --- /dev/null +++ b/Sts1CobcSw/Hal/SpiMock.hpp @@ -0,0 +1,43 @@ +#pragma once + + +#include +#include + +#include +#include + + +namespace sts1cobcsw::hal +{ +class SpiMock : public Spi +{ +public: + SpiMock() = default; + SpiMock(SpiMock const &) = delete; + SpiMock(SpiMock &&) = default; + auto operator=(SpiMock const &) -> SpiMock & = delete; + auto operator=(SpiMock &&) -> SpiMock & = default; + ~SpiMock() override = default; + + auto SetInitialize(void (*initialize)(std::uint32_t)) -> void; + auto SetRead(void (*read)(void *, std::size_t, Duration)) -> void; + auto SetWrite(void (*write)(void const *, std::size_t, Duration)) -> void; + auto SetTransferEnd(RodosTime (*transferEnd)()) -> void; + auto SetBaudRate(std::int32_t (*baudRate)()) -> void; + + +private: + auto DoInitialize(std::uint32_t baudRate) -> void override; + auto Read(void * data, std::size_t nBytes, Duration timeout) -> void override; + auto Write(void const * data, std::size_t nBytes, Duration timeout) -> void override; + [[nodiscard]] auto DoTransferEnd() const -> RodosTime override; + [[nodiscard]] auto DoBaudRate() const -> std::int32_t override; + + void (*initialize_)(std::uint32_t) = [](auto) {}; + void (*read_)(void *, std::size_t, Duration) = [](auto...) {}; + void (*write_)(void const *, std::size_t, Duration) = [](auto...) {}; + RodosTime (*transferEnd_)() = []() { return RodosTime{}; }; + std::int32_t (*baudRate_)() = []() { return 0; }; +}; +} diff --git a/Sts1CobcSw/Hal/Uart.cpp b/Sts1CobcSw/Hal/Uart.cpp index 180cb529..2d3b5ded 100644 --- a/Sts1CobcSw/Hal/Uart.cpp +++ b/Sts1CobcSw/Hal/Uart.cpp @@ -1,7 +1,5 @@ #include -#include - namespace sts1cobcsw::hal { diff --git a/Sts1CobcSw/Hal/Uart.ipp b/Sts1CobcSw/Hal/Uart.ipp index ceda1f55..7ae6a6b6 100644 --- a/Sts1CobcSw/Hal/Uart.ipp +++ b/Sts1CobcSw/Hal/Uart.ipp @@ -2,7 +2,7 @@ #include -#include +#include namespace sts1cobcsw::hal diff --git a/Sts1CobcSw/Periphery/CMakeLists.txt b/Sts1CobcSw/Periphery/CMakeLists.txt index d4ed69fe..310b17f8 100644 --- a/Sts1CobcSw/Periphery/CMakeLists.txt +++ b/Sts1CobcSw/Periphery/CMakeLists.txt @@ -1,11 +1,11 @@ target_link_libraries( - Sts1CobcSw_Periphery PUBLIC rodos::without_main_on_linux Sts1CobcSw_Serial Sts1CobcSw_Outcome - Sts1CobcSw_Utility + Sts1CobcSw_Periphery + PUBLIC rodos::without_main_on_linux strong_type::strong_type Sts1CobcSw_Hal Sts1CobcSw_Outcome + Sts1CobcSw_Serial Sts1CobcSw_Utility ) if(CMAKE_SYSTEM_NAME STREQUAL Generic) - target_sources(Sts1CobcSw_Periphery PRIVATE Flash.cpp Fram.cpp Rf.cpp Eps.cpp FramEpsSpi.cpp) - target_link_libraries(Sts1CobcSw_Periphery PUBLIC Sts1CobcSw_Hal) + target_sources(Sts1CobcSw_Periphery PRIVATE Eps.cpp Flash.cpp Fram.cpp Rf.cpp Spis.cpp) else() - target_sources(Sts1CobcSw_Periphery PRIVATE FramMock.cpp) + target_sources(Sts1CobcSw_Periphery PRIVATE FlashMock.cpp FramMock.cpp SpiMocks.cpp) endif() diff --git a/Sts1CobcSw/Periphery/Eps.cpp b/Sts1CobcSw/Periphery/Eps.cpp index 055005ff..5a9c63b6 100644 --- a/Sts1CobcSw/Periphery/Eps.cpp +++ b/Sts1CobcSw/Periphery/Eps.cpp @@ -2,13 +2,14 @@ #include #include #include -#include +#include #include #include #include +#include #include -#include +#include #include #include @@ -88,7 +89,7 @@ enum class ResetType // --- Private globals --- -constexpr auto spiTimeout = 1 * RODOS::MILLISECONDS; +constexpr auto spiTimeout = 1 * ms; auto adc4CsGpioPin = hal::GpioPin(hal::epsAdc4CsPin); auto adc5CsGpioPin = hal::GpioPin(hal::epsAdc5CsPin); @@ -226,8 +227,8 @@ auto ReadAdc(hal::GpioPin * adcCsPin) -> AdcValues // According to the datasheet at most 514 conversions are done after a conversion command // (depends on averaging and channels). This takes 514 * (t_acq + t_conv) + wakeup = 514 * (0.6 // + 3.5) us + 65 us = 2172.4 us. - static constexpr auto conversionTime = 3 * RODOS::MILLISECONDS; - RODOS::AT(RODOS::NOW() + conversionTime); + static constexpr auto conversionTime = 3 * ms; + SuspendFor(conversionTime); // Resolution is 12 bit, sent like this: [0 0 0 0 MSB x x x], [x x x x x x x LSB] auto adcData = SerialBuffer{}; diff --git a/Sts1CobcSw/Periphery/Flash.cpp b/Sts1CobcSw/Periphery/Flash.cpp index 107a5ccf..da39ab0e 100644 --- a/Sts1CobcSw/Periphery/Flash.cpp +++ b/Sts1CobcSw/Periphery/Flash.cpp @@ -1,14 +1,20 @@ #include #include +#include #include +#include #include #include +#include #include -#include +#include +#include +#include #include #include +#include namespace sts1cobcsw @@ -30,17 +36,11 @@ struct SimpleInstruction }; -// --- Public globals --- - -hal::Spi spi = - hal::Spi(hal::flashSpiIndex, hal::flashSpiSckPin, hal::flashSpiMisoPin, hal::flashSpiMosiPin); - - // --- Private globals --- // Baud rate = 48 MHz, largest data transfer = 1 page = 256 bytes -> spiTimeout = 1 ms is enough for // all transfers -constexpr auto spiTimeout = 1 * RODOS::MILLISECONDS; +constexpr auto spiTimeout = 1 * ms; constexpr auto endianness = std::endian::big; // Instructions according to section 7.3 in W25Q01JV datasheet @@ -68,13 +68,13 @@ auto DisableWriting() -> void; auto IsBusy() -> bool; template -auto Write(std::span data, std::int64_t timeout) -> void; +auto Write(std::span data, Duration timeout) -> void; template -auto Read(std::span data, std::int64_t timeout) -> void; +auto Read(std::span data, Duration timeout) -> void; template -auto Read(std::int64_t timeout) -> std::array; +auto Read(Duration timeout) -> std::array; template requires(instruction.answerLength > 0) @@ -97,7 +97,7 @@ auto Initialize() -> void writeProtectionGpioPin.Direction(hal::PinDirection::out); writeProtectionGpioPin.Set(); auto const baudRate = 48'000'000; - Initialize(&spi, baudRate); + Initialize(&flashSpi, baudRate); Enter4ByteAdressMode(); } @@ -169,17 +169,17 @@ auto EraseSector(std::uint32_t address) -> void } -auto WaitWhileBusy(std::int64_t timeout) -> Result +auto WaitWhileBusy(Duration timeout) -> Result { - auto const pollingCycleTime = 1 * RODOS::MILLISECONDS; - auto const reactivationTime = RODOS::NOW() + timeout; + auto const pollingCycleTime = 1 * ms; + auto const reactivationTime = CurrentRodosTime() + timeout; while(IsBusy()) { - if(RODOS::NOW() >= reactivationTime) + if(CurrentRodosTime() >= reactivationTime) { return ErrorCode::timeout; } - RODOS::AT(RODOS::NOW() + pollingCycleTime); + SuspendFor(pollingCycleTime); } return outcome_v2::success(); } @@ -187,7 +187,7 @@ auto WaitWhileBusy(std::int64_t timeout) -> Result auto ActualBaudRate() -> std::int32_t { - return spi.BaudRate(); + return flashSpi.BaudRate(); } @@ -225,24 +225,24 @@ auto IsBusy() -> bool template -inline auto Write(std::span data, std::int64_t timeout) -> void +inline auto Write(std::span data, Duration timeout) -> void { - hal::WriteTo(&spi, data, timeout); + hal::WriteTo(&flashSpi, data, timeout); } template -inline auto Read(std::span data, std::int64_t timeout) -> void +inline auto Read(std::span data, Duration timeout) -> void { - hal::ReadFrom(&spi, data, timeout); + hal::ReadFrom(&flashSpi, data, timeout); } template -inline auto Read(std::int64_t timeout) -> std::array +inline auto Read(Duration timeout) -> std::array { auto answer = std::array{}; - hal::ReadFrom(&spi, Span(&answer), timeout); + hal::ReadFrom(&flashSpi, Span(&answer), timeout); return answer; } diff --git a/Sts1CobcSw/Periphery/Flash.hpp b/Sts1CobcSw/Periphery/Flash.hpp index 0af79878..d28326e1 100644 --- a/Sts1CobcSw/Periphery/Flash.hpp +++ b/Sts1CobcSw/Periphery/Flash.hpp @@ -4,9 +4,9 @@ #pragma once -#include #include #include +#include #include #include @@ -49,8 +49,6 @@ using PageSpan = std::span; inline constexpr auto correctJedecId = JedecId{.manufacturerId = 0xEF, .deviceId = 0x4021}; -extern hal::Spi spi; - // TODO: Proper error handling/return type auto Initialize() -> void; @@ -60,6 +58,6 @@ auto Initialize() -> void; [[nodiscard]] auto ReadPage(std::uint32_t address) -> Page; auto ProgramPage(std::uint32_t address, PageSpan data) -> void; auto EraseSector(std::uint32_t address) -> void; -[[nodiscard]] auto WaitWhileBusy(std::int64_t timeout) -> Result; +[[nodiscard]] auto WaitWhileBusy(Duration timeout) -> Result; auto ActualBaudRate() -> std::int32_t; } diff --git a/Sts1CobcSw/Periphery/FlashMock.cpp b/Sts1CobcSw/Periphery/FlashMock.cpp new file mode 100644 index 00000000..43bb7502 --- /dev/null +++ b/Sts1CobcSw/Periphery/FlashMock.cpp @@ -0,0 +1,180 @@ +#include +#include + + +namespace sts1cobcsw::flash +{ +auto doInitialize = empty::DoInitialize; +auto doReadJedecId = empty::DoReadJedecId; +auto doReadStatusRegister = empty::DoReadStatusRegister; + +auto doReadPage = empty::DoReadPage; +auto doProgramPage = empty::DoProgramPage; +auto doEraseSector = empty::DoEraseSector; +auto doWaitWhileBusy = empty::DoWaitWhileBusy; +auto doActualBaudRate = empty::DoActualBaudRate; + + +// --- Mocked functions --- + +auto Initialize() -> void +{ + return doInitialize(); +} + + +auto ReadJedecId() -> JedecId +{ + return doReadJedecId(); +} + + +auto ReadStatusRegister(std::int8_t registerNo) -> Byte +{ + return doReadStatusRegister(registerNo); +} + + +auto ReadPage(std::uint32_t address) -> Page +{ + return doReadPage(address); +} + + +auto ProgramPage(std::uint32_t address, PageSpan data) -> void +{ + return doProgramPage(address, data); +} + + +auto EraseSector(std::uint32_t address) -> void +{ + return doEraseSector(address); +} + + +auto WaitWhileBusy(Duration timeout) -> Result +{ + return doWaitWhileBusy(timeout); +} + + +auto ActualBaudRate() -> std::int32_t +{ + return doActualBaudRate(); +} + + +// --- Set functions --- + +auto SetDoInitialize(void (*doInitializeFunction)()) -> void +{ + doInitialize = doInitializeFunction; +} + + +auto SetDoReadJedecId(JedecId (*doReadJedecIdFunction)()) -> void +{ + doReadJedecId = doReadJedecIdFunction; +} + + +auto SetDoReadStatusRegister(Byte (*doReadStatusRegisterFunction)(std::int8_t registerNo)) -> void +{ + doReadStatusRegister = doReadStatusRegisterFunction; +} + + +auto SetDoReadPage(Page (*doReadPageFunction)(std::uint32_t address)) -> void +{ + doReadPage = doReadPageFunction; +} + + +auto SetDoProgramPage(void (*doProgramPageFunction)(std::uint32_t address, PageSpan data)) -> void +{ + doProgramPage = doProgramPageFunction; +} + + +auto SetDoEraseSector(void (*doEraseSectorFunction)(std::uint32_t address)) -> void +{ + doEraseSector = doEraseSectorFunction; +} + + +auto SetDoWaitWhileBusy(Result (*doWaitWhileBusyFunction)(Duration timeout)) -> void +{ + doWaitWhileBusy = doWaitWhileBusyFunction; +} + + +auto SetDoActualBaudRate(std::int32_t (*doActualBaudRateFunction)()) -> void +{ + doActualBaudRate = doActualBaudRateFunction; +} + + +// --- Predefined do functions --- + +namespace empty +{ +auto SetAllDoFunctions() -> void +{ + SetDoInitialize(DoInitialize); + SetDoReadJedecId(DoReadJedecId); + SetDoReadStatusRegister(DoReadStatusRegister); + + SetDoReadPage(DoReadPage); + SetDoProgramPage(DoProgramPage); + SetDoEraseSector(DoEraseSector); + SetDoWaitWhileBusy(DoWaitWhileBusy); + SetDoActualBaudRate(DoActualBaudRate); +} + + +auto DoInitialize() -> void +{ +} + + +auto DoReadJedecId() -> JedecId +{ + return JedecId{}; +} + + +auto DoReadStatusRegister([[maybe_unused]] std::int8_t registerNo) -> Byte +{ + return Byte{0}; +} + + +auto DoReadPage([[maybe_unused]] std::uint32_t address) -> Page +{ + return Page{}; +} + + +auto DoProgramPage([[maybe_unused]] std::uint32_t address, [[maybe_unused]] PageSpan data) -> void +{ +} + + +auto DoEraseSector([[maybe_unused]] std::uint32_t address) -> void +{ +} + + +auto DoWaitWhileBusy([[maybe_unused]] Duration timeout) -> Result +{ + return outcome_v2::success(); +} + + +auto DoActualBaudRate() -> std::int32_t +{ + return 0; +} +} +} diff --git a/Sts1CobcSw/Periphery/FlashMock.hpp b/Sts1CobcSw/Periphery/FlashMock.hpp new file mode 100644 index 00000000..ec58ab66 --- /dev/null +++ b/Sts1CobcSw/Periphery/FlashMock.hpp @@ -0,0 +1,37 @@ +#pragma once + + +#include +#include +#include + +#include + + +namespace sts1cobcsw::flash +{ +auto SetDoInitialize(void (*doInitializeFunction)()) -> void; +auto SetDoReadJedecId(JedecId (*doReadJedecIdFunction)()) -> void; +auto SetDoReadStatusRegister(Byte (*doReadStatusRegisterFunction)(std::int8_t registerNo)) -> void; + +auto SetDoReadPage(Page (*doReadPageFunction)(std::uint32_t address)) -> void; +auto SetDoProgramPage(void (*doProgramPageFunction)(std::uint32_t address, PageSpan data)) -> void; +auto SetDoEraseSector(void (*doEraseSectorFunction)(std::uint32_t address)) -> void; +auto SetDoWaitWhileBusyFunction(Result (*doWaitWhileBusy)(Duration timeout)) -> void; +auto SetDoActualBaudRate(std::int32_t (*doActualBaudRateFunction)()) -> void; + +namespace empty +{ +auto SetAllDoFunctions() -> void; + +auto DoInitialize() -> void; +auto DoReadJedecId() -> JedecId; +auto DoReadStatusRegister(std::int8_t registerNo) -> Byte; + +auto DoReadPage(std::uint32_t address) -> Page; +auto DoProgramPage(std::uint32_t address, PageSpan data) -> void; +auto DoEraseSector(std::uint32_t address) -> void; +auto DoWaitWhileBusy(Duration timeout) -> Result; +auto DoActualBaudRate() -> std::int32_t; +} +} diff --git a/Sts1CobcSw/Periphery/Fram.cpp b/Sts1CobcSw/Periphery/Fram.cpp index 6f3ea342..736c8b9e 100644 --- a/Sts1CobcSw/Periphery/Fram.cpp +++ b/Sts1CobcSw/Periphery/Fram.cpp @@ -5,12 +5,11 @@ #include #include #include -#include +#include #include +#include #include -#include - #include @@ -23,7 +22,7 @@ EdacVariable framIsWorking(true); // --- Private globals --- -constexpr auto spiTimeout = 1 * RODOS::MILLISECONDS; +constexpr auto spiTimeout = 1 * ms; constexpr auto endianness = std::endian::big; // Command opcodes according to section 4.1 in CY15B108QN-40SXI datasheet. I couldn't use an enum @@ -76,7 +75,7 @@ auto ActualBaudRate() -> std::int32_t namespace internal { -auto WriteTo(Address address, void const * data, std::size_t nBytes, std::int64_t timeout) -> void +auto WriteTo(Address address, void const * data, std::size_t nBytes, Duration timeout) -> void { SetWriteEnableLatch(); csGpioPin.Reset(); @@ -89,7 +88,7 @@ auto WriteTo(Address address, void const * data, std::size_t nBytes, std::int64_ } -auto ReadFrom(Address address, void * data, std::size_t nBytes, std::int64_t timeout) -> void +auto ReadFrom(Address address, void * data, std::size_t nBytes, Duration timeout) -> void { csGpioPin.Reset(); hal::WriteTo(&framEpsSpi, Span(opcode::readData), spiTimeout); diff --git a/Sts1CobcSw/Periphery/Fram.hpp b/Sts1CobcSw/Periphery/Fram.hpp index 906bcbf9..61784082 100644 --- a/Sts1CobcSw/Periphery/Fram.hpp +++ b/Sts1CobcSw/Periphery/Fram.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -44,21 +45,21 @@ auto Initialize() -> void; auto ActualBaudRate() -> std::int32_t; template -auto WriteTo(Address address, std::span data, std::int64_t timeout) -> void; +auto WriteTo(Address address, std::span data, Duration timeout) -> void; template -auto ReadFrom(Address address, std::span data, std::int64_t timeout) -> void; +auto ReadFrom(Address address, std::span data, Duration timeout) -> void; template -[[nodiscard]] auto ReadFrom(Address address, std::int64_t timeout) -> std::array; +[[nodiscard]] auto ReadFrom(Address address, Duration timeout) -> std::array; // Contents of namespace internal is only for internal use and not part of the public interface. The // declarations here are necessary because of templates. namespace internal { -auto WriteTo(Address address, void const * data, std::size_t nBytes, std::int64_t timeout) -> void; -auto ReadFrom(Address address, void * data, std::size_t nBytes, std::int64_t timeout) -> void; +auto WriteTo(Address address, void const * data, std::size_t nBytes, Duration timeout) -> void; +auto ReadFrom(Address address, void * data, std::size_t nBytes, Duration timeout) -> void; } } diff --git a/Sts1CobcSw/Periphery/Fram.ipp b/Sts1CobcSw/Periphery/Fram.ipp index adb19f1b..fc868701 100644 --- a/Sts1CobcSw/Periphery/Fram.ipp +++ b/Sts1CobcSw/Periphery/Fram.ipp @@ -7,22 +7,21 @@ namespace sts1cobcsw::fram { template -inline auto WriteTo(Address address, std::span data, std::int64_t timeout) - -> void +inline auto WriteTo(Address address, std::span data, Duration timeout) -> void { internal::WriteTo(address, data.data(), data.size(), timeout); } template -inline auto ReadFrom(Address address, std::span data, std::int64_t timeout) -> void +inline auto ReadFrom(Address address, std::span data, Duration timeout) -> void { internal::ReadFrom(address, data.data(), data.size(), timeout); } template -auto ReadFrom(Address address, std::int64_t timeout) -> std::array +auto ReadFrom(Address address, Duration timeout) -> std::array { auto data = std::array{}; internal::ReadFrom(address, data.data(), data.size(), timeout); diff --git a/Sts1CobcSw/Periphery/FramEpsSpi.cpp b/Sts1CobcSw/Periphery/FramEpsSpi.cpp deleted file mode 100644 index 5a38f180..00000000 --- a/Sts1CobcSw/Periphery/FramEpsSpi.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include -#include -#include - - -namespace sts1cobcsw -{ -hal::Spi framEpsSpi = hal::Spi( - hal::framEpsSpiIndex, hal::framEpsSpiSckPin, hal::framEpsSpiMisoPin, hal::framEpsSpiMosiPin); -} diff --git a/Sts1CobcSw/Periphery/FramEpsSpi.hpp b/Sts1CobcSw/Periphery/FramEpsSpi.hpp deleted file mode 100644 index 82edff72..00000000 --- a/Sts1CobcSw/Periphery/FramEpsSpi.hpp +++ /dev/null @@ -1,7 +0,0 @@ -#include - - -namespace sts1cobcsw -{ -extern hal::Spi framEpsSpi; -} diff --git a/Sts1CobcSw/Periphery/FramMock.cpp b/Sts1CobcSw/Periphery/FramMock.cpp index b5402430..906202e9 100644 --- a/Sts1CobcSw/Periphery/FramMock.cpp +++ b/Sts1CobcSw/Periphery/FramMock.cpp @@ -41,13 +41,13 @@ auto ActualBaudRate() -> std::int32_t namespace internal { -auto WriteTo(Address address, void const * data, std::size_t nBytes, std::int64_t timeout) -> void +auto WriteTo(Address address, void const * data, std::size_t nBytes, Duration timeout) -> void { return doWriteTo(address, data, nBytes, timeout); } -auto ReadFrom(Address address, void * data, std::size_t nBytes, std::int64_t timeout) -> void +auto ReadFrom(Address address, void * data, std::size_t nBytes, Duration timeout) -> void { return doReadFrom(address, data, nBytes, timeout); } @@ -75,14 +75,14 @@ void SetDoActualBaudRate(std::int32_t (*doActualBaudRateFunction)()) auto SetDoWriteTo(void (*doWriteToFunction)( - Address address, void const * data, std::size_t nBytes, std::int64_t timeout)) -> void + Address address, void const * data, std::size_t nBytes, Duration timeout)) -> void { doWriteTo = doWriteToFunction; } auto SetDoReadFrom(void (*doReadFromFunction)( - Address address, void * data, std::size_t nBytes, std::int64_t timeout)) -> void + Address address, void * data, std::size_t nBytes, Duration timeout)) -> void { doReadFrom = doReadFromFunction; } @@ -122,7 +122,7 @@ auto DoActualBaudRate() -> std::int32_t auto DoWriteTo([[maybe_unused]] Address address, [[maybe_unused]] void const * data, [[maybe_unused]] std::size_t nBytes, - [[maybe_unused]] std::int64_t timeout) -> void + [[maybe_unused]] Duration timeout) -> void { } @@ -130,7 +130,7 @@ auto DoWriteTo([[maybe_unused]] Address address, auto DoReadFrom([[maybe_unused]] Address address, [[maybe_unused]] void * data, [[maybe_unused]] std::size_t nBytes, - [[maybe_unused]] std::int64_t timeout) -> void + [[maybe_unused]] Duration timeout) -> void { } } @@ -171,16 +171,14 @@ auto DoActualBaudRate() -> std::int32_t auto DoWriteTo(Address address, void const * data, std::size_t nBytes, - [[maybe_unused]] std::int64_t timeout) -> void + [[maybe_unused]] Duration timeout) -> void { std::memcpy(memory.data() + value_of(address), data, nBytes); } -auto DoReadFrom(Address address, - void * data, - std::size_t nBytes, - [[maybe_unused]] std::int64_t timeout) -> void +auto DoReadFrom(Address address, void * data, std::size_t nBytes, [[maybe_unused]] Duration timeout) + -> void { std::memcpy(data, memory.data() + value_of(address), nBytes); } diff --git a/Sts1CobcSw/Periphery/FramMock.hpp b/Sts1CobcSw/Periphery/FramMock.hpp index 6afc49ea..1a94f737 100644 --- a/Sts1CobcSw/Periphery/FramMock.hpp +++ b/Sts1CobcSw/Periphery/FramMock.hpp @@ -3,6 +3,7 @@ #include #include +#include #include @@ -17,9 +18,9 @@ auto SetDoInitialize(void (*doInitializeFunction)()) -> void; auto SetDoReadDeviceId(DeviceId (*doReadDeviceIdFunction)()) -> void; auto SetDoActualBaudRate(std::int32_t (*doActualBaudRateFunction)()) -> void; auto SetDoWriteTo(void (*doWriteToFunction)( - Address address, void const * data, std::size_t nBytes, std::int64_t timeout)) -> void; + Address address, void const * data, std::size_t nBytes, Duration timeout)) -> void; auto SetDoReadFrom(void (*doReadFromFunction)( - Address address, void * data, std::size_t nBytes, std::int64_t timeout)) -> void; + Address address, void * data, std::size_t nBytes, Duration timeout)) -> void; // Empty do functions that do nothing; used to initialized function pointers @@ -30,9 +31,8 @@ auto SetAllDoFunctions() -> void; auto DoInitialize() -> void; auto DoReadDeviceId() -> DeviceId; auto DoActualBaudRate() -> std::int32_t; -auto DoWriteTo(Address address, void const * data, std::size_t nBytes, std::int64_t timeout) - -> void; -auto DoReadFrom(Address address, void * data, std::size_t nBytes, std::int64_t timeout) -> void; +auto DoWriteTo(Address address, void const * data, std::size_t nBytes, Duration timeout) -> void; +auto DoReadFrom(Address address, void * data, std::size_t nBytes, Duration timeout) -> void; } @@ -47,8 +47,7 @@ auto SetAllDoFunctions() -> void; auto DoInitialize() -> void; auto DoReadDeviceId() -> DeviceId; auto DoActualBaudRate() -> std::int32_t; -auto DoWriteTo(Address address, void const * data, std::size_t nBytes, std::int64_t timeout) - -> void; -auto DoReadFrom(Address address, void * data, std::size_t nBytes, std::int64_t timeout) -> void; +auto DoWriteTo(Address address, void const * data, std::size_t nBytes, Duration timeout) -> void; +auto DoReadFrom(Address address, void * data, std::size_t nBytes, Duration timeout) -> void; } } diff --git a/Sts1CobcSw/Periphery/Rf.cpp b/Sts1CobcSw/Periphery/Rf.cpp index 7a9e3977..1b54b491 100644 --- a/Sts1CobcSw/Periphery/Rf.cpp +++ b/Sts1CobcSw/Periphery/Rf.cpp @@ -6,13 +6,16 @@ #include #include +#include #include +#include #include #include #include +#include #include -#include +#include #include #include @@ -22,12 +25,6 @@ namespace sts1cobcsw::rf { -using RODOS::AT; -using RODOS::MICROSECONDS; -using RODOS::MILLISECONDS; -using RODOS::NOW; - - enum class PropertyGroup : std::uint8_t { global = 0x00, // @@ -49,7 +46,6 @@ enum class PropertyGroup : std::uint8_t // --- Public globals --- -hal::Spi spi = hal::Spi(hal::rfSpiIndex, hal::rfSpiSckPin, hal::rfSpiMisoPin, hal::rfSpiMosiPin); bool rfIsWorking = true; @@ -72,13 +68,13 @@ constexpr auto partInfoAnswerLength = 8U; constexpr auto maxNProperties = 12; // Delay to wait for power on reset to finish -constexpr auto porRunningDelay = 20 * MILLISECONDS; +constexpr auto porRunningDelay = 20 * ms; // Time until PoR circuit settles after applying power -constexpr auto porCircuitSettleDelay = 100 * MILLISECONDS; +constexpr auto porCircuitSettleDelay = 100 * ms; // Delay for the sequence reset -> pause -> set -> pause -> reset in initialization -constexpr auto watchDogResetPinDelay = 1 * MILLISECONDS; +constexpr auto watchDogResetPinDelay = 1 * ms; // TODO: Check this and write a good comment -constexpr auto spiTimeout = 1 * RODOS::MILLISECONDS; +constexpr auto spiTimeout = 1 * ms; auto csGpioPin = hal::GpioPin(hal::rfCsPin); auto nirqGpioPin = hal::GpioPin(hal::rfNirqPin); @@ -175,18 +171,18 @@ auto InitializeGpiosAndSpi() -> void gpio0GpioPin.Reset(); watchdogResetGpioPin.Direction(hal::PinDirection::out); watchdogResetGpioPin.Reset(); - AT(NOW() + watchDogResetPinDelay); + SuspendFor(watchDogResetPinDelay); watchdogResetGpioPin.Set(); - AT(NOW() + watchDogResetPinDelay); + SuspendFor(watchDogResetPinDelay); watchdogResetGpioPin.Reset(); constexpr auto baudrate = 6'000'000; - Initialize(&spi, baudrate); + Initialize(&rfSpi, baudrate); // Enable Si4463 and wait for PoR to finish - AT(NOW() + porCircuitSettleDelay); + SuspendFor(porCircuitSettleDelay); sdnGpioPin.Reset(); - AT(NOW() + porRunningDelay); + SuspendFor(porRunningDelay); } @@ -759,7 +755,7 @@ auto Configure(TxType txType) -> void auto SendCommand(std::span data) -> void { csGpioPin.Reset(); - hal::WriteTo(&spi, data, spiTimeout); + hal::WriteTo(&rfSpi, data, spiTimeout); csGpioPin.Set(); WaitForCts(); } @@ -771,7 +767,7 @@ auto SendCommand(std::span data) -> std::array SendCommand(data); auto answer = std::array{}; csGpioPin.Reset(); - hal::ReadFrom(&spi, Span(&answer), spiTimeout); + hal::ReadFrom(&rfSpi, Span(&answer), spiTimeout); csGpioPin.Set(); return answer; } @@ -784,9 +780,9 @@ auto WaitForCts() -> void do { csGpioPin.Reset(); - hal::WriteTo(&spi, Span(cmdReadCmdBuff), spiTimeout); + hal::WriteTo(&rfSpi, Span(cmdReadCmdBuff), spiTimeout); auto cts = 0x00_b; - hal::ReadFrom(&spi, Span(&cts), spiTimeout); + hal::ReadFrom(&rfSpi, Span(&cts), spiTimeout); csGpioPin.Set(); if(cts == dataIsReadyValue) { diff --git a/Sts1CobcSw/Periphery/Rf.hpp b/Sts1CobcSw/Periphery/Rf.hpp index 6ef8fcc3..4f5aea07 100644 --- a/Sts1CobcSw/Periphery/Rf.hpp +++ b/Sts1CobcSw/Periphery/Rf.hpp @@ -1,8 +1,6 @@ #pragma once -#include - #include @@ -17,7 +15,6 @@ enum class TxType inline constexpr auto correctPartNumber = 0x4463; -extern hal::Spi spi; extern bool rfIsWorking; diff --git a/Sts1CobcSw/Periphery/SpiMocks.cpp b/Sts1CobcSw/Periphery/SpiMocks.cpp new file mode 100644 index 00000000..abaa8b15 --- /dev/null +++ b/Sts1CobcSw/Periphery/SpiMocks.cpp @@ -0,0 +1,14 @@ +#include +#include // IWYU pragma: associated + + +namespace sts1cobcsw +{ +auto flashSpiMock = hal::SpiMock{}; +auto framEpsSpiMock = hal::SpiMock{}; +auto rfSpiMock = hal::SpiMock{}; + +hal::Spi & flashSpi = flashSpiMock; +hal::Spi & framEpsSpi = framEpsSpiMock; +hal::Spi & rfSpi = rfSpiMock; +} diff --git a/Sts1CobcSw/Periphery/Spis.cpp b/Sts1CobcSw/Periphery/Spis.cpp new file mode 100644 index 00000000..a7718bd9 --- /dev/null +++ b/Sts1CobcSw/Periphery/Spis.cpp @@ -0,0 +1,18 @@ +#include +#include +#include + + +namespace sts1cobcsw +{ +auto hardwareFlashSpi = hal::HardwareSpi( + hal::flashSpiIndex, hal::flashSpiSckPin, hal::flashSpiMisoPin, hal::flashSpiMosiPin); +auto hardwareFramEpsSpi = hal::HardwareSpi( + hal::framEpsSpiIndex, hal::framEpsSpiSckPin, hal::framEpsSpiMisoPin, hal::framEpsSpiMosiPin); +auto hardwareRfSpi = + hal::HardwareSpi(hal::rfSpiIndex, hal::rfSpiSckPin, hal::rfSpiMisoPin, hal::rfSpiMosiPin); + +hal::Spi & flashSpi = hardwareFlashSpi; +hal::Spi & framEpsSpi = hardwareFramEpsSpi; +hal::Spi & rfSpi = hardwareRfSpi; +} diff --git a/Sts1CobcSw/Periphery/Spis.hpp b/Sts1CobcSw/Periphery/Spis.hpp new file mode 100644 index 00000000..1b0527c1 --- /dev/null +++ b/Sts1CobcSw/Periphery/Spis.hpp @@ -0,0 +1,9 @@ +#include + + +namespace sts1cobcsw +{ +extern hal::Spi & flashSpi; +extern hal::Spi & framEpsSpi; +extern hal::Spi & rfSpi; +} diff --git a/Sts1CobcSw/Utility/Debug.hpp b/Sts1CobcSw/Utility/Debug.hpp index a9646a8d..37a14962 100644 --- a/Sts1CobcSw/Utility/Debug.hpp +++ b/Sts1CobcSw/Utility/Debug.hpp @@ -1,7 +1,7 @@ #pragma once -#include +#include #include diff --git a/Sts1CobcSw/Utility/RealTime.hpp b/Sts1CobcSw/Utility/RealTime.hpp new file mode 100644 index 00000000..9b532842 --- /dev/null +++ b/Sts1CobcSw/Utility/RealTime.hpp @@ -0,0 +1,26 @@ +#pragma once + + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + + +namespace sts1cobcsw +{ +[[nodiscard]] auto CurrentRealTime() -> RealTime; +[[nodiscard]] auto ToRodosTime(RealTime realTime) -> RodosTime; +[[nodiscard]] auto ToRealTime(RodosTime rodosTime) -> RealTime; +} + + +#include // IWYU pragma: keep diff --git a/Sts1CobcSw/Utility/Time.ipp b/Sts1CobcSw/Utility/RealTime.ipp similarity index 58% rename from Sts1CobcSw/Utility/Time.ipp rename to Sts1CobcSw/Utility/RealTime.ipp index ca4d941a..5cbe1d84 100644 --- a/Sts1CobcSw/Utility/Time.ipp +++ b/Sts1CobcSw/Utility/RealTime.ipp @@ -2,48 +2,29 @@ #include -#include -#include +#include -#include +#include namespace sts1cobcsw { -inline auto ToRodosTime(RealTime realTime) -> RodosTime -{ - return RodosTime(value_of(realTime) * RODOS::SECONDS) - - persistentVariables.template Load<"realTimeOffset">(); -} - - -inline auto ToRealTime(RodosTime rodosTime) -> RealTime -{ - return RealTime(value_of(rodosTime + persistentVariables.template Load<"realTimeOffset">()) - / RODOS::SECONDS); -} - - inline auto CurrentRealTime() -> RealTime { return ToRealTime(CurrentRodosTime()); } -inline auto CurrentRodosTime() -> RodosTime -{ - return RodosTime(RODOS::NOW()); -} - - -inline auto SuspendUntil(RodosTime time) -> void +inline auto ToRodosTime(RealTime realTime) -> RodosTime { - RODOS::AT(value_of(time)); + return RodosTime(value_of(realTime) * RODOS::SECONDS) + - persistentVariables.template Load<"realTimeOffset">(); } -inline auto SuspendFor(Duration duration) -> void +inline auto ToRealTime(RodosTime rodosTime) -> RealTime { - RODOS::AT(RODOS::NOW() + value_of(duration)); + return RealTime(value_of(rodosTime + persistentVariables.template Load<"realTimeOffset">()) + / RODOS::SECONDS); } } diff --git a/Sts1CobcSw/Utility/RodosTime.hpp b/Sts1CobcSw/Utility/RodosTime.hpp new file mode 100644 index 00000000..6e2286d9 --- /dev/null +++ b/Sts1CobcSw/Utility/RodosTime.hpp @@ -0,0 +1,30 @@ +#pragma once + + +#include + +#include + + +namespace sts1cobcsw +{ +// NOLINTBEGIN(readability-identifier-length) +constexpr auto s = Duration(RODOS::SECONDS); +constexpr auto ms = Duration(RODOS::MILLISECONDS); +constexpr auto us = Duration(RODOS::MICROSECONDS); +constexpr auto ns = Duration(RODOS::NANOSECONDS); +constexpr auto min = Duration(RODOS::MINUTES); +constexpr auto h = Duration(RODOS::HOURS); +// NOLINTEND(readability-identifier-length) +constexpr auto days = Duration(RODOS::DAYS); +constexpr auto weeks = Duration(RODOS::WEEKS); +constexpr auto endOfTime = RodosTime(RODOS::END_OF_TIME); + + +[[nodiscard]] auto CurrentRodosTime() -> RodosTime; +auto SuspendUntil(RodosTime time) -> void; +auto SuspendFor(Duration duration) -> void; +} + + +#include // IWYU pragma: keep diff --git a/Sts1CobcSw/Utility/RodosTime.ipp b/Sts1CobcSw/Utility/RodosTime.ipp new file mode 100644 index 00000000..a5f35a36 --- /dev/null +++ b/Sts1CobcSw/Utility/RodosTime.ipp @@ -0,0 +1,27 @@ +#pragma once + + +#include + +#include + + +namespace sts1cobcsw +{ +inline auto CurrentRodosTime() -> RodosTime +{ + return RodosTime(RODOS::NOW()); +} + + +inline auto SuspendUntil(RodosTime time) -> void +{ + RODOS::AT(value_of(time)); +} + + +inline auto SuspendFor(Duration duration) -> void +{ + RODOS::AT(RODOS::NOW() + value_of(duration)); +} +} diff --git a/Sts1CobcSw/Utility/Time.hpp b/Sts1CobcSw/Utility/Time.hpp deleted file mode 100644 index e559c0e9..00000000 --- a/Sts1CobcSw/Utility/Time.hpp +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - - -#include - -#include - - -namespace sts1cobcsw -{ -constexpr auto seconds = Duration(RODOS::SECONDS); -constexpr auto milliseconds = Duration(RODOS::MILLISECONDS); -constexpr auto microseconds = Duration(RODOS::MICROSECONDS); -constexpr auto nanoseconds = Duration(RODOS::NANOSECONDS); -constexpr auto minutes = Duration(RODOS::MINUTES); -constexpr auto hours = Duration(RODOS::HOURS); -constexpr auto days = Duration(RODOS::DAYS); -constexpr auto weeks = Duration(RODOS::WEEKS); -// NOLINTBEGIN(readability-identifier-length) -constexpr auto s = seconds; -constexpr auto ms = milliseconds; -constexpr auto us = microseconds; -constexpr auto ns = nanoseconds; -constexpr auto min = minutes; -constexpr auto h = hours; -constexpr auto d = days; -constexpr auto w = weeks; -// NOLINTEND(readability-identifier-length) -constexpr auto endOfTime = RodosTime(RODOS::END_OF_TIME); - - -[[nodiscard]] auto ToRodosTime(RealTime realTime) -> RodosTime; -[[nodiscard]] auto ToRealTime(RodosTime rodosTime) -> RealTime; -[[nodiscard]] auto CurrentRealTime() -> RealTime; -[[nodiscard]] auto CurrentRodosTime() -> RodosTime; -auto SuspendUntil(RodosTime time) -> void; -auto SuspendFor(Duration duration) -> void; -} - - -#include // IWYU pragma: keep diff --git a/Sts1CobcSw/Utility/TimeTypes.hpp b/Sts1CobcSw/Utility/TimeTypes.hpp index 587a20e3..894c35c9 100644 --- a/Sts1CobcSw/Utility/TimeTypes.hpp +++ b/Sts1CobcSw/Utility/TimeTypes.hpp @@ -1,5 +1,6 @@ #pragma once + #include #include @@ -15,13 +16,12 @@ namespace sts1cobcsw { -using Duration = strong::type; +using Duration = strong:: + type; using RodosTime = strong::type, + strong::default_constructible, strong::equality, strong::strongly_ordered>; using RealTime = strong::type } -#include "TimeTypes.ipp" // IWYU pragma: keep +#include // IWYU pragma: keep diff --git a/Sts1CobcSw/Utility/TimeTypes.ipp b/Sts1CobcSw/Utility/TimeTypes.ipp index d745cab0..b2f2cd46 100644 --- a/Sts1CobcSw/Utility/TimeTypes.ipp +++ b/Sts1CobcSw/Utility/TimeTypes.ipp @@ -1,7 +1,9 @@ #pragma once + #include + namespace sts1cobcsw { template @@ -18,6 +20,7 @@ inline auto DeserializeFrom(void const * source, RealTime * data) -> void const return source; } + template inline auto SerializeTo(void * destination, Duration const & data) -> void * { diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 739987e0..08dc023e 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -15,8 +15,9 @@ find_rodos() add_custom_target(AllTests) if(CMAKE_SYSTEM_NAME STREQUAL Linux) add_subdirectory(GoldenTests EXCLUDE_FROM_ALL) + add_subdirectory(IntegrationTests EXCLUDE_FROM_ALL) add_subdirectory(UnitTests EXCLUDE_FROM_ALL) - add_dependencies(AllTests AllUnitTests AllGoldenTests) + add_dependencies(AllTests AllGoldenTests AllIntegrationTests AllUnitTests) elseif(CMAKE_SYSTEM_NAME STREQUAL Generic) add_subdirectory(HardwareTests EXCLUDE_FROM_ALL) add_dependencies(AllTests AllHardwareTests) diff --git a/Tests/HardwareTests/CMakeLists.txt b/Tests/HardwareTests/CMakeLists.txt index bb637b92..b1ade1c4 100644 --- a/Tests/HardwareTests/CMakeLists.txt +++ b/Tests/HardwareTests/CMakeLists.txt @@ -89,6 +89,27 @@ target_link_libraries( ) add_watchdog_version_of(MaxPower) +add_program(SpiSupervisor SpiSupervisor.test.cpp) +target_sources( + Sts1CobcSwTests_SpiSupervisor + PRIVATE ${CMAKE_SOURCE_DIR}/Sts1CobcSw/CobcSoftware/FlashStartupTestThread.cpp + ${CMAKE_SOURCE_DIR}/Sts1CobcSw/CobcSoftware/FramEpsStartupTestThread.cpp + ${CMAKE_SOURCE_DIR}/Sts1CobcSw/CobcSoftware/RfStartupTestThread.cpp + ${CMAKE_SOURCE_DIR}/Sts1CobcSw/CobcSoftware/SpiStartupTestAndSupervisorThread.cpp +) +target_link_libraries( + Sts1CobcSwTests_SpiSupervisor + PRIVATE rodos::rodos + strong_type::strong_type + Sts1CobcSw_FramSections + Sts1CobcSw_Hal + Sts1CobcSw_Periphery + Sts1CobcSw_Serial + Sts1CobcSw_Utility + Sts1CobcSwTests_RfLatchupDisablePin +) +add_watchdog_version_of(SpiSupervisor) + add_program(Gpio Gpio.test.cpp) target_link_libraries( Sts1CobcSwTests_Gpio PRIVATE rodos::rodos Sts1CobcSw_Hal Sts1CobcSwTests_RfLatchupDisablePin diff --git a/Tests/HardwareTests/EduCommands.test.cpp b/Tests/HardwareTests/EduCommands.test.cpp index b63015d6..78447aaa 100644 --- a/Tests/HardwareTests/EduCommands.test.cpp +++ b/Tests/HardwareTests/EduCommands.test.cpp @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include diff --git a/Tests/HardwareTests/Flash.test.cpp b/Tests/HardwareTests/Flash.test.cpp index d107612a..1757960b 100644 --- a/Tests/HardwareTests/Flash.test.cpp +++ b/Tests/HardwareTests/Flash.test.cpp @@ -3,6 +3,12 @@ #include #include +#include +#include + +#include +#include +#include #include @@ -84,24 +90,22 @@ class FlashTest : public RODOS::StaticThread std::fill(page.begin(), page.end(), 0x00_b); PRINTF("Programming page at address 0x%08x:\n", static_cast(pageAddress)); Print(page); - auto begin = RODOS::NOW(); + auto begin = CurrentRodosTime(); flash::ProgramPage(pageAddress, page); - auto endPage = RODOS::NOW(); + auto endPage = CurrentRodosTime(); - auto const programPageTimeout = 10 * RODOS::MILLISECONDS; + auto const programPageTimeout = 10 * ms; auto waitWhileBusyResult = flash::WaitWhileBusy(programPageTimeout); - auto end = RODOS::NOW(); - PRINTF("ProgrammPage took %d us\n", - static_cast((endPage - begin) / RODOS::MICROSECONDS)); + auto end = CurrentRodosTime(); + PRINTF("ProgrammPage took %d us\n", static_cast((endPage - begin) / us)); if(waitWhileBusyResult.has_error()) { PRINTF("WaitWhileBusy failed because it didn't finish in %d us\n", - static_cast(programPageTimeout / RODOS::MICROSECONDS)); + static_cast(programPageTimeout / us)); } else { - PRINTF("WaitWhileBusy took %d us\n", - static_cast((end - endPage) / RODOS::MICROSECONDS)); + PRINTF("WaitWhileBusy took %d us\n", static_cast((end - endPage) / us)); } PRINTF("\n"); @@ -114,19 +118,18 @@ class FlashTest : public RODOS::StaticThread static_cast(pageAddress)); flash::EraseSector(pageAddress); - auto const eraseSectorTimeout = 500 * RODOS::MILLISECONDS; - begin = RODOS::NOW(); + auto const eraseSectorTimeout = 500 * ms; + begin = CurrentRodosTime(); waitWhileBusyResult = flash::WaitWhileBusy(eraseSectorTimeout); - end = RODOS::NOW(); + end = CurrentRodosTime(); if(waitWhileBusyResult.has_error()) { PRINTF("WaitWhileBusy failed because it didn't finish in %d us\n", - static_cast(eraseSectorTimeout / RODOS::MICROSECONDS)); + static_cast(eraseSectorTimeout / us)); } else { - PRINTF("WaitWhileBusy took %d us\n", - static_cast((end - begin) / RODOS::MICROSECONDS)); + PRINTF("WaitWhileBusy took %d us\n", static_cast((end - begin) / us)); } PRINTF("\n"); diff --git a/Tests/HardwareTests/Fram.test.cpp b/Tests/HardwareTests/Fram.test.cpp index fb5a7571..1d8bcb29 100644 --- a/Tests/HardwareTests/Fram.test.cpp +++ b/Tests/HardwareTests/Fram.test.cpp @@ -4,7 +4,9 @@ #include #include #include +#include +#include #include #include @@ -29,7 +31,8 @@ auto testData = std::array{}; auto readData = std::array{}; // Baud rate = 6 MHz, largest data transfer = 11 KiB -> spiTimeout = 30 ms is enough for all // transfers -constexpr auto spiTimeout = 30 * RODOS::MILLISECONDS; +// TODO: Test if the test still works if we include Time.hpp and use ms here instead +constexpr auto spiTimeout = 30 * Duration(RODOS::MILLISECONDS); auto PrintDeviceId(fram::DeviceId const & deviceId) -> void; diff --git a/Tests/HardwareTests/MaxPower.test.cpp b/Tests/HardwareTests/MaxPower.test.cpp index 8072fd2c..d733055b 100644 --- a/Tests/HardwareTests/MaxPower.test.cpp +++ b/Tests/HardwareTests/MaxPower.test.cpp @@ -5,8 +5,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/Tests/HardwareTests/SpiSupervisor.test.cpp b/Tests/HardwareTests/SpiSupervisor.test.cpp new file mode 100644 index 00000000..7c19bf4e --- /dev/null +++ b/Tests/HardwareTests/SpiSupervisor.test.cpp @@ -0,0 +1,66 @@ +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include + + +namespace sts1cobcsw +{ +class SpiSupervisorTest : public RODOS::StaticThread<> +{ +public: + SpiSupervisorTest() : StaticThread("SpiSupervisorTest") + { + } + + +private: + void init() override + { + InitializeRfLatchupDisablePins(); + } + + + void run() override + { + using RODOS::PRINTF; + + EnableRfLatchupProtection(); + + PRINTF("\nSPI supervisor test\n\n"); + + PRINTF("\n"); + std::uint32_t const flashAddress = 0x00'01'10'00U; + PRINTF("Reading flash page ...\n"); + auto page = flash::ReadPage(flashAddress); + PRINTF("Writing flash page ...\n"); + flash::ProgramPage(flashAddress, Span(page)); + + SuspendFor(2 * s); + + PRINTF("\n"); + RODOS::setRandSeed(static_cast(RODOS::NOW())); + constexpr std::uint32_t nAdressBits = 20U; + auto framAddress = fram::Address(RODOS::uint32Rand() % (1U << nAdressBits)); + + auto framTestData = std::array{}; + // Baud rate = 6 MHz, data size = 11 KiB -> transfer time ~ 15 ms + constexpr auto spiTimeout = 30 * ms; + PRINTF("Writing %d B to FRAM ...\n", static_cast(framTestData.size())); + fram::WriteTo(framAddress, Span(framTestData), spiTimeout); + } + +} spiSupervisorTest; +} diff --git a/Tests/HardwareTests/Uart.test.cpp b/Tests/HardwareTests/Uart.test.cpp index c6f28b25..af296b70 100644 --- a/Tests/HardwareTests/Uart.test.cpp +++ b/Tests/HardwareTests/Uart.test.cpp @@ -11,8 +11,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/Tests/HardwareTests/Watchdog.test.cpp b/Tests/HardwareTests/Watchdog.test.cpp index 8b6ee0af..bdec3a1c 100644 --- a/Tests/HardwareTests/Watchdog.test.cpp +++ b/Tests/HardwareTests/Watchdog.test.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include diff --git a/Tests/IntegrationTests/CMakeLists.txt b/Tests/IntegrationTests/CMakeLists.txt new file mode 100644 index 00000000..78becd15 --- /dev/null +++ b/Tests/IntegrationTests/CMakeLists.txt @@ -0,0 +1,19 @@ +add_program(SpiSupervisor 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_Utility +) +add_test(NAME SpiSupervisor COMMAND Sts1CobcSwTests_SpiSupervisor) + +# --- All integration tests --- + +get_property( + all_integration_test_targets DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY BUILDSYSTEM_TARGETS +) +add_custom_target(AllIntegrationTests) # Must be defined after getting all integration test targets +add_dependencies(AllIntegrationTests ${all_integration_test_targets}) diff --git a/Tests/IntegrationTests/SpiSupervisor.test.cpp b/Tests/IntegrationTests/SpiSupervisor.test.cpp new file mode 100644 index 00000000..42e6061c --- /dev/null +++ b/Tests/IntegrationTests/SpiSupervisor.test.cpp @@ -0,0 +1,45 @@ +#include +#include +#include +#include +#include +#include + +#include + +#include + + +namespace sts1cobcsw +{ +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 endOfTime; }); + framEpsSpi_.SetTransferEnd([]() { return endOfTime; }); + rfSpi_.SetTransferEnd([]() { return endOfTime; }); + fram::ram::SetAllDoFunctions(); + fram::Initialize(); + } + + void run() override + { + SuspendFor(1 * s); + RODOS::PRINTF("Starting SPI supervisor test\n"); + } +} spiSupervisorTest; +} diff --git a/Tests/UnitTests/Fram.test.cpp b/Tests/UnitTests/Fram.test.cpp index 83549d9d..182a76a9 100644 --- a/Tests/UnitTests/Fram.test.cpp +++ b/Tests/UnitTests/Fram.test.cpp @@ -1,14 +1,17 @@ #include #include #include +#include #include #include #include #include #include +#include #include +#include #include #include @@ -18,6 +21,7 @@ namespace fram = sts1cobcsw::fram; using sts1cobcsw::Byte; using sts1cobcsw::Span; using sts1cobcsw::operator""_b; // NOLINT(misc-unused-using-decls) +using sts1cobcsw::ms; auto WriteAndReadTestData(sts1cobcsw::fram::Address address) -> void; @@ -41,12 +45,12 @@ TEST_CASE("Mocked functions do nothing by default") SECTION("WriteTo() and ReadFrom()") { auto readData = std::array{0x11_b, 0x22_b, 0x33_b, 0x44_b}; - fram::ReadFrom(address, Span(&readData), 0); + fram::ReadFrom(address, Span(&readData), 0 * ms); CHECK(readData == std::array{0x11_b, 0x22_b, 0x33_b, 0x44_b}); auto writeData = std::array{0xAA_b, 0xBB_b, 0xCC_b, 0xDD_b}; - fram::WriteTo(address, Span(writeData), 0); - readData = fram::ReadFrom(address, 0); + fram::WriteTo(address, Span(writeData), 0 * ms); + readData = fram::ReadFrom(address, 0 * ms); CHECK(readData == decltype(readData){}); } } @@ -67,16 +71,16 @@ TEST_CASE("Mocking FRAM in RAM") auto address = fram::Address(GENERATE(take(1, random(0U, value_of(fram::memorySize) - 10)))); auto readData = std::array{0x01_b, 0x02_b, 0x03_b, 0x04_b}; - fram::ReadFrom(address, Span(&readData), 0); + fram::ReadFrom(address, Span(&readData), 0 * ms); CHECK(readData == decltype(readData){}); auto writeData = std::array{0xAA_b, 0xBB_b, 0xCC_b, 0xDD_b}; - fram::WriteTo(address, Span(writeData), 0); + fram::WriteTo(address, Span(writeData), 0 * ms); CHECK(fram::ram::memory[value_of(address)] == writeData[0]); CHECK(fram::ram::memory[value_of(address) + 1] == writeData[1]); CHECK(fram::ram::memory[value_of(address) + 2] == writeData[2]); CHECK(fram::ram::memory[value_of(address) + 3] == writeData[3]); - readData = fram::ReadFrom(address, 0); + readData = fram::ReadFrom(address, 0 * ms); CHECK(readData == writeData); } diff --git a/Tests/UnitTests/PersistentVariables.test.cpp b/Tests/UnitTests/PersistentVariables.test.cpp index 11d35597..7ad94117 100644 --- a/Tests/UnitTests/PersistentVariables.test.cpp +++ b/Tests/UnitTests/PersistentVariables.test.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include #include diff --git a/iwyu.imp b/iwyu.imp index aa41bb1f..7bc92ad8 100644 --- a/iwyu.imp +++ b/iwyu.imp @@ -59,9 +59,10 @@ { include: ["\"Sts1CobcSw/Serial/Byte.ipp\"", "private", "", "public"] }, { include: ["\"Sts1CobcSw/Serial/Serial.ipp\"", "private", "", "public"] }, { include: ["\"Sts1CobcSw/Utility/ErrorDetectionAndCorrection.ipp\"", "private", "", "public"] }, + { include: ["\"Sts1CobcSw/Utility/RealTime.ipp\"", "private", "", "public"] }, + { include: ["\"Sts1CobcSw/Utility/RodosTime.ipp\"", "private", "", "public"] }, { include: ["\"Sts1CobcSw/Utility/Span.ipp\"", "private", "", "public"] }, { include: ["\"Sts1CobcSw/Utility/StringLiteral.ipp\"", "private", "", "public"] }, - { include: ["\"Sts1CobcSw/Utility/Time.ipp\"", "private", "", "public"] }, { include: ["\"Sts1CobcSw/Utility/TimeTypes.ipp\"", "private", "", "public"] }, # Include all our headers with <> instead of "" @@ -81,17 +82,19 @@ { include: ["\"Sts1CobcSw/FramSections/SubsectionInfo.hpp\"", "public", "", "public"] }, { include: ["\"Sts1CobcSw/FramSections/Subsections.hpp\"", "public", "", "public"] }, { include: ["\"Sts1CobcSw/Hal/GpioPin.hpp\"", "public", "", "public"] }, + { include: ["\"Sts1CobcSw/Hal/HardwareSpi.hpp\"", "public", "", "public"] }, { include: ["\"Sts1CobcSw/Hal/IoNames.hpp\"", "public", "", "public"] }, { include: ["\"Sts1CobcSw/Hal/PinNames.hpp\"", "public", "", "public"] }, { include: ["\"Sts1CobcSw/Hal/Spi.hpp\"", "public", "", "public"] }, + { include: ["\"Sts1CobcSw/Hal/SpiMock.hpp\"", "public", "", "public"] }, { include: ["\"Sts1CobcSw/Hal/Uart.hpp\"", "public", "", "public"] }, { include: ["\"Sts1CobcSw/Outcome/Outcome.hpp\"", "public", "", "public"] }, { include: ["\"Sts1CobcSw/Periphery/Eps.hpp\"", "public", "", "public"] }, { include: ["\"Sts1CobcSw/Periphery/Flash.hpp\"", "public", "", "public"] }, { include: ["\"Sts1CobcSw/Periphery/Fram.hpp\"", "public", "", "public"] }, - { include: ["\"Sts1CobcSw/Periphery/FramEpsSpi.hpp\"", "public", "", "public"] }, { include: ["\"Sts1CobcSw/Periphery/FramMock.hpp\"", "public", "", "public"] }, { include: ["\"Sts1CobcSw/Periphery/Rf.hpp\"", "public", "", "public"] }, + { include: ["\"Sts1CobcSw/Periphery/Spis.hpp\"", "public", "", "public"] }, { include: ["\"Sts1CobcSw/ProgramId/ProgramId.hpp\"", "public", "", "public"] }, { include: ["\"Sts1CobcSw/Serial/Byte.hpp\"", "public", "", "public"] }, { include: ["\"Sts1CobcSw/Serial/Serial.hpp\"", "public", "", "public"] }, @@ -100,9 +103,10 @@ { include: ["\"Sts1CobcSw/Utility/Debug.hpp\"", "public", "", "public"] }, { include: ["\"Sts1CobcSw/Utility/ErrorDetectionAndCorrection.hpp\"", "public", "", "public"] }, { include: ["\"Sts1CobcSw/Utility/FlatArray.hpp\"", "public", "", "public"] }, + { include: ["\"Sts1CobcSw/Utility/RealTime.hpp\"", "public", "", "public"] }, + { include: ["\"Sts1CobcSw/Utility/RodosTime.hpp\"", "public", "", "public"] }, { include: ["\"Sts1CobcSw/Utility/Span.hpp\"", "public", "", "public"] }, { include: ["\"Sts1CobcSw/Utility/StringLiteral.hpp\"", "public", "", "public"] }, - { include: ["\"Sts1CobcSw/Utility/Time.hpp\"", "public", "", "public"] }, { include: ["\"Sts1CobcSw/Utility/TimeTypes.hpp\"", "public", "", "public"] }, { include: ["\"Sts1CobcSw/CommandParser.hpp\"", "public", "", "public"] }, { include: ["\"Sts1CobcSw/EduCommunicationErrorThread.hpp\"", "public", "", "public"] },