Skip to content

Commit

Permalink
Add SpiMock.cpp and SpiMock.hpp
Browse files Browse the repository at this point in the history
  • Loading branch information
kamilchmela authored and PatrickKa committed Sep 29, 2024
1 parent 54f7c8a commit 199a3f9
Show file tree
Hide file tree
Showing 3 changed files with 279 additions and 1 deletion.
8 changes: 7 additions & 1 deletion Sts1CobcSw/Hal/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
target_sources(Sts1CobcSw_Hal PRIVATE Uart.cpp Spi.cpp)
target_sources(Sts1CobcSw_Hal PRIVATE Uart.cpp)
target_link_libraries(
Sts1CobcSw_Hal PUBLIC etl::etl rodos::without_main_on_linux Sts1CobcSw_Utility
Sts1CobcSw_Outcome
)
target_compile_definitions(Sts1CobcSw_Hal PUBLIC HW_VERSION=${HW_VERSION})

if(CMAKE_SYSTEM_NAME STREQUAL Generic)
target_sources(Sts1CobcSw_Hal PRIVATE Spi.cpp)
else()
target_sources(Sts1CobcSw_Hal PRIVATE SpiMock.cpp)
endif()
209 changes: 209 additions & 0 deletions Sts1CobcSw/Hal/SpiMock.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
#include <Sts1CobcSw/Hal/IoNames.hpp>
#include <Sts1CobcSw/Hal/SpiMock.hpp>

#include <strong_type/affine_point.hpp>

#include <rodos_no_using_namespace.h>

#include <etl/vector.h>


namespace sts1cobcsw::hal
{
class Spi::Impl
{
public:
static constexpr auto maxNInstances = 3;

// Since we cannot use dynamic memory allocation we use a static ETL vector to provide the
// storage for a fixed number of instances. This limitation is acceptable since we only need one
// global instance for each of the three SPIs that we use.
[[nodiscard]] static auto GetInstances() -> etl::vector<Spi::Impl, maxNInstances> &;

Impl(RODOS::SPI_IDX spiIndex,
RODOS::GPIO_PIN sckPin,
RODOS::GPIO_PIN misoPin,
RODOS::GPIO_PIN mosiPin);

auto Initialize(std::uint32_t baudRate) -> void;
auto Read(void * data, std::size_t nBytes, Duration timeout) -> void;
auto Write(void const * data, std::size_t nBytes, Duration timeout) -> void;
[[nodiscard]] auto TransferEnd() const -> RodosTime;
[[nodiscard]] auto BaudRate() const -> std::int32_t;


private:
mutable RODOS::CommBuffer transferEnd_;
};

auto doInitialize = empty::DoInitialize;
auto doRead = empty::DoRead;
auto doWrite = empty::DoWrite;
auto doTransferEnd = empty::DoTransferEnd;
auto doBaudRate = empty::DoBaudRate;

auto Spi::Impl::GetInstances() -> etl::vector<Spi::Impl, maxNInstances> &
{
static etl::vector<Spi::Impl, maxNInstances> instances;
return instances;
}


Spi::Impl::Impl(RODOS::SPI_IDX spiIndex,
RODOS::GPIO_PIN sckPin,
RODOS::GPIO_PIN misoPin,
RODOS::GPIO_PIN mosiPin)
: spi_(spiIndex, sckPin, misoPin, mosiPin, spiNssDummyPin)
{
transferEnd_ = RodosTime(RODOS::END_OF_TIME);
}


auto Spi::Impl::Initialize(std::uint32_t baudRate) -> void
{
return doInitialize();
}


auto Spi::Impl::Read(void * data, std::size_t nBytes, Duration timeout) -> void
{
return doRead();
}


auto Spi::Impl::Write(void const * data, std::size_t nBytes, Duration timeout) -> void
{
return doWrite();
}


auto Spi::Impl::TransferEnd() const -> RodosTime
{
return doTransferEnd();
}


auto Spi::Impl::BaudRate() const -> std::int32_t
{
return doBaudRate();
}


// --- Set functions ---

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


auto SetDoRead(void (*doReadFunction)()) -> void
{
doRead = doReadFunction;
}


auto SetDoWtite(void (*doWriteFunction)()) -> void
{
doWrite = doWriteFunction;
}


auto SetDoTransferEnd(RodosTime (*doTransferEndFunction)()) -> void
{
doTransferEnd = doTransferEndFunction;
}


auto SetDoBaudRate(std::int32_t (*doBaudRateFunction)()) -> void
{
doBaudRate = doBaudRateFunction;
}


// --- Predefined do functions ---

namespace empty
{
auto SetAllDoFunctions() -> void
{
SetDoInitialize(DoInitialize);
SetDoRead(DoRead);
SetDoWrite(DoWrite);
SetDoTransferEnd(DoTransferEnd);
SetDoBaudRate(DoBaudRate);
}


auto DoInitialize([[maybe_unused]] std::uint32_t baudRate) -> void
{
}


auto DoRead([[maybe_unused]] void * data,
[[maybe_unused]] std::size_t nBytes,
[[maybe_unused]] Duration timeout) -> void
{
}


auto DoWrite([[maybe_unused]] void const * data,
[[maybe_unused]] std::size_t nBytes,
[[maybe_unused]] Duration timeout) -> void
{
}


auto DoTransferEnd() -> RodosTime
{
return endOfTime;
}


auto DoBaudRate() -> std::int32_t
{
return 0;
}
}


Spi::Spi(RODOS::SPI_IDX spiIndex,
RODOS::GPIO_PIN sckPin,
RODOS::GPIO_PIN misoPin,
RODOS::GPIO_PIN mosiPin)
{
// TODO: Check what happens if we exceed maxNInstances
Impl::GetInstances().emplace_back(spiIndex, sckPin, misoPin, mosiPin);
pimpl_ = &Impl::GetInstances().back(); // NOLINT(*prefer-member-initializer)
}


auto Spi::TransferEnd() const -> RodosTime
{
return pimpl_->TransferEnd();
}


auto Spi::BaudRate() const -> std::int32_t
{
return pimpl_->BaudRate();
}


auto Initialize(Spi * spi, std::uint32_t baudRate) -> void
{
spi->pimpl_->Initialize(baudRate);
}


auto Spi::Read(void * data, std::size_t nBytes, Duration timeout) -> void
{
pimpl_->Read(data, nBytes, timeout);
}


auto Spi::Write(void const * data, std::size_t nBytes, Duration timeout) -> void
{
pimpl_->Write(data, nBytes, timeout);
}
}
63 changes: 63 additions & 0 deletions Sts1CobcSw/Hal/SpiMock.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#pragma once


#include <Sts1CobcSw/Utility/TimeTypes.hpp>

#include <rodos_no_using_namespace.h>

#include <cstddef>
#include <cstdint>
#include <span>


namespace sts1cobcsw::hal
{
class Spi
{
public:
Spi() = delete;
Spi(RODOS::SPI_IDX spiIndex,
RODOS::GPIO_PIN sckPin,
RODOS::GPIO_PIN misoPin,
RODOS::GPIO_PIN mosiPin);

// The following functions are friends and not members to keep the interface coherent with the
// rest of the low-level code.
friend auto Initialize(Spi * spi, std::uint32_t baudRate) -> void;
template<typename T, std::size_t extent>
friend auto ReadFrom(Spi * spi, std::span<T, extent> data, Duration timeout) -> void;
template<typename T, std::size_t extent>
friend auto WriteTo(Spi * spi, std::span<T const, extent> data, Duration timeout) -> void;

[[nodiscard]] auto TransferEnd() const -> RodosTime;
[[nodiscard]] auto BaudRate() const -> std::int32_t;


private:
class Impl;
Impl * pimpl_;

auto Read(void * data, std::size_t nBytes, Duration timeout) -> void;
auto Write(void const * data, std::size_t nBytes, Duration timeout) -> void;
};

auto SetDoInitialize(void (*doInitializeFunction)()) -> void;
auto SetDoRead(void (*doReadFunction)()) -> void;
auto SetDoWrite(void (*doWriteFunction)()) -> void;
auto SetDoTransferEnd(RodosTime (*doTransferEndFunction)()) -> void;
auto SetDoBaudRate(std::int32_t (*doBaudRateFunction)()) -> void;

namespace empty
{
auto SetAllDoFunctions() -> void;

auto DoInitialize(std::uint32_t baudRate) -> void;
auto DoRead(void * data, std::size_t nBytes, Duration timeout) -> void;
auto DoWrite(void const * data, std::size_t nBytes, Duration timeout) -> void;
auto DoTransferEnd() -> RodosTime;
auto DoBaudRate() -> std::int32_t;
}
}


#include <Sts1CobcSw/Hal/Spi.ipp> // IWYU pragma: keep

0 comments on commit 199a3f9

Please sign in to comment.