Skip to content

Commit

Permalink
Add EdacVariable<>
Browse files Browse the repository at this point in the history
We will need that later for `framIsWorking`.
  • Loading branch information
PatrickKa committed Aug 25, 2024
1 parent 3c573d7 commit 4a19cdb
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 29 deletions.
43 changes: 30 additions & 13 deletions Sts1CobcSw/Utility/ErrorDetectionAndCorrection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,37 @@

namespace sts1cobcsw
{
// I won't make a separate .ipp file just for this simple function
template<typename T>
class EdacVariable
{
public:
constexpr EdacVariable() = default;
explicit constexpr EdacVariable(T const & value);
EdacVariable(EdacVariable const &) = delete;
EdacVariable(EdacVariable &&) = delete;
auto operator=(EdacVariable const &) -> EdacVariable & = delete;
auto operator=(EdacVariable &&) -> EdacVariable & = delete;
~EdacVariable() = default;

[[nodiscard]] constexpr auto Load() const -> T;
constexpr auto Store(T const & value) -> void;


private:
// This function must be const, because it is called from Load() which is const
constexpr auto SetAllValues(T const & value) const -> void;

mutable T value0_ = T{};
mutable T value1_ = T{};
mutable T value2_ = T{};
};


template<typename T>
[[nodiscard]] constexpr auto ComputeMajorityVote(T const & value0,
T const & value1,
T const & value2) -> std::optional<T>
{
if(value0 == value1 or value0 == value2)
{
return value0;
}
if(value1 == value2)
{
return value1;
}
return std::nullopt;
}
T const & value2) -> std::optional<T>;
}


#include <Sts1CobcSw/Utility/ErrorDetectionAndCorrection.ipp> // IWYU pragma: keep
58 changes: 58 additions & 0 deletions Sts1CobcSw/Utility/ErrorDetectionAndCorrection.ipp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#pragma once


#include <Sts1CobcSw/Utility/ErrorDetectionAndCorrection.hpp>


namespace sts1cobcsw
{
template<typename T>
constexpr EdacVariable<T>::EdacVariable(T const & value)
: value0_(value), value1_(value), value2_(value)
{
}


template<typename T>
constexpr auto EdacVariable<T>::Load() const -> T
{
// TODO: Make Load() thread-safe/atomic
auto voteResult = ComputeMajorityVote(value0_, value1_, value2_);
auto value = voteResult.value_or(value0_);
SetAllValues(value);
return value;
}


template<typename T>
constexpr auto EdacVariable<T>::Store(T const & value) -> void
{
// TODO: Make Store() thread-safe/atomic
SetAllValues(value);
}


template<typename T>
constexpr auto EdacVariable<T>::SetAllValues(T const & value) const -> void
{
value0_ = value;
value1_ = value;
value2_ = value;
}


template<typename T>
constexpr auto ComputeMajorityVote(T const & value0, T const & value1, T const & value2)
-> std::optional<T>
{
if(value0 == value1 or value0 == value2)
{
return value0;
}
if(value1 == value2)
{
return value1;
}
return std::nullopt;
}
}
2 changes: 2 additions & 0 deletions Tests/UnitTests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ add_program(ErrorDetectionAndCorrection ErrorDetectionAndCorrection.test.cpp)
target_link_libraries(
Sts1CobcSwTests_ErrorDetectionAndCorrection PRIVATE Catch2::Catch2WithMain Sts1CobcSw_Utility
)
# Disable warnings about memcpy() of non-trivially copiable type EdacVariable<>
target_compile_options(Sts1CobcSwTests_ErrorDetectionAndCorrection PRIVATE -Wno-class-memaccess)

add_program(FlatArray FlatArray.test.cpp)
target_link_libraries(Sts1CobcSwTests_FlatArray PRIVATE Catch2::Catch2WithMain Sts1CobcSw_Utility)
Expand Down
75 changes: 75 additions & 0 deletions Tests/UnitTests/ErrorDetectionAndCorrection.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@

#include <catch2/catch_test_macros.hpp>

#include <array>
#include <cstring>
#include <optional>
#include <string>
#include <type_traits>


TEST_CASE("Majority vote")
Expand All @@ -28,3 +32,74 @@ TEST_CASE("Majority vote")
voteResult = ComputeMajorityVote(17, 173, -2);
CHECK(not voteResult.has_value());
}


struct S
{
char c = 's';

[[nodiscard]] friend constexpr auto operator==(S const & lhs, S const & rhs) -> bool
{
return lhs.c == rhs.c;
}
};


