Skip to content

Commit

Permalink
Mock Fram Code
Browse files Browse the repository at this point in the history
  • Loading branch information
jeromehue committed May 3, 2024
1 parent 4c3ac27 commit fc0fd3d
Show file tree
Hide file tree
Showing 8 changed files with 281 additions and 5 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ prefix/
CMakeLists.txt.user
CMakeUserPresets.json
compile_commands.json
FramMock.bin
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ add_library(Sts1CobcSw_FileSystem STATIC)
add_library(Sts1CobcSw_Outcome INTERFACE)
add_library(Sts1CobcSw_Serial INTERFACE)
add_library(Sts1CobcSw_Utility STATIC)
add_library(Sts1CobcSw_Periphery STATIC)
add_program(HelloDummy)
# add_program(Heartbeat)

if(CMAKE_SYSTEM_NAME STREQUAL Generic)
add_library(Sts1CobcSw_Periphery STATIC)
add_library(Sts1CobcSw_Hal STATIC)
add_program(CobcSw)
endif()
Expand Down
2 changes: 1 addition & 1 deletion Sts1CobcSw/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
if(CMAKE_SYSTEM_NAME STREQUAL Generic)
add_subdirectory(Periphery)
add_subdirectory(Hal)
endif()
add_subdirectory(Periphery)
add_subdirectory(Edu)
add_subdirectory(FileSystem)
add_subdirectory(Outcome)
Expand Down
9 changes: 6 additions & 3 deletions Sts1CobcSw/Periphery/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
target_link_libraries(Sts1CobcSw_Periphery PUBLIC rodos::rodos Sts1CobcSw_Serial Sts1CobcSw_Outcome)

if(CMAKE_SYSTEM_NAME STREQUAL Generic)
target_sources(
Sts1CobcSw_Periphery PRIVATE PersistentState.cpp Flash.cpp Fram.cpp Rf.cpp Eps.cpp
)
target_sources(Sts1CobcSw_Periphery PRIVATE Fram.cpp)
target_sources(Sts1CobcSw_Periphery PRIVATE PersistentState.cpp)
target_sources(Sts1CobcSw_Periphery PRIVATE Flash.cpp Rf.cpp Eps.cpp)

target_link_libraries(Sts1CobcSw_Periphery PRIVATE Sts1CobcSw_Utility)
target_link_libraries(Sts1CobcSw_Periphery PUBLIC Sts1CobcSw_Hal)
else()
target_sources(Sts1CobcSw_Periphery PRIVATE FramMock.cpp)
endif()
121 changes: 121 additions & 0 deletions Sts1CobcSw/Periphery/FramMock.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
#include <Sts1CobcSw/Periphery/FramMock.hpp>

#include <cstring>
#include <fstream>
#include <ios>
#include <iostream>
#include <vector>


namespace sts1cobcsw::fram
{

auto ramSimulation = std::array<uint8_t, 1048576>{};
MockMode mockDevice = MockMode::ram;
constexpr auto mockFilename = "FramMock.bin";

auto FramMockMode(MockMode mockMode) -> void
{
mockDevice = mockMode;
}

// Default do functions, doing nothing
auto DoInitializeDefault() -> void
{
}

auto DoReadDeviceIdDefault() -> DeviceId
{
return DeviceId{};
}

auto DoActualBaudRateDefault() -> int32_t
{
return 0;
}


auto doInitialize = DoInitializeDefault;
auto doReadDeviceId = DoReadDeviceIdDefault;
auto doActualBaudRate = DoActualBaudRateDefault;


auto SetDoInitialize(void (*doInitializeFunction)()) -> void
{
doInitialize = doInitializeFunction;
}

auto SetDoReadDeviceId(DeviceId (*doReadDeviceIdFunction)()) -> void
{
doReadDeviceId = doReadDeviceIdFunction;
}

void SetDoActualBaudRate(int32_t (*doActualBaudRateFunction)())
{
doActualBaudRate = doActualBaudRateFunction;
}


auto Initialize() -> void
{
return doInitialize();
}

auto ReadDeviceId() -> DeviceId
{
return doReadDeviceId();
}

auto ActualBaudRate() -> int32_t
{
return doActualBaudRate();
}


namespace internal
{
auto WriteTo(Address address, void const * data, std::size_t nBytes) -> void
{
if(mockDevice == MockMode::file)
{
std::ofstream file(mockFilename, std::ios::binary | std::ios_base::ate);
if(not file)
{
std::cerr << "Failed to open file " << mockFilename << " for writing." << '\n';
return;
}

file.seekp(address);
file.write(static_cast<char const *>(data), static_cast<std::streamsize>(nBytes));
file.close();
}
else
{
// FIXME: Fix pointer arithmetic
std::memcpy(ramSimulation.data() + address, data, nBytes);
}
}

auto ReadFrom(Address address, void * data, std::size_t nBytes) -> void
{
if(mockDevice == MockMode::file)
{
std::ifstream file(mockFilename, std::ios::binary);
if(not file)
{
std::cerr << "Failed to open file " << mockFilename << " for reading." << '\n';
return;
}

file.clear();
file.seekg(address);
file.read(static_cast<char *>(data), static_cast<std::streamsize>(nBytes));
file.close();
}
else
{
std::memcpy(data, ramSimulation.data() + address, nBytes);
}
}
}
}
41 changes: 41 additions & 0 deletions Sts1CobcSw/Periphery/FramMock.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#pragma once


#include <Sts1CobcSw/Periphery/Fram.hpp>


