Skip to content

Commit

Permalink
Add cache to fram::RingArray
Browse files Browse the repository at this point in the history
  • Loading branch information
PatrickKa committed Sep 15, 2024
1 parent 999d3b8 commit 740db96
Show file tree
Hide file tree
Showing 3 changed files with 238 additions and 119 deletions.
16 changes: 10 additions & 6 deletions Sts1CobcSw/Periphery/FramRingArray.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include <rodos/api/rodos-semaphore.h>

#include <etl/circular_buffer.h>
#include <etl/cyclic_value.h>

#include <cstddef>
Expand All @@ -25,15 +26,16 @@
// TODO: Move to FramSections
namespace sts1cobcsw
{
template<typename T, Section ringArraySection>
template<typename T, Section ringArraySection, std::size_t nCachedElements>
requires(serialSize<T> > 0)
class RingArray
{
public:
using ValueType = T;
static constexpr auto section = ringArraySection;

[[nodiscard]] static constexpr auto Capacity() -> std::size_t;
[[nodiscard]] static constexpr auto FramCapacity() -> std::size_t;
[[nodiscard]] static constexpr auto CacheCapacity() -> std::size_t;
[[nodiscard]] static auto Size() -> std::size_t;
[[nodiscard]] static auto Get(std::size_t index) -> T;
[[nodiscard]] static auto Front() -> T;
Expand All @@ -53,15 +55,17 @@ class RingArray
PersistentVariables<subsections.template Get<"indexes">(),
PersistentVariableInfo<"iBegin", std::size_t>,
PersistentVariableInfo<"iEnd", std::size_t>>{};
// We reduce the capacity by one to distinguish between an empty and a full ring. See PushBack()
// for details.
static constexpr auto capacity = subsections.template Get<"array">().size / elementSize - 1;
// We reduce the FRAM capacity by one to distinguish between an empty and a full ring. See
// PushBack() for details.
static constexpr auto framCapacity = subsections.template Get<"array">().size / elementSize - 1;
static constexpr auto spiTimeout = elementSize < 300U ? 1 * ms : value_of(elementSize) * 3 * us;

using RingIndex = etl::cyclic_value<std::size_t, 0, capacity>;

using RingIndex = etl::cyclic_value<std::size_t, 0, framCapacity>;

static RingIndex iEnd;
static RingIndex iBegin;
static etl::circular_buffer<SerialBuffer<T>, nCachedElements> cache;
static RODOS::Semaphore semaphore;

static auto LoadIndexes() -> void;
Expand Down
142 changes: 100 additions & 42 deletions Sts1CobcSw/Periphery/FramRingArray.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -8,104 +8,138 @@

namespace sts1cobcsw
{
template<typename T, Section ringArraySection>
requires(serialSize<T> > 0)
typename RingArray<T, ringArraySection>::RingIndex RingArray<T, ringArraySection>::iEnd =
RingIndex{};
using fram::framIsWorking;


template<typename T, Section ringArraySection>
template<typename T, Section ringArraySection, std::size_t nCachedElements>
requires(serialSize<T> > 0)
typename RingArray<T, ringArraySection>::RingIndex RingArray<T, ringArraySection>::iBegin =
RingIndex{};


template<typename T, Section ringArraySection>
requires(serialSize<T> > 0)
RODOS::Semaphore RingArray<T, ringArraySection>::semaphore = RODOS::Semaphore{};
inline constexpr auto RingArray<T, ringArraySection, nCachedElements>::FramCapacity() -> std::size_t
{
return framCapacity;
}


template<typename T, Section ringArraySection>
template<typename T, Section ringArraySection, std::size_t nCachedElements>
requires(serialSize<T> > 0)
inline constexpr auto RingArray<T, ringArraySection>::Capacity() -> std::size_t
inline constexpr auto RingArray<T, ringArraySection, nCachedElements>::CacheCapacity()
-> std::size_t
{
return capacity;
return nCachedElements;
}


template<typename T, Section ringArraySection>
template<typename T, Section ringArraySection, std::size_t nCachedElements>
requires(serialSize<T> > 0)
auto RingArray<T, ringArraySection>::Size() -> std::size_t
auto RingArray<T, ringArraySection, nCachedElements>::Size() -> std::size_t
{
auto protector = RODOS::ScopeProtector(&semaphore); // NOLINT(google-readability-casting)
if(not framIsWorking.Load())
{
return cache.size();
}
LoadIndexes();
return ComputeSize();
}


template<typename T, Section ringArraySection>
template<typename T, Section ringArraySection, std::size_t nCachedElements>
requires(serialSize<T> > 0)
auto RingArray<T, ringArraySection>::Get(std::size_t index) -> T
auto RingArray<T, ringArraySection, nCachedElements>::Get(std::size_t index) -> T
{
auto protector = RODOS::ScopeProtector(&semaphore); // NOLINT(google-readability-casting)
LoadIndexes();
auto size = ComputeSize();
auto size = []()
{
if(framIsWorking.Load())
{
LoadIndexes();
return ComputeSize();
}
return cache.size();
}();
if(index >= size)
{
DEBUG_PRINT("Index out of bounds in RingArray::Get: %u >= %u\n", index, size);
index = size - 1;
}
if(not framIsWorking.Load())
{
return Deserialize<T>(cache[index]);
}
auto i = iBegin;
i.advance(static_cast<int>(index));
return ReadElement(i);
}


template<typename T, Section ringArraySection>
template<typename T, Section ringArraySection, std::size_t nCachedElements>
requires(serialSize<T> > 0)
auto RingArray<T, ringArraySection>::Front() -> T
auto RingArray<T, ringArraySection, nCachedElements>::Front() -> T
{
auto protector = RODOS::ScopeProtector(&semaphore); // NOLINT(google-readability-casting)
if(not framIsWorking.Load())
{
return Deserialize<T>(cache.front());
}
LoadIndexes();
return ReadElement(iBegin);
}


template<typename T, Section ringArraySection>
template<typename T, Section ringArraySection, std::size_t nCachedElements>
requires(serialSize<T> > 0)
auto RingArray<T, ringArraySection>::Back() -> T
auto RingArray<T, ringArraySection, nCachedElements>::Back() -> T
{
auto protector = RODOS::ScopeProtector(&semaphore); // NOLINT(google-readability-casting)
if(not framIsWorking.Load())
{
return Deserialize<T>(cache.back());
}
LoadIndexes();
auto i = iEnd;
i--;
return ReadElement(i);
}


template<typename T, Section ringArraySection>
template<typename T, Section ringArraySection, std::size_t nCachedElements>
requires(serialSize<T> > 0)
auto RingArray<T, ringArraySection>::Set(std::size_t index, T const & t) -> void
auto RingArray<T, ringArraySection, nCachedElements>::Set(std::size_t index, T const & t) -> void
{
auto protector = RODOS::ScopeProtector(&semaphore); // NOLINT(google-readability-casting)
LoadIndexes();
auto size = ComputeSize();
auto size = []()
{
if(framIsWorking.Load())
{
LoadIndexes();
return ComputeSize();
}
return cache.size();
}();
if(index >= size)
{
DEBUG_PRINT("Index out of bounds in RingArray::Set: %u >= %u\n", index, size);
return;
}
if(not framIsWorking.Load())
{
cache[index] = Serialize(t);
}
auto i = iBegin;
i.advance(static_cast<int>(index));
WriteElement(i, t);
}


template<typename T, Section ringArraySection>
template<typename T, Section ringArraySection, std::size_t nCachedElements>
requires(serialSize<T> > 0)
auto RingArray<T, ringArraySection>::PushBack(T const & t) -> void
auto RingArray<T, ringArraySection, nCachedElements>::PushBack(T const & t) -> void
{
auto protector = RODOS::ScopeProtector(&semaphore); // NOLINT(google-readability-casting)
if(not framIsWorking.Load())
{
cache.push(Serialize(t));
return;
}
LoadIndexes();
WriteElement(iEnd, t);
// We reduce the capacity by one to distinguish between an empty and a full ring: iEnd == iBegin
Expand All @@ -119,48 +153,72 @@ auto RingArray<T, ringArraySection>::PushBack(T const & t) -> void
}


template<typename T, Section ringArraySection>
template<typename T, Section ringArraySection, std::size_t nCachedElements>
requires(serialSize<T> > 0)
typename RingArray<T, ringArraySection, nCachedElements>::RingIndex
RingArray<T, ringArraySection, nCachedElements>::iEnd = {};


template<typename T, Section ringArraySection, std::size_t nCachedElements>
requires(serialSize<T> > 0)
typename RingArray<T, ringArraySection, nCachedElements>::RingIndex
RingArray<T, ringArraySection, nCachedElements>::iBegin = {};


template<typename T, Section ringArraySection, std::size_t nCachedElements>
requires(serialSize<T> > 0)
etl::circular_buffer<SerialBuffer<T>,
nCachedElements> RingArray<T, ringArraySection, nCachedElements>::cache = {};


template<typename T, Section ringArraySection, std::size_t nCachedElements>
requires(serialSize<T> > 0)
RODOS::Semaphore RingArray<T, ringArraySection, nCachedElements>::semaphore = {};


template<typename T, Section ringArraySection, std::size_t nCachedElements>
requires(serialSize<T> > 0)
auto RingArray<T, ringArraySection>::LoadIndexes() -> void
auto RingArray<T, ringArraySection, nCachedElements>::LoadIndexes() -> void
{
iBegin.set(persistentIndexes.template Load<"iBegin">());
iEnd.set(persistentIndexes.template Load<"iEnd">());
}


template<typename T, Section ringArraySection>
template<typename T, Section ringArraySection, std::size_t nCachedElements>
requires(serialSize<T> > 0)
auto RingArray<T, ringArraySection>::StoreIndexes() -> void
auto RingArray<T, ringArraySection, nCachedElements>::StoreIndexes() -> void
{
persistentIndexes.template Store<"iBegin">(iBegin.get());
persistentIndexes.template Store<"iEnd">(iEnd.get());
}


template<typename T, Section ringArraySection>
template<typename T, Section ringArraySection, std::size_t nCachedElements>
requires(serialSize<T> > 0)
auto RingArray<T, ringArraySection>::ComputeSize() -> std::size_t
auto RingArray<T, ringArraySection, nCachedElements>::ComputeSize() -> std::size_t
{
if(iEnd.get() >= iBegin.get())
{
return iEnd.get() - iBegin.get();
}
return capacity + 1 + iEnd.get() - iBegin.get();
return framCapacity + 1 + iEnd.get() - iBegin.get();
}


template<typename T, Section ringArraySection>
template<typename T, Section ringArraySection, std::size_t nCachedElements>
requires(serialSize<T> > 0)
auto RingArray<T, ringArraySection>::ReadElement(RingIndex index) -> T
auto RingArray<T, ringArraySection, nCachedElements>::ReadElement(RingIndex index) -> T
{
auto address = subsections.template Get<"array">().begin + index.get() * elementSize;
return Deserialize<T>(fram::ReadFrom<serialSize<T>>(address, value_of(spiTimeout)));
}


template<typename T, Section ringArraySection>
template<typename T, Section ringArraySection, std::size_t nCachedElements>
requires(serialSize<T> > 0)
auto RingArray<T, ringArraySection>::WriteElement(RingIndex index, T const & t) -> void
auto RingArray<T, ringArraySection, nCachedElements>::WriteElement(RingIndex index, T const & t)
-> void
{
auto address = subsections.template Get<"array">().begin + index.get() * elementSize;
fram::WriteTo(address, Span(Serialize(t)), value_of(spiTimeout));
Expand Down
Loading

0 comments on commit 740db96

Please sign in to comment.