TEST_CASE("EdacVariable")
{
using sts1cobcsw::EdacVariable;


SECTION("Construction")
{
auto variable1 = EdacVariable<S>();
auto variable2 = EdacVariable<int>();
auto variable3 = EdacVariable<double>(-3.14);
CHECK(variable1.Load().c == 's');
CHECK(variable2.Load() == 0);
CHECK(variable3.Load() == -3.14);
}

SECTION("You load what you store")
{
auto variable = EdacVariable<int>(17);
CHECK(variable.Load() == 17);
variable.Store(-123);
CHECK(variable.Load() == -123);
}

SECTION("Error correction")
{
auto variable = EdacVariable<char>('a');
CHECK(variable.Load() == 'a');

// Those memcpy's are unspecified behavior but I can't think of a better way (= one that is
// not undefined behavior) and it seems to work
auto data = std::array<char, sizeof(variable)>{};
std::memcpy(data.data(), &variable, sizeof(variable));
data[0] = 'x';
std::memcpy(&variable, data.data(), sizeof(variable));
CHECK(variable.Load() == 'a');
std::memcpy(data.data(), &variable, sizeof(variable));
CHECK(data == std::array{'a', 'a', 'a'});

data[1] = 'x';
std::memcpy(&variable, data.data(), sizeof(variable));
CHECK(variable.Load() == 'a');
std::memcpy(data.data(), &variable, sizeof(variable));
CHECK(data == std::array{'a', 'a', 'a'});

data[2] = 'x';
std::memcpy(&variable, data.data(), sizeof(variable));
CHECK(variable.Load() == 'a');
std::memcpy(data.data(), &variable, sizeof(variable));
CHECK(data == std::array{'a', 'a', 'a'});

data[0] = 'x';
data[1] = 'x';
std::memcpy(&variable, data.data(), sizeof(variable));
CHECK(variable.Load() == 'x');
std::memcpy(data.data(), &variable, sizeof(variable));
CHECK(data == std::array{'x', 'x', 'x'});
}
}
34 changes: 18 additions & 16 deletions iwyu.imp
Original file line number Diff line number Diff line change
Expand Up @@ -45,21 +45,22 @@
{ include: ["<etl/basic_string.h>", "private", "<etl/string.h>", "public"] },

# Instead of all our .ipp files include the .hpp ones
{ include: ["\"Sts1CobcSw/Edu/Types.ipp\"", "private", "<Sts1CobcSw/Edu/Types.hpp>", "public"] },
{ include: ["\"Sts1CobcSw/FileSystem/FileSystem.ipp\"", "private", "<Sts1CobcSw/FileSystem/FileSystem.hpp>", "public"] },
{ include: ["\"Sts1CobcSw/FramSections/Subsections.ipp\"", "private", "<Sts1CobcSw/FramSections/Subsections.hpp>", "public"] },
{ include: ["\"Sts1CobcSw/FramSections/PersistentVariables.ipp\"", "private", "<Sts1CobcSw/FramSections/PersistentVariables.hpp>", "public"] },
{ include: ["\"Sts1CobcSw/Hal/GpioPin.ipp\"", "private", "<Sts1CobcSw/Hal/GpioPin.hpp>", "public"] },
{ include: ["\"Sts1CobcSw/Hal/Spi.ipp\"", "private", "<Sts1CobcSw/Hal/Spi.hpp>", "public"] },
{ include: ["\"Sts1CobcSw/Hal/Uart.ipp\"", "private", "<Sts1CobcSw/Hal/Uart.hpp>", "public"] },
{ include: ["\"Sts1CobcSw/Periphery/Fram.ipp\"", "private", "<Sts1CobcSw/Periphery/Fram.hpp>", "public"] },
{ include: ["\"Sts1CobcSw/PersistentState/PersistentVariable.ipp\"", "private", "<Sts1CobcSw/PersistentState/PersistentVariable.hpp>", "public"] },
{ include: ["\"Sts1CobcSw/ProgramId/ProgramId.ipp\"", "private", "<Sts1CobcSw/ProgramId/ProgramId.hpp>", "public"] },
{ include: ["\"Sts1CobcSw/Serial/Byte.ipp\"", "private", "<Sts1CobcSw/Serial/Byte.hpp>", "public"] },
{ include: ["\"Sts1CobcSw/Serial/Serial.ipp\"", "private", "<Sts1CobcSw/Serial/Serial.hpp>", "public"] },
{ include: ["\"Sts1CobcSw/Utility/Span.ipp\"", "private", "<Sts1CobcSw/Utility/Span.hpp>", "public"] },
{ include: ["\"Sts1CobcSw/Utility/StringLiteral.ipp\"", "private", "<Sts1CobcSw/Utility/StringLiteral.hpp>", "public"] },
{ include: ["\"Sts1CobcSw/Utility/Time.ipp\"", "private", "<Sts1CobcSw/Utility/Time.hpp>", "public"] },
{ include: ["\"Sts1CobcSw/Edu/Types.ipp\"", "private", "<Sts1CobcSw/Edu/Types.hpp>", "public"] },
{ include: ["\"Sts1CobcSw/FileSystem/FileSystem.ipp\"", "private", "<Sts1CobcSw/FileSystem/FileSystem.hpp>", "public"] },
{ include: ["\"Sts1CobcSw/FramSections/Subsections.ipp\"", "private", "<Sts1CobcSw/FramSections/Subsections.hpp>", "public"] },
{ include: ["\"Sts1CobcSw/FramSections/PersistentVariables.ipp\"", "private", "<Sts1CobcSw/FramSections/PersistentVariables.hpp>", "public"] },
{ include: ["\"Sts1CobcSw/Hal/GpioPin.ipp\"", "private", "<Sts1CobcSw/Hal/GpioPin.hpp>", "public"] },
{ include: ["\"Sts1CobcSw/Hal/Spi.ipp\"", "private", "<Sts1CobcSw/Hal/Spi.hpp>", "public"] },
{ include: ["\"Sts1CobcSw/Hal/Uart.ipp\"", "private", "<Sts1CobcSw/Hal/Uart.hpp>", "public"] },
{ include: ["\"Sts1CobcSw/Periphery/Fram.ipp\"", "private", "<Sts1CobcSw/Periphery/Fram.hpp>", "public"] },
{ include: ["\"Sts1CobcSw/PersistentState/PersistentVariable.ipp\"", "private", "<Sts1CobcSw/PersistentState/PersistentVariable.hpp>", "public"] },
{ include: ["\"Sts1CobcSw/ProgramId/ProgramId.ipp\"", "private", "<Sts1CobcSw/ProgramId/ProgramId.hpp>", "public"] },
{ include: ["\"Sts1CobcSw/Serial/Byte.ipp\"", "private", "<Sts1CobcSw/Serial/Byte.hpp>", "public"] },
{ include: ["\"Sts1CobcSw/Serial/Serial.ipp\"", "private", "<Sts1CobcSw/Serial/Serial.hpp>", "public"] },
{ include: ["\"Sts1CobcSw/Utility/ErrorDetectionAndCorrection.ipp\"", "private", "<Sts1CobcSw/Utility/ErrorDetectionAndCorrection.hpp>", "public"] },
{ include: ["\"Sts1CobcSw/Utility/Span.ipp\"", "private", "<Sts1CobcSw/Utility/Span.hpp>", "public"] },
{ include: ["\"Sts1CobcSw/Utility/StringLiteral.ipp\"", "private", "<Sts1CobcSw/Utility/StringLiteral.hpp>", "public"] },
{ include: ["\"Sts1CobcSw/Utility/Time.ipp\"", "private", "<Sts1CobcSw/Utility/Time.hpp>", "public"] },

