blob: 5c74c30cce90821916bd9b815ad116e0bc1c9d06 [file] [log] [blame]
Jagpal Singh Gillb62e3df2025-10-22 18:10:40 -07001#include "common/entity_manager_interface.hpp"
Jagpal Singh Gill7f9d41d2025-10-16 09:42:18 -07002#include "modbus_server_tester.hpp"
Jagpal Singh Gillb62e3df2025-10-22 18:10:40 -07003#include "port/port_factory.hpp"
Jagpal Singh Gill2fa10f42025-12-08 10:35:14 -08004#include "test_base.hpp"
Jagpal Singh Gill7f9d41d2025-10-16 09:42:18 -07005
Jagpal Singh Gillb62e3df2025-10-22 18:10:40 -07006#include <xyz/openbmc_project/Configuration/USBPort/aserver.hpp>
7#include <xyz/openbmc_project/Inventory/Item/client.hpp>
8
Jagpal Singh Gill7f9d41d2025-10-16 09:42:18 -07009#include <gtest/gtest.h>
10
11using namespace std::literals;
12
Jagpal Singh Gillb62e3df2025-10-22 18:10:40 -070013class PortTest;
14
Jagpal Singh Gill7f9d41d2025-10-16 09:42:18 -070015namespace PortIntf = phosphor::modbus::rtu::port;
16namespace PortConfigIntf = PortIntf::config;
17namespace RTUIntf = phosphor::modbus::rtu;
Jagpal Singh Gillb62e3df2025-10-22 18:10:40 -070018using PortFactoryIntf = PortIntf::PortFactory;
19using USBPortConfigServerIntf =
20 sdbusplus::aserver::xyz::openbmc_project::configuration::USBPort<PortTest>;
Jagpal Singh Gill7f9d41d2025-10-16 09:42:18 -070021
22struct properties_t
23{
24 std::string name = {};
25 std::string mode = {};
26 uint64_t baud_rate = {};
27 uint64_t rts_delay = {};
28};
29
30class MockPort : public PortIntf::BasePort
31{
32 public:
33 MockPort(sdbusplus::async::context& ctx,
34 const PortConfigIntf::Config& config,
35 const std::string& devicePath) : BasePort(ctx, config, devicePath)
36 {}
37};
38
Jagpal Singh Gill2fa10f42025-12-08 10:35:14 -080039class PortTest : public BaseTest
Jagpal Singh Gill7f9d41d2025-10-16 09:42:18 -070040{
41 public:
42 static constexpr properties_t properties = {"TestPort", "RS485", 115200, 1};
Jagpal Singh Gill2fa10f42025-12-08 10:35:14 -080043 static constexpr auto clientDevicePath = "/tmp/ttyPortV0";
44 static constexpr auto serverDevicePath = "/tmp/ttyPortV1";
45 static constexpr auto serviceName = "xyz.openbmc_project.TestModbusPort";
Jagpal Singh Gillb62e3df2025-10-22 18:10:40 -070046 bool getPortConfigPassed = false;
Jagpal Singh Gill7f9d41d2025-10-16 09:42:18 -070047
Jagpal Singh Gill2fa10f42025-12-08 10:35:14 -080048 PortTest() : BaseTest(clientDevicePath, serverDevicePath, serviceName) {}
Jagpal Singh Gill7f9d41d2025-10-16 09:42:18 -070049
Jagpal Singh Gillb62e3df2025-10-22 18:10:40 -070050 void SetUp() override
51 {
52 getPortConfigPassed = false;
Jagpal Singh Gill2fa10f42025-12-08 10:35:14 -080053 BaseTest::SetUp();
Jagpal Singh Gillb62e3df2025-10-22 18:10:40 -070054 }
55
Jagpal Singh Gill7f9d41d2025-10-16 09:42:18 -070056 auto TestHoldingRegisters(PortConfigIntf::Config& config, MockPort& port,
57 uint16_t registerOffset, bool res)
58 -> sdbusplus::async::task<void>
59 {
60 std::vector<uint16_t> registers(
61 TestIntf::testSuccessReadHoldingRegisterCount);
62
63 auto ret = co_await port.readHoldingRegisters(
64 TestIntf::testDeviceAddress, registerOffset, config.baudRate,
65 RTUIntf::Parity::none, registers);
66
67 EXPECT_EQ(ret, res) << "Failed to read holding registers";
68
69 if (!res)
70 {
71 co_return;
72 }
73
74 for (auto i = 0; i < TestIntf::testSuccessReadHoldingRegisterCount; i++)
75 {
76 EXPECT_EQ(registers[i],
77 TestIntf::testSuccessReadHoldingRegisterResponse[i]);
78 }
79
80 co_return;
81 }
Jagpal Singh Gillb62e3df2025-10-22 18:10:40 -070082
83 template <typename Config, typename Properties>
84 static inline void VerifyConfig(const Config& config,
85 const Properties& property)
86 {
87 EXPECT_EQ(config, property);
88 }
89
90 auto TestGetUSBPortConfig(
91 const USBPortConfigServerIntf::properties_t properties, bool shouldPass)
92 -> sdbusplus::async::task<void>
93 {
94 static constexpr auto objectPath =
95 "/xyz/openbmc_project/inventory/system/board/Ventura_Modbus/DevTTYUSB0";
96
97 auto configServer = std::make_unique<USBPortConfigServerIntf>(
98 ctx, objectPath, properties);
99
100 auto config = co_await PortFactoryIntf::getConfig(
101 ctx, std::string(objectPath), USBPortConfigServerIntf::interface);
102
103 if (!shouldPass)
104 {
105 VerifyConfig(config, nullptr);
106 co_return;
107 }
108
109 VerifyConfig(config->name, properties.name);
110 VerifyConfig(config->portMode, PortConfigIntf::PortMode::rs485);
111 VerifyConfig(config->baudRate, properties.baud_rate);
112 VerifyConfig(config->rtsDelay, properties.rts_delay);
113
114 getPortConfigPassed = true;
115
116 co_return;
117 }
Jagpal Singh Gill7f9d41d2025-10-16 09:42:18 -0700118};
119
120TEST_F(PortTest, TestUpdateConfig)
121{
122 PortConfigIntf::Config config = {};
123 auto res = PortConfigIntf::updateBaseConfig(config, properties);
124 EXPECT_TRUE(res) << "Failed to update config";
125
126 EXPECT_EQ(config.name, properties.name);
127 EXPECT_EQ(config.portMode, PortConfigIntf::PortMode::rs485);
128 EXPECT_EQ(config.baudRate, properties.baud_rate);
129 EXPECT_EQ(config.rtsDelay, properties.rts_delay);
130}
131
Jagpal Singh Gillb62e3df2025-10-22 18:10:40 -0700132TEST_F(PortTest, TestGetUSBPortConfigSucess)
133{
134 using InventoryIntf =
135 sdbusplus::client::xyz::openbmc_project::inventory::Item<>;
136 sdbusplus::server::manager_t manager{ctx, InventoryIntf::namespace_path};
137
138 const USBPortConfigServerIntf::properties_t properties = {
139 .type = "USBPort",
140 .name = "USBPort1",
141 .device_address = "0xa",
142 .device_interface = 1,
143 .port = 1,
144 .mode = "RS485",
145 .baud_rate = 115200,
146 .rts_delay = 100};
147
148 ctx.spawn(TestGetUSBPortConfig(properties, true));
149
150 ctx.spawn(sdbusplus::async::sleep_for(ctx, 1s) |
151 sdbusplus::async::execution::then([&]() { ctx.request_stop(); }));
152
153 ctx.request_name(entity_manager::EntityManagerInterface::serviceName);
154 ctx.run();
155
156 EXPECT_EQ(getPortConfigPassed, true);
157}
158
159TEST_F(PortTest, TestGetUSBPortConfigFailureForInvalidPortMode)
160{
161 using InventoryIntf =
162 sdbusplus::client::xyz::openbmc_project::inventory::Item<>;
163 sdbusplus::server::manager_t manager{ctx, InventoryIntf::namespace_path};
164
165 const USBPortConfigServerIntf::properties_t properties = {
166 .type = "USBPort",
167 .name = "USBPort1",
168 .device_address = "0xa",
169 .device_interface = 1,
170 .port = 1,
171 .mode = "RSXXX", // Invalid port mode
172 .baud_rate = 115200,
173 .rts_delay = 100};
174
175 ctx.spawn(TestGetUSBPortConfig(properties, false));
176
177 ctx.spawn(sdbusplus::async::sleep_for(ctx, 1s) |
178 sdbusplus::async::execution::then([&]() { ctx.request_stop(); }));
179
180 ctx.request_name(entity_manager::EntityManagerInterface::serviceName);
181 ctx.run();
182
183 EXPECT_EQ(getPortConfigPassed, false);
184}
185
Jagpal Singh Gill7f9d41d2025-10-16 09:42:18 -0700186TEST_F(PortTest, TestReadHoldingRegisterSuccess)
187{
188 PortConfigIntf::Config config = {};
189 auto res = PortConfigIntf::updateBaseConfig(config, properties);
190 EXPECT_TRUE(res) << "Failed to update config";
191
192 MockPort port(ctx, config, clientDevicePath);
193
Jagpal Singh Gill7f9d41d2025-10-16 09:42:18 -0700194 ctx.spawn(TestHoldingRegisters(
195 config, port, TestIntf::testSuccessReadHoldingRegisterOffset, true));
196
197 ctx.spawn(sdbusplus::async::sleep_for(ctx, 1s) |
198 sdbusplus::async::execution::then([&]() { ctx.request_stop(); }));
199
200 ctx.run();
201}
202
203TEST_F(PortTest, TestReadHoldingRegisterFailure)
204{
205 PortConfigIntf::Config config = {};
206 auto res = PortConfigIntf::updateBaseConfig(config, properties);
207 EXPECT_TRUE(res) << "Failed to update config";
208
209 MockPort port(ctx, config, clientDevicePath);
210
Jagpal Singh Gill7f9d41d2025-10-16 09:42:18 -0700211 ctx.spawn(TestHoldingRegisters(
212 config, port, TestIntf::testFailureReadHoldingRegister, false));
213
214 ctx.spawn(sdbusplus::async::sleep_for(ctx, 1s) |
215 sdbusplus::async::execution::then([&]() { ctx.request_stop(); }));
216
217 ctx.run();
218}