namespace sts1cobcsw::fram
{
auto SetDoInitialize(void (*doInitializeFunction)()) -> void;
auto SetDoReadDeviceId(DeviceId (*doReadDeviceIdFunction)()) -> void;
auto SetDoActualBaudRate(int32_t (*doActualBaudRateFunction)()) -> void;


// Default "do" functions that do nothing, used to initialized function pointers
auto DoInitializeDefault() -> void;
auto DoReadDeviceIdDefault() -> DeviceId;
auto DoActualBaudRateDefault() -> int32_t;


enum class MockMode
{
ram,
file
};

auto FramMockMode(MockMode mockMode) -> void;

namespace ram
{
auto DoInitialize() -> void;
auto DoReadDeviceId() -> DeviceId;
auto DoActualBaudRate() -> int32_t;
}

namespace file
{
auto DoInitialize() -> void;
auto DoReadDeviceId() -> DeviceId;
auto DoActualBaudRate() -> int32_t;
}
}
5 changes: 5 additions & 0 deletions Tests/UnitTests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ target_link_libraries(Sts1CobcSwTests_LfsRam PRIVATE Catch2::Catch2WithMain Sts1
add_program(Outcome Outcome.test.cpp)
target_link_libraries(Sts1CobcSwTests_Outcome PRIVATE Catch2::Catch2WithMain)

add_program(Fram Fram.test.cpp)
target_link_libraries(
Sts1CobcSwTests_Fram PRIVATE Catch2::Catch2WithMain Sts1CobcSw_Periphery Sts1CobcSw_Serial
)

# TODO: Fix the problem with two main()s, one from Rodos one from Catch, somehow
if(FALSE)
add_program(PersistentState PersistentState.test.cpp)
Expand Down
105 changes: 105 additions & 0 deletions Tests/UnitTests/Fram.test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#include <Sts1CobcSw/Periphery/Fram.hpp>
#include <Sts1CobcSw/Periphery/FramMock.hpp>
#include <Sts1CobcSw/Serial/Byte.hpp>
#include <Sts1CobcSw/Utility/Span.hpp>

#include <catch2/catch_test_macros.hpp>

#include <algorithm>
#include <array>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <random>
#include <span>


namespace fram = sts1cobcsw::fram;


using sts1cobcsw::Byte;
using sts1cobcsw::Span;
using sts1cobcsw::operator""_b; // NOLINT(misc-unused-using-decls)


constexpr auto nAddressBits = 20U;
size_t const testDataSize = 11 * 1024; // 11 KiB
auto testData = std::array<Byte, testDataSize>{};
auto readData = std::array<Byte, testDataSize>{};


auto WriteAndReadTestData(sts1cobcsw::fram::Address const & address) -> void;


TEST_CASE("Fram mock using ram")
{
fram::FramMockMode(fram::MockMode::ram);

std::mt19937 randomEngine(std::random_device{}());
std::uniform_int_distribution<uint32_t> gen(0, (1U << nAddressBits) - 1);
fram::Address const address = gen(randomEngine);

WriteAndReadTestData(address);
std::generate(
testData.begin(), testData.end(), [&]() { return static_cast<std::byte>(randomEngine()); });
WriteAndReadTestData(address);
<<<<<<< HEAD
=======

auto deviceId = fram::ReadDeviceId();
constexpr auto correctDeviceId =
std::to_array({0x03_b, 0x2E_b, 0xC2_b, 0x7F_b, 0x7F_b, 0x7F_b, 0x7F_b, 0x7F_b, 0x7F_b});
REQUIRE(deviceId != correctDeviceId);
fram::SetDoReadDeviceId(ReadCorrectDeviceId);
deviceId = fram::ReadDeviceId();
REQUIRE(deviceId == correctDeviceId);
>>>>>>> 465f578 (Fix more stuff)
}

TEST_CASE("Fram mock using file")
{
fram::FramMockMode(fram::MockMode::file);

std::mt19937 randomEngine(std::random_device{}());
std::uniform_int_distribution<std::uint32_t> addressGenerator(0, ((1U << nAddressBits) - 1));
fram::Address const address = addressGenerator(randomEngine);

WriteAndReadTestData(address);
std::generate(
testData.begin(), testData.end(), [&]() { return static_cast<std::byte>(randomEngine()); });
WriteAndReadTestData(address);
}

auto WriteAndReadTestData(fram::Address const & address) -> void
{
auto nBytesToPrint = 10U;

std::printf("Writing %d bytes to address 0x%08x ...\n",
static_cast<int>(testDataSize),
static_cast<unsigned int>(address));
fram::WriteTo(address, Span(testData));
<<<<<<< HEAD
std::printf("Reading n bytes from address ...\n");
=======

std::printf("Reading %d bytes from address 0x%08x ...\n",
static_cast<int>(testDataSize),
static_cast<unsigned int>(address));
>>>>>>> 465f578 (Fix more stuff)
fram::ReadFrom(address, Span(&readData));

std::printf("Comparing first %d written and read bytes:\n", nBytesToPrint);
std::printf(" ");
for(auto byte : Span(testData).first(nBytesToPrint))
{
std::printf("0x%02x ", static_cast<unsigned char>(byte));
}
std::printf("\n ");
for(auto byte : Span(readData).first(nBytesToPrint))
{
std::printf("0x%02x ", static_cast<unsigned char>(byte));
}
std::printf("\n");

REQUIRE(readData == testData);
}

0 comments on commit fc0fd3d

Please sign in to comment.