# Include all our headers with <> instead of ""
{ include: ["\"Sts1CobcSw/Edu/Edu.hpp\"", "public", "<Sts1CobcSw/Edu/Edu.hpp>", "public"] },
Expand Down Expand Up @@ -91,9 +92,10 @@
{ include: ["\"Sts1CobcSw/PersistentState/PersistentVariable.hpp\"", "public", "<Sts1CobcSw/PersistentState/PersistentVariable.hpp>", "public"] },
{ include: ["\"Sts1CobcSw/ProgramId/ProgramId.hpp\"", "public", "<Sts1CobcSw/ProgramId/ProgramId.hpp>", "public"] },
{ include: ["\"Sts1CobcSw/Serial/Byte.hpp\"", "public", "<Sts1CobcSw/Serial/Byte.hpp>", "public"] },
{ include: ["\"Sts1CobcSw/Serial/Serial.hpp\"", "public", "<Sts1CobcwSw/Serial/Serial.hpp>", "public"] },
{ include: ["\"Sts1CobcSw/Serial/Serial.hpp\"", "public", "<Sts1CobcSw/Serial/Serial.hpp>", "public"] },
{ include: ["\"Sts1CobcSw/Utility/Crc32.hpp\"", "public", "<Sts1CobcSw/Utility/Crc32.hpp>", "public"] },
{ include: ["\"Sts1CobcSw/Utility/Debug.hpp\"", "public", "<Sts1CobcSw/Utility/Debug.hpp>", "public"] },
{ include: ["\"Sts1CobcSw/Utility/ErrorDetectionAndCorrection.hpp\"", "public", "<Sts1CobcSw/Utility/ErrorDetectionAndCorrection.hpp>", "public"] },
{ include: ["\"Sts1CobcSw/Utility/FlatArray.hpp\"", "public", "<Sts1CobcSw/Utility/FlatArray.hpp>", "public"] },
{ include: ["\"Sts1CobcSw/Utility/Span.hpp\"", "public", "<Sts1CobcSw/Utility/Span.hpp>", "public"] },
{ include: ["\"Sts1CobcSw/Utility/StringLiteral.hpp\"", "public", "<Sts1CobcSw/Utility/StringLiteral.hpp>", "public"] },
Expand Down

0 comments on commit 4a19cdb

Please sign in to comment.