diff --git a/Sts1CobcSw/Periphery/FramRingBuffer.hpp b/Sts1CobcSw/Periphery/FramRingBuffer.hpp index 9034bf4a..da41d008 100644 --- a/Sts1CobcSw/Periphery/FramRingBuffer.hpp +++ b/Sts1CobcSw/Periphery/FramRingBuffer.hpp @@ -2,17 +2,31 @@ #include +#include +#include + +#include #include +#include #include #include #include +#include "Sts1CobcSw/Utility/Span.hpp" + namespace sts1cobcsw::fram { +using sts1cobcsw::Byte; +using sts1cobcsw::Span; +using sts1cobcsw::operator""_b; // NOLINT(misc-unused-using-decls) +using sts1cobcsw::TriviallySerializable; -template + +// TODO: Handle non trivially serializable types/class +// template +template class RingBuffer { public: @@ -20,28 +34,28 @@ class RingBuffer std::uint32_t writeIndex = 0; std::uint32_t readIndex = 0; std::uint32_t currentWrite = UINT32_MAX; + // TODO: Check that this is correct, or that it should be std::array vals; -public: std::uint64_t writeCnt = 0; std::uint64_t readCnt = 0; std::uint32_t occupiedCnt = 0; - RingBuffer(Address startAddress) : startAddress(startAddress) + explicit RingBuffer(Address address) : startAddress(address) { } - T * getNextEntryToPut() + auto GetNextEntryToPut() -> T * { return &vals[writeIndex]; } - void put(T const & newdata) + void Put(T const & newdata) { currentWrite = writeIndex; - Address address = startAddress + writeIndex * sizeof(T); - - WriteTo(address, reinterpret_cast(&newdata), sizeof(T), 0); + // NOTE: For trivially serializable types, sizeof and serialSize should be the same. + auto const address = startAddress + writeIndex * serialSize; + fram::WriteTo(address, Span(Serialize(newdata)), 0); writeIndex++; if(writeIndex >= poolSize) @@ -57,7 +71,7 @@ class RingBuffer } // Get next item - void get(T & fromRing) + void Get(T & fromRing) { // Jump the current being written record if(readIndex == currentWrite) @@ -75,10 +89,19 @@ class RingBuffer readIndex = 0; } - Address address = startAddress + readIndex * sizeof(T); - std::array buffer; - ReadFrom(address, buffer, 0); - fromRing = *reinterpret_cast(buffer.data()); + auto const address = startAddress + readIndex * serialSize; + // TODO: Deal with timeout + auto readData = fram::ReadFrom>(address, 0); + fromRing = Deserialize(std::span(readData)); + + // DEBUG PRINT + std::printf("Printing read data in buffer.Get() method :\n"); + for(auto byte : readData) + { + std::printf("0x%02x ", static_cast(byte)); + } + std::printf("\n"); + // END DEBUG PRINT readIndex++; if(readIndex >= poolSize) @@ -93,9 +116,9 @@ class RingBuffer readCnt++; } - int getLen() + auto GetLen() -> int { return poolSize; } }; -} \ No newline at end of file +} diff --git a/Tests/UnitTests/CMakeLists.txt b/Tests/UnitTests/CMakeLists.txt index ceea962a..8853c413 100644 --- a/Tests/UnitTests/CMakeLists.txt +++ b/Tests/UnitTests/CMakeLists.txt @@ -12,7 +12,7 @@ target_link_libraries( ) add_program(RingBuffer FramRingBuffer.test.cpp) -target_link_libraries(Sts1CobcSwTests_RingBuffer PRIVATE Catch2::Catch2WithMain) +target_link_libraries(Sts1CobcSwTests_RingBuffer PRIVATE Catch2::Catch2WithMain Sts1CobcSw_Periphery Sts1CobcSw_Serial) # TODO: Enable again once problem with segmentation violation on CI is fixed add_program(LfsRam LfsRam.test.cpp) diff --git a/Tests/UnitTests/FramRingBuffer.test.cpp b/Tests/UnitTests/FramRingBuffer.test.cpp index 42fe8f64..80f49b4d 100644 --- a/Tests/UnitTests/FramRingBuffer.test.cpp +++ b/Tests/UnitTests/FramRingBuffer.test.cpp @@ -1,17 +1,42 @@ -#include -#include +#include +#include +#include +#include +#include +#include + #include +#include +#include +#include + +#include + +#include +#include +#include +#include + + +namespace fram = sts1cobcsw::fram; + +using sts1cobcsw::Byte; +using sts1cobcsw::Span; +using sts1cobcsw::edu::ProgramStatus; +using sts1cobcsw::edu::ProgramStatusHistoryEntry; +using sts1cobcsw::operator""_b; // NOLINT(misc-unused-using-decls) +using sts1cobcsw::Deserialize; +using sts1cobcsw::Serialize; TEST_CASE("RODOS ringbuffer put and get operations") { - RODOS::RingBuffer buffer; - - REQUIRE(buffer.getLen() == 10); - int value = 42; - int result; + REQUIRE(buffer.getLen() == 10); + + auto const value = 42; + int result = 0; buffer.put(value); buffer.get(result); REQUIRE(value == result); @@ -19,43 +44,147 @@ TEST_CASE("RODOS ringbuffer put and get operations") TEST_CASE("RODOS ringbuffer overwrite") { - RODOS::RingBuffer buffer; - REQUIRE(buffer.getLen() == 10); + REQUIRE(buffer.getLen() == 10); for(int i = 0; i < 15; i++) { buffer.put(i); } - int result; + int result = 0; for(int i = 10; i < 15; ++i) { buffer.get(result); REQUIRE(result == i); - } + } } TEST_CASE("RODOS ringbuffer wrapping") { - RODOS::RingBuffer buffer; for(int i = 0; i < 30; ++i) { buffer.put(i); } - int result; + int result = 0; for(int i = 20; i < 30; ++i) { buffer.get(result); REQUIRE(result == i); } - - } // TODO: Split in differents tests or sections TEST_CASE("RingBuffer put and get operations") { -} \ No newline at end of file + fram::ram::SetAllDoFunctions(); + fram::ram::storage.fill(0x00_b); + fram::Initialize(); + + auto address = GENERATE(take(2, random(0U, 1U << 20U))); + auto int8Buffer = sts1cobcsw::fram::RingBuffer(address); + auto uint16Buffer = sts1cobcsw::fram::RingBuffer(address + 10); + auto int32Buffer = sts1cobcsw::fram::RingBuffer(address + 20); + + + REQUIRE(int8Buffer.GetLen() == 10); + + + auto const i8Value = 42; + std::int8_t result = 0; + int8Buffer.Put(i8Value); + int8Buffer.Get(result); + REQUIRE(i8Value == result); + + const std::uint16_t u16Value = 65000; + std::uint16_t u16Result = 0; + uint16Buffer.Put(u16Value); + uint16Buffer.Get(u16Result); + REQUIRE(u16Value == u16Result); + + + const std::int32_t i32Value = -2'147'483'648; + std::int32_t i32Result = 0; + int32Buffer.Put(i32Value); + int32Buffer.Get(i32Result); + REQUIRE(i32Value == i32Result); +} + + +// Debug test case +TEST_CASE("Simple put and get inlined") +{ + fram::ram::SetAllDoFunctions(); + fram::ram::storage.fill(0x00_b); + + fram::Initialize(); + auto const correctDeviceId = + std::to_array({0x03_b, 0x2E_b, 0xC2_b, 0x7F_b, 0x7F_b, 0x7F_b, 0x7F_b, 0x7F_b, 0x7F_b}); + auto deviceId = fram::ReadDeviceId(); + CHECK(deviceId == correctDeviceId); + auto actualBaudRate = fram::ActualBaudRate(); + CHECK(actualBaudRate == 6'000'000); + + auto address = GENERATE(take(1, random(0U, fram::ram::storageSize - 10))); + + auto readData = std::array{0x01_b, 0x02_b, 0x03_b, 0x04_b}; + fram::ReadFrom(address, Span(&readData), 0); + CHECK(readData == decltype(readData){}); +} + + +namespace sts1cobcsw +{ +template<> +constexpr std::size_t serialSize = + totalSerialSize; +} + + +namespace sts1cobcsw::edu +{ +template +auto SerializeTo(void * destination, sts1cobcsw::edu::ProgramStatusHistoryEntry const & data) + -> void * +{ + destination = sts1cobcsw::SerializeTo(destination, data.programId); + destination = sts1cobcsw::SerializeTo(destination, data.startTime); + destination = sts1cobcsw::SerializeTo(destination, data.status); + return destination; +} + +template +auto DeserializeFrom(void const * source, sts1cobcsw::edu::ProgramStatusHistoryEntry * data) + -> void const * +{ + source = sts1cobcsw::DeserializeFrom(source, &(data->programId)); + source = sts1cobcsw::DeserializeFrom(source, &(data->startTime)); + source = sts1cobcsw::DeserializeFrom(source, &(data->status)); + return source; +} +} + + +TEST_CASE("Program status and history") +{ + fram::ram::SetAllDoFunctions(); + fram::ram::storage.fill(0x00_b); + fram::Initialize(); + + // Put() and Get() a ProgramStatusHistoryEntry variable. + auto ringBuffer = fram::RingBuffer(0); + auto value = ProgramStatusHistoryEntry{ + .programId = 12, .startTime = 34, .status = ProgramStatus::programExecutionFailed}; + auto result = ProgramStatusHistoryEntry{}; + + ringBuffer.Put(value); + ringBuffer.Get(result); + + CHECK(result.programId == 12); + CHECK(result.startTime == 34); + CHECK(result.status == ProgramStatus::programExecutionFailed); +}