1*a32d241bSJagpal Singh Gill #include "modbus/modbus.hpp"
2*a32d241bSJagpal Singh Gill #include "modbus_server_tester.hpp"
3*a32d241bSJagpal Singh Gill
4*a32d241bSJagpal Singh Gill #include <fcntl.h>
5*a32d241bSJagpal Singh Gill
6*a32d241bSJagpal Singh Gill #include <gmock/gmock.h>
7*a32d241bSJagpal Singh Gill #include <gtest/gtest.h>
8*a32d241bSJagpal Singh Gill
9*a32d241bSJagpal Singh Gill using namespace std::literals;
10*a32d241bSJagpal Singh Gill
11*a32d241bSJagpal Singh Gill namespace RTUIntf = phosphor::modbus::rtu;
12*a32d241bSJagpal Singh Gill using ModbusIntf = RTUIntf::Modbus;
13*a32d241bSJagpal Singh Gill namespace TestIntf = phosphor::modbus::test;
14*a32d241bSJagpal Singh Gill
15*a32d241bSJagpal Singh Gill class ModbusTest : public ::testing::Test
16*a32d241bSJagpal Singh Gill {
17*a32d241bSJagpal Singh Gill public:
18*a32d241bSJagpal Singh Gill static constexpr const char* clientDevicePath = "/tmp/ttyV0";
19*a32d241bSJagpal Singh Gill static constexpr const char* serverDevicePath = "/tmp/ttyV1";
20*a32d241bSJagpal Singh Gill static constexpr const auto defaultBaudeRate = "b115200";
21*a32d241bSJagpal Singh Gill int socat_pid = -1;
22*a32d241bSJagpal Singh Gill sdbusplus::async::context ctx;
23*a32d241bSJagpal Singh Gill std::unique_ptr<ModbusIntf> modbus;
24*a32d241bSJagpal Singh Gill int fdClient = -1;
25*a32d241bSJagpal Singh Gill std::unique_ptr<TestIntf::ServerTester> serverTester;
26*a32d241bSJagpal Singh Gill int fdServer = -1;
27*a32d241bSJagpal Singh Gill
ModbusTest()28*a32d241bSJagpal Singh Gill ModbusTest()
29*a32d241bSJagpal Singh Gill {
30*a32d241bSJagpal Singh Gill std::string socatCmd = std::format(
31*a32d241bSJagpal Singh Gill "socat -x -v -d -d pty,link={},rawer,echo=0,parenb,{} pty,link={},rawer,echo=0,parenb,{} & echo $!",
32*a32d241bSJagpal Singh Gill serverDevicePath, defaultBaudeRate, clientDevicePath,
33*a32d241bSJagpal Singh Gill defaultBaudeRate);
34*a32d241bSJagpal Singh Gill
35*a32d241bSJagpal Singh Gill // Start socat in the background and capture its PID
36*a32d241bSJagpal Singh Gill FILE* fp = popen(socatCmd.c_str(), "r");
37*a32d241bSJagpal Singh Gill EXPECT_NE(fp, nullptr) << "Failed to start socat: " << strerror(errno);
38*a32d241bSJagpal Singh Gill EXPECT_GT(fscanf(fp, "%d", &socat_pid), 0);
39*a32d241bSJagpal Singh Gill pclose(fp);
40*a32d241bSJagpal Singh Gill
41*a32d241bSJagpal Singh Gill // Wait for socat to start up
42*a32d241bSJagpal Singh Gill sleep(1);
43*a32d241bSJagpal Singh Gill
44*a32d241bSJagpal Singh Gill fdClient = open(clientDevicePath, O_RDWR | O_NOCTTY | O_NONBLOCK);
45*a32d241bSJagpal Singh Gill EXPECT_NE(fdClient, -1)
46*a32d241bSJagpal Singh Gill << "Failed to open serial port " << clientDevicePath
47*a32d241bSJagpal Singh Gill << " with error: " << strerror(errno);
48*a32d241bSJagpal Singh Gill
49*a32d241bSJagpal Singh Gill modbus = std::make_unique<ModbusIntf>(ctx, fdClient, 115200, 0);
50*a32d241bSJagpal Singh Gill
51*a32d241bSJagpal Singh Gill fdServer = open(serverDevicePath, O_RDWR | O_NOCTTY | O_NONBLOCK);
52*a32d241bSJagpal Singh Gill EXPECT_NE(fdServer, -1)
53*a32d241bSJagpal Singh Gill << "Failed to open serial port " << serverDevicePath
54*a32d241bSJagpal Singh Gill << " with error: " << strerror(errno);
55*a32d241bSJagpal Singh Gill
56*a32d241bSJagpal Singh Gill serverTester = std::make_unique<TestIntf::ServerTester>(ctx, fdServer);
57*a32d241bSJagpal Singh Gill }
58*a32d241bSJagpal Singh Gill
~ModbusTest()59*a32d241bSJagpal Singh Gill ~ModbusTest() noexcept override
60*a32d241bSJagpal Singh Gill {
61*a32d241bSJagpal Singh Gill if (fdClient != -1)
62*a32d241bSJagpal Singh Gill {
63*a32d241bSJagpal Singh Gill close(fdClient);
64*a32d241bSJagpal Singh Gill fdClient = -1;
65*a32d241bSJagpal Singh Gill }
66*a32d241bSJagpal Singh Gill if (fdServer != -1)
67*a32d241bSJagpal Singh Gill {
68*a32d241bSJagpal Singh Gill close(fdServer);
69*a32d241bSJagpal Singh Gill fdServer = -1;
70*a32d241bSJagpal Singh Gill }
71*a32d241bSJagpal Singh Gill kill(socat_pid, SIGTERM);
72*a32d241bSJagpal Singh Gill }
73*a32d241bSJagpal Singh Gill
SetUp()74*a32d241bSJagpal Singh Gill void SetUp() override
75*a32d241bSJagpal Singh Gill {
76*a32d241bSJagpal Singh Gill ctx.spawn(serverTester->processRequests());
77*a32d241bSJagpal Singh Gill }
78*a32d241bSJagpal Singh Gill
TestHoldingRegisters(uint16_t registerOffset,bool res)79*a32d241bSJagpal Singh Gill auto TestHoldingRegisters(uint16_t registerOffset, bool res)
80*a32d241bSJagpal Singh Gill -> sdbusplus::async::task<void>
81*a32d241bSJagpal Singh Gill {
82*a32d241bSJagpal Singh Gill std::cout << "TestHoldingRegisters() start" << std::endl;
83*a32d241bSJagpal Singh Gill
84*a32d241bSJagpal Singh Gill std::vector<uint16_t> registers(
85*a32d241bSJagpal Singh Gill TestIntf::testSuccessReadHoldingRegisterCount);
86*a32d241bSJagpal Singh Gill
87*a32d241bSJagpal Singh Gill auto ret = co_await modbus->readHoldingRegisters(
88*a32d241bSJagpal Singh Gill TestIntf::testDeviceAddress, registerOffset, registers);
89*a32d241bSJagpal Singh Gill
90*a32d241bSJagpal Singh Gill EXPECT_EQ(ret, res) << "Failed to read holding registers";
91*a32d241bSJagpal Singh Gill
92*a32d241bSJagpal Singh Gill if (!res)
93*a32d241bSJagpal Singh Gill {
94*a32d241bSJagpal Singh Gill co_return;
95*a32d241bSJagpal Singh Gill }
96*a32d241bSJagpal Singh Gill
97*a32d241bSJagpal Singh Gill for (auto i = 0; i < TestIntf::testSuccessReadHoldingRegisterCount; i++)
98*a32d241bSJagpal Singh Gill {
99*a32d241bSJagpal Singh Gill EXPECT_EQ(registers[i],
100*a32d241bSJagpal Singh Gill TestIntf::testSuccessReadHoldingRegisterResponse[i]);
101*a32d241bSJagpal Singh Gill }
102*a32d241bSJagpal Singh Gill
103*a32d241bSJagpal Singh Gill co_return;
104*a32d241bSJagpal Singh Gill }
105*a32d241bSJagpal Singh Gill };
106*a32d241bSJagpal Singh Gill
TEST_F(ModbusTest,TestReadHoldingRegisterSuccess)107*a32d241bSJagpal Singh Gill TEST_F(ModbusTest, TestReadHoldingRegisterSuccess)
108*a32d241bSJagpal Singh Gill {
109*a32d241bSJagpal Singh Gill ctx.spawn(TestHoldingRegisters(
110*a32d241bSJagpal Singh Gill TestIntf::testSuccessReadHoldingRegisterOffset, true));
111*a32d241bSJagpal Singh Gill
112*a32d241bSJagpal Singh Gill ctx.spawn(sdbusplus::async::sleep_for(ctx, 1s) |
113*a32d241bSJagpal Singh Gill sdbusplus::async::execution::then([&]() { ctx.request_stop(); }));
114*a32d241bSJagpal Singh Gill
115*a32d241bSJagpal Singh Gill ctx.run();
116*a32d241bSJagpal Singh Gill }
117*a32d241bSJagpal Singh Gill
TEST_F(ModbusTest,TestReadHoldingRegisterSegmentedSuccess)118*a32d241bSJagpal Singh Gill TEST_F(ModbusTest, TestReadHoldingRegisterSegmentedSuccess)
119*a32d241bSJagpal Singh Gill {
120*a32d241bSJagpal Singh Gill ctx.spawn(TestHoldingRegisters(
121*a32d241bSJagpal Singh Gill TestIntf::testSuccessReadHoldingRegisterSegmentedOffset, true));
122*a32d241bSJagpal Singh Gill
123*a32d241bSJagpal Singh Gill ctx.spawn(sdbusplus::async::sleep_for(ctx, 1s) |
124*a32d241bSJagpal Singh Gill sdbusplus::async::execution::then([&]() { ctx.request_stop(); }));
125*a32d241bSJagpal Singh Gill
126*a32d241bSJagpal Singh Gill ctx.run();
127*a32d241bSJagpal Singh Gill }
128*a32d241bSJagpal Singh Gill
TEST_F(ModbusTest,TestReadHoldingRegisterFailure)129*a32d241bSJagpal Singh Gill TEST_F(ModbusTest, TestReadHoldingRegisterFailure)
130*a32d241bSJagpal Singh Gill {
131*a32d241bSJagpal Singh Gill ctx.spawn(
132*a32d241bSJagpal Singh Gill TestHoldingRegisters(TestIntf::testFailureReadHoldingRegister, false));
133*a32d241bSJagpal Singh Gill
134*a32d241bSJagpal Singh Gill ctx.spawn(sdbusplus::async::sleep_for(ctx, 1s) |
135*a32d241bSJagpal Singh Gill sdbusplus::async::execution::then([&]() { ctx.request_stop(); }));
136*a32d241bSJagpal Singh Gill
137*a32d241bSJagpal Singh Gill ctx.run();
138*a32d241bSJagpal Singh Gill }
139