xref: /openbmc/phosphor-modbus/tests/test_modbus.cpp (revision a32d241b08af236b5ea1d4e18a390bdc561b435b)
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