Skip to content

Commit

Permalink
feat: added SerialCommunicationLoopback (#440)
Browse files Browse the repository at this point in the history
* feat: added SerialCommunicationLoopback

* chore: replaced ClockFixture with EventDispatcherFixture

* chore: made SerialCommunicationLoopback compatible with <= GCC9

* chore: fixed comments

* chore: correct comparing byte ranges for SerialCommunicationLoopbackTest

* chore: fix coverage and macos build

---------

Co-authored-by: Daan Timmer <[email protected]>
  • Loading branch information
daantimmer and Daan Timmer authored Oct 20, 2023
1 parent 4b52156 commit 2c87dfb
Show file tree
Hide file tree
Showing 5 changed files with 152 additions and 0 deletions.
2 changes: 2 additions & 0 deletions services/util/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ target_sources(services.util PRIVATE
MessageCommunicationWindowed.hpp
RepeatingButton.cpp
RepeatingButton.hpp
SerialCommunicationLoopback.cpp
SerialCommunicationLoopback.hpp
Sha256.hpp
SignalLed.cpp
SignalLed.hpp
Expand Down
42 changes: 42 additions & 0 deletions services/util/SerialCommunicationLoopback.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#include "services/util/SerialCommunicationLoopback.hpp"
#include "hal/interfaces/SerialCommunication.hpp"
#include "infra/event/EventDispatcher.hpp"

namespace services
{
SerialCommunicationLoopback::SerialCommunicationLoopback()
: server(&client)
, client(&server)
{}

hal::SerialCommunication& SerialCommunicationLoopback::Server()
{
return server;
}

hal::SerialCommunication& SerialCommunicationLoopback::Client()
{
return client;
}

SerialCommunicationLoopback::SerialCommunicationLoopbackPeer::SerialCommunicationLoopbackPeer(SerialCommunicationLoopbackPeer* other)
: other{ *other }
{}

void SerialCommunicationLoopback::SerialCommunicationLoopbackPeer::SendData(infra::ConstByteRange data, infra::Function<void()> actionOnCompletion)
{
this->data = data;
this->actionOnCompletion = actionOnCompletion;

infra::EventDispatcher::Instance().Schedule([this]
{
other.dataReceived(this->data);
this->actionOnCompletion();
});
}

void SerialCommunicationLoopback::SerialCommunicationLoopbackPeer::ReceiveData(infra::Function<void(infra::ConstByteRange data)> dataReceived)
{
this->dataReceived = dataReceived;
}
}
43 changes: 43 additions & 0 deletions services/util/SerialCommunicationLoopback.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#ifndef SERVICES_SERIAL_COMMUNICATION_LOOPBACK_HPP
#define SERVICES_SERIAL_COMMUNICATION_LOOPBACK_HPP

#include "hal/interfaces/SerialCommunication.hpp"

namespace services
{

class SerialCommunicationLoopback
{
public:
SerialCommunicationLoopback();

hal::SerialCommunication& Server();
hal::SerialCommunication& Client();

private:
class SerialCommunicationLoopbackPeer
: public hal::SerialCommunication
{
public:
// pointer instead of reference to avoid defining a copy constructor
// pass by reference generates a warning with clang and -Wunitialized
explicit SerialCommunicationLoopbackPeer(SerialCommunicationLoopbackPeer* other);

void SendData(infra::ConstByteRange data, infra::Function<void()> actionOnCompletion) override;
void ReceiveData(infra::Function<void(infra::ConstByteRange data)> dataReceived) override;

private:
SerialCommunicationLoopbackPeer& other;

infra::ConstByteRange data;
infra::Function<void()> actionOnCompletion;
infra::Function<void(infra::ConstByteRange data)> dataReceived;
};

private:
SerialCommunicationLoopbackPeer server;
SerialCommunicationLoopbackPeer client;
};
}

#endif
2 changes: 2 additions & 0 deletions services/util/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ target_link_libraries(services.util_test PUBLIC
hal.interfaces_test_doubles
infra.timer_test_helper
infra.util_test_helper
infra.event_test_helper
)

target_sources(services.util_test PRIVATE
Expand All @@ -39,6 +40,7 @@ target_sources(services.util_test PRIVATE
TestMessageCommunicationSecured.cpp
TestMessageCommunicationWindowed.cpp
TestRepeatingButton.cpp
TestSerialCommunicationLoopback.cpp
TestSignalLed.cpp
TestSpiMasterWithChipSelect.cpp
TestSpiMultipleAccess.cpp
Expand Down
63 changes: 63 additions & 0 deletions services/util/test/TestSerialCommunicationLoopback.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#include "hal/interfaces/SerialCommunication.hpp"
#include "infra/event/test_helper/EventDispatcherFixture.hpp"
#include "infra/util/ByteRange.hpp"
#include "infra/util/Function.hpp"
#include "infra/util/test_helper/MockCallback.hpp"
#include "services/util/SerialCommunicationLoopback.hpp"
#include "gmock/gmock.h"
#include "gtest/gtest.h"

class SerialCommunicationLoopbackTest
: public testing::Test
, public infra::EventDispatcherFixture
{
public:
services::SerialCommunicationLoopback SerialCommunicationLoopback;
hal::SerialCommunication& server{ SerialCommunicationLoopback.Server() };
hal::SerialCommunication& client{ SerialCommunicationLoopback.Client() };
};

TEST_F(SerialCommunicationLoopbackTest, SendFromServerReceiveByClient)
{
infra::ConstByteRange data = infra::MakeStringByteRange("hello");
infra::VerifyingFunctionMock<void(infra::ConstByteRange)> clientReceiveCallback{ data };

client.ReceiveData(clientReceiveCallback);
server.SendData(data, infra::emptyFunction);

ExecuteAllActions();
}

TEST_F(SerialCommunicationLoopbackTest, SendFromClientReceiveByServer)
{
infra::ConstByteRange data = infra::MakeStringByteRange("world");
infra::VerifyingFunctionMock<void(infra::ConstByteRange)> serverReceiveCallback{ data };

server.ReceiveData(serverReceiveCallback);
client.SendData(data, infra::emptyFunction);

ExecuteAllActions();
}

TEST_F(SerialCommunicationLoopbackTest, ActionOnCompletionAfterDataReceivedByOtherPeer)
{
infra::ConstByteRange data = infra::MakeStringByteRange("Hello World!");
infra::MockCallback<void(infra::ConstByteRange)> dataReceivedMockCallback;
infra::MockCallback<void()> actionOnCompletionMockCallback;

server.ReceiveData([&dataReceivedMockCallback](infra::ConstByteRange data)
{
dataReceivedMockCallback.callback(data);
});

client.SendData(data, [&actionOnCompletionMockCallback]
{
actionOnCompletionMockCallback.callback();
});

testing::InSequence sequence;
EXPECT_CALL(dataReceivedMockCallback, callback(data));
EXPECT_CALL(actionOnCompletionMockCallback, callback());

ExecuteAllActions();
}

0 comments on commit 2c87dfb

Please sign in to comment.