diff --git a/Sts1CobcSw/Edu/ProgramStatusHistory.cpp b/Sts1CobcSw/Edu/ProgramStatusHistory.cpp index 0c9a4a1b..de9e0715 100644 --- a/Sts1CobcSw/Edu/ProgramStatusHistory.cpp +++ b/Sts1CobcSw/Edu/ProgramStatusHistory.cpp @@ -4,8 +4,9 @@ namespace sts1cobcsw::edu { -ProgramStatusHistoryClass programStatusHistory = - ProgramStatusHistoryClass(); +// TODO: Put a real variable for start Address +ProgramStatusHistoryClass programStatusHistory = + ProgramStatusHistoryClass(); } namespace sts1cobcsw::edu diff --git a/Sts1CobcSw/Edu/ProgramStatusHistory.hpp b/Sts1CobcSw/Edu/ProgramStatusHistory.hpp index 0edaec02..6ca1ccd2 100644 --- a/Sts1CobcSw/Edu/ProgramStatusHistory.hpp +++ b/Sts1CobcSw/Edu/ProgramStatusHistory.hpp @@ -5,6 +5,7 @@ // clang-format off #include // NOLINT(llvm-include-order) +#include "Sts1CobcSw/Periphery/Fram.hpp" #include "Sts1CobcSw/Periphery/FramRingBuffer.hpp" // ringbuffer.h does not include even though it requires it #include @@ -56,14 +57,15 @@ template [[nodiscard]] auto SerializeTo(void * destination, ProgramStatusHistoryEntry const & data) -> void *; -template -auto UpdateRingBufferEntry(fram::RingBuffer & ringBuffer, - std::int32_t startTime, - ProgramId programId, - ProgramStatus newStatus) -> bool; +template +auto UpdateRingBufferEntry( + fram::RingBuffer & ringBuffer, + std::int32_t startTime, + ProgramId programId, + ProgramStatus newStatus) -> bool; -template +template class ProgramStatusHistoryClass { public: @@ -76,7 +78,7 @@ class ProgramStatusHistoryClass { if(fram::framIsWorking) { - framProgramStatusHistory_.Put(programStatusHistoryEntry); + // framProgramStatusHistory_.Put(programStatusHistoryEntry); } ramProgramStatusHistory_.put(programStatusHistoryEntry); } @@ -104,19 +106,22 @@ class ProgramStatusHistoryClass } private: - sts1cobcsw::fram::RingBuffer framProgramStatusHistory_; + sts1cobcsw::fram::RingBuffer + framProgramStatusHistory_; RODOS::RingBuffer ramProgramStatusHistory_; }; -extern ProgramStatusHistoryClass programStatusHistory; +// TODO: Put a real value here +extern ProgramStatusHistoryClass programStatusHistory; // TODO: Move this into .cpp file -template -auto UpdateRingBufferEntry(fram::RingBuffer & ringBuffer, - const std::int32_t startTime, - const ProgramId programId, - const ProgramStatus newStatus) -> bool +template +auto UpdateRingBufferEntry( + fram::RingBuffer & ringBuffer, + const std::int32_t startTime, + const ProgramId programId, + const ProgramStatus newStatus) -> bool { for(std::uint32_t i = 0; i < poolSize; ++i) { diff --git a/Sts1CobcSw/Periphery/FramRingBuffer.hpp b/Sts1CobcSw/Periphery/FramRingBuffer.hpp index cd4f8102..4b3df9ec 100644 --- a/Sts1CobcSw/Periphery/FramRingBuffer.hpp +++ b/Sts1CobcSw/Periphery/FramRingBuffer.hpp @@ -14,61 +14,28 @@ namespace sts1cobcsw::fram { -using sts1cobcsw::Span; -using sts1cobcsw::TriviallySerializable; - - -template +template class RingBuffer { public: - // NOLINTBEGIN(*non-private-member-variables-in-classes) - std::uint64_t writeCnt = 0; - std::uint64_t readCnt = 0; - std::uint32_t occupiedCnt = 0; - Address startAddress; - // NOLINTEND(*non-private-member-variables-in-classes) - - explicit RingBuffer(Address address) : startAddress(address) - { - } - - RingBuffer() : startAddress(0){}; - - void Put(T const & newdata) - { - currentWrite_ = writeIndex_; - auto const address = startAddress + writeIndex_ * serialSize; - fram::WriteTo(address, Span(Serialize(newdata)), 0); - writeIndex_++; - - if(writeIndex_ >= poolSize) - { - writeIndex_ = 0; - } - if(occupiedCnt < poolSize) - { - occupiedCnt++; - } - writeCnt++; - currentWrite_ = UINT32_MAX; - } + RingBuffer() = default; + // TODO: Move this in .ipp file // Get next item void Get(T & fromRing) { // Jump the current being written record - if(readIndex_ == currentWrite_) + if(readIndex_ == currentWriteIndex_) { readIndex_++; } - if(readIndex_ >= poolSize) + if(readIndex_ >= size) { readIndex_ = 0; } // readIndex should not pass write index if there is no data after it - if(writeCnt < poolSize && readIndex_ >= writeIndex_) + if(writeCount_ < size && readIndex_ >= writeIndex_) { readIndex_ = 0; } @@ -79,26 +46,43 @@ class RingBuffer fromRing = Deserialize(std::span(readData)); readIndex_++; - if(readIndex_ >= poolSize) + if(readIndex_ >= size) { readIndex_ = 0; } - if(occupiedCnt > 0) + if(occupiedCount_ > 0) { - occupiedCnt--; + occupiedCount_--; } - readCnt++; + readCount_++; } - auto GetLen() -> int + auto Capacity() -> std::size_t { - return poolSize; + return capacity_; } + auto Size() -> std::size_t + { + return size; + } + + auto Push(T const & newData) -> void; + auto operator[](std::size_t index) -> T; + auto Front() -> T; + auto Back() -> T; + private: std::uint32_t writeIndex_ = 0; std::uint32_t readIndex_ = 0; - std::uint32_t currentWrite_ = UINT32_MAX; + std::uint32_t currentWriteIndex_ = UINT32_MAX; + std::uint64_t writeCount_ = 0; + std::uint64_t readCount_ = 0; + std::uint32_t occupiedCount_ = 0; + std::size_t capacity_ = 0; }; } + + +#include // IWYU pragma: keep diff --git a/Sts1CobcSw/Periphery/FramRingBuffer.ipp b/Sts1CobcSw/Periphery/FramRingBuffer.ipp new file mode 100644 index 00000000..149a59be --- /dev/null +++ b/Sts1CobcSw/Periphery/FramRingBuffer.ipp @@ -0,0 +1,80 @@ +#pragma once + + +#include + + +namespace sts1cobcsw::fram +{ +template +void RingBuffer::Push(T const & newData) +{ + currentWriteIndex_ = writeIndex_; + auto const address = startAddress + writeIndex_ * serialSize; + fram::WriteTo(address, Span(Serialize(newData)), 0); + writeIndex_++; + + if(writeIndex_ >= size) + { + writeIndex_ = 0; + } + if(occupiedCount_ < size) + { + occupiedCount_++; + } + writeCount_++; + // TODO: iwyu + currentWriteIndex_ = UINT32_MAX; +} + + +template +auto RingBuffer::Front() -> T +{ + // TODO: Check if using RODOS ringbuffer logic is right + + // Jump the current being written record + if(readIndex_ == currentWriteIndex_) + { + readIndex_++; + } + if(readIndex_ >= size) + { + readIndex_ = 0; + } + + // readIndex should not pass write index if there is no data after it + if(writeCount_ < size && readIndex_ >= writeIndex_) + { + readIndex_ = 0; + } + + auto const address = startAddress + readIndex_ * serialSize; + // TODO: Add a real timeout value (spiTimeout in hw tests is 30ms, but for much more data) + auto readData = fram::ReadFrom>(address, 0); + auto fromRing = Deserialize(std::span(readData)); + + readIndex_++; + if(readIndex_ >= size) + { + readIndex_ = 0; + } + + if(occupiedCount_ > 0) + { + occupiedCount_--; + } + readCount_++; + + return fromRing; +} + +template +auto RingBuffer::operator[](std::size_t index) -> T +{ + // TODO: This assume that index not out of bounds + auto const address = startAddress + index * serialSize; + auto readData = fram::ReadFrom>(address, 0); + return Deserialize(std::span(readData)); +} +} diff --git a/Tests/UnitTests/FramRingBuffer.test.cpp b/Tests/UnitTests/FramRingBuffer.test.cpp index 17a28f5b..16611f89 100644 --- a/Tests/UnitTests/FramRingBuffer.test.cpp +++ b/Tests/UnitTests/FramRingBuffer.test.cpp @@ -1,157 +1,86 @@ -#include #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") +TEST_CASE("Initial State ringbuffer") { - RODOS::RingBuffer buffer; + // TODO: Sections could be useful + sts1cobcsw::fram::RingBuffer buffer; - REQUIRE(buffer.getLen() == 10); - - auto const value = 42; - int result = 0; - buffer.put(value); - buffer.get(result); - REQUIRE(value == result); + REQUIRE(buffer.Size() == 10); + REQUIRE(buffer.Capacity() == 0); } -TEST_CASE("RODOS ringbuffer overwrite") +TEST_CASE("FramRingBuffer Push function") { - RODOS::RingBuffer buffer; - REQUIRE(buffer.getLen() == 10); - - for(int i = 0; i < 15; i++) - { - buffer.put(i); - } - - int result = 0; - for(int i = 10; i < 15; ++i) - { - buffer.get(result); - REQUIRE(result == i); - } -} + fram::RingBuffer buffer; -TEST_CASE("RODOS ringbuffer wrapping") -{ - RODOS::RingBuffer buffer; - for(int i = 0; i < 30; ++i) - { - buffer.put(i); - } - - int result = 0; - for(int i = 20; i < 30; ++i) - { - buffer.get(result); - REQUIRE(result == i); - } + buffer.Push(1); + buffer.Push(2); + buffer.Push(3); + + // Failing + // REQUIRE(buffer.Size() == 3); } -// TODO: Split in different tests or sections -TEST_CASE("RingBuffer put and get operations") + +TEMPLATE_TEST_CASE_SIG("FramRingBuffer Front Address", + "", + ((typename T, size_t S, fram::Address A), T, S, A), + (int, 10, fram::Address{0}), + (int, 10, fram::Address{31415})) { 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); - + fram::RingBuffer buffer; - auto const i8Value = 42; - std::int8_t result = 0; - int8Buffer.Put(i8Value); - int8Buffer.Get(result); - REQUIRE(i8Value == result); + buffer.Push(10); + buffer.Push(20); + buffer.Push(30); - 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); + REQUIRE(buffer[0] == 10); + REQUIRE(buffer[1] == 20); + REQUIRE(buffer[2] == 30); } -// Debug test case -TEST_CASE("Simple put and get inlined") +TEST_CASE("FramRingBuffer Back and Front") { 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){}); -} + fram::RingBuffer buffer; + etl::circular_buffer etlBuffer; -TEST_CASE("Program status and history") -{ - fram::ram::SetAllDoFunctions(); - fram::ram::storage.fill(0x00_b); - fram::Initialize(); + buffer.Push(1); + buffer.Push(2); + buffer.Push(3); - // Put() and Get() a ProgramStatusHistoryEntry variable. - auto ringBuffer = fram::RingBuffer(0); - auto value = ProgramStatusHistoryEntry{.programId = sts1cobcsw::ProgramId(12), - .startTime = 34, - .status = ProgramStatus::programExecutionFailed}; - auto result = ProgramStatusHistoryEntry{}; + etlBuffer.push(1); + etlBuffer.push(2); + etlBuffer.push(3); - ringBuffer.Put(value); - ringBuffer.Get(result); + REQUIRE(etlBuffer.front() == 1); + REQUIRE(etlBuffer.back() == 3); - CHECK(result.programId == 12); - CHECK(result.startTime == 34); - CHECK(result.status == ProgramStatus::programExecutionFailed); + REQUIRE(buffer.Front() == 1); + // REQUIRE(buffer.Back() == 3); } diff --git a/Tests/UnitTests/UpdateRingBuffer.test.cpp b/Tests/UnitTests/UpdateRingBuffer.test.cpp index 688f35e5..ac3f6a2c 100644 --- a/Tests/UnitTests/UpdateRingBuffer.test.cpp +++ b/Tests/UnitTests/UpdateRingBuffer.test.cpp @@ -35,8 +35,8 @@ using sts1cobcsw::Serialize; // Normally this would be set in Sts1CobcSw/someThread.cpp bool sts1cobcsw::fram::framIsWorking = true; -ProgramStatusHistoryClass programStatusHistory = - ProgramStatusHistoryClass(); +ProgramStatusHistoryClass programStatusHistory = + ProgramStatusHistoryClass(); namespace sts1cobcsw::edu { diff --git a/iwyu.imp b/iwyu.imp index f8758a5a..879d9150 100644 --- a/iwyu.imp +++ b/iwyu.imp @@ -56,6 +56,7 @@ { include: ["\"Sts1CobcSw/Serial/Byte.ipp\"", "private", "", "public"] }, { include: ["\"Sts1CobcSw/Serial/Serial.ipp\"", "private", "", "public"] }, { include: ["\"Sts1CobcSw/Utility/Span.ipp\"", "private", "", "public"] }, + { include: ["\"Sts1CobcSw/Periphery/FramRingBuffer.ipp\"", "private", "", "public"] }, # Include all our headers with <> instead of "" { include: ["\"Sts1CobcSw/Edu/Edu.hpp\"", "public", "", "public"] },