1*2168bbd0SJagpal Singh Gill #include "modbus/modbus.hpp"
2*2168bbd0SJagpal Singh Gill #include "modbus/modbus_commands.hpp"
3*2168bbd0SJagpal Singh Gill #include "modbus/modbus_message.hpp"
4*2168bbd0SJagpal Singh Gill
5*2168bbd0SJagpal Singh Gill #include <fcntl.h>
6*2168bbd0SJagpal Singh Gill
7*2168bbd0SJagpal Singh Gill #include <sdbusplus/async.hpp>
8*2168bbd0SJagpal Singh Gill
9*2168bbd0SJagpal Singh Gill #include <iostream>
10*2168bbd0SJagpal Singh Gill #include <string>
11*2168bbd0SJagpal Singh Gill
12*2168bbd0SJagpal Singh Gill namespace phosphor::modbus::test
13*2168bbd0SJagpal Singh Gill {
14*2168bbd0SJagpal Singh Gill
15*2168bbd0SJagpal Singh Gill class MessageIntf : public phosphor::modbus::rtu::Message
16*2168bbd0SJagpal Singh Gill {
17*2168bbd0SJagpal Singh Gill friend class TestServer;
18*2168bbd0SJagpal Singh Gill };
19*2168bbd0SJagpal Singh Gill
20*2168bbd0SJagpal Singh Gill class TestServer
21*2168bbd0SJagpal Singh Gill {
22*2168bbd0SJagpal Singh Gill public:
23*2168bbd0SJagpal Singh Gill explicit TestServer(sdbusplus::async::context& ctx, int fd);
24*2168bbd0SJagpal Singh Gill
25*2168bbd0SJagpal Singh Gill private:
26*2168bbd0SJagpal Singh Gill auto processRequests() -> sdbusplus::async::task<void>;
27*2168bbd0SJagpal Singh Gill void processMessage(MessageIntf& request, size_t requestSize,
28*2168bbd0SJagpal Singh Gill MessageIntf& response);
29*2168bbd0SJagpal Singh Gill
30*2168bbd0SJagpal Singh Gill void processReadHoldingRegisters(MessageIntf& request, size_t requestSize,
31*2168bbd0SJagpal Singh Gill MessageIntf& response);
32*2168bbd0SJagpal Singh Gill
33*2168bbd0SJagpal Singh Gill sdbusplus::async::context& ctx;
34*2168bbd0SJagpal Singh Gill int fd;
35*2168bbd0SJagpal Singh Gill sdbusplus::async::fdio fdioInstance;
36*2168bbd0SJagpal Singh Gill };
37*2168bbd0SJagpal Singh Gill
TestServer(sdbusplus::async::context & ctx,int fd)38*2168bbd0SJagpal Singh Gill TestServer::TestServer(sdbusplus::async::context& ctx, int fd) :
39*2168bbd0SJagpal Singh Gill ctx(ctx), fd(fd), fdioInstance(ctx, fd)
40*2168bbd0SJagpal Singh Gill {
41*2168bbd0SJagpal Singh Gill ctx.spawn(processRequests());
42*2168bbd0SJagpal Singh Gill }
43*2168bbd0SJagpal Singh Gill
processRequests()44*2168bbd0SJagpal Singh Gill auto TestServer::processRequests() -> sdbusplus::async::task<void>
45*2168bbd0SJagpal Singh Gill {
46*2168bbd0SJagpal Singh Gill while (!ctx.stop_requested())
47*2168bbd0SJagpal Singh Gill {
48*2168bbd0SJagpal Singh Gill MessageIntf request;
49*2168bbd0SJagpal Singh Gill co_await fdioInstance.next();
50*2168bbd0SJagpal Singh Gill auto ret = read(fd, request.raw.data(), request.raw.size());
51*2168bbd0SJagpal Singh Gill // Request message need to be at least 4 bytes long - address(1),
52*2168bbd0SJagpal Singh Gill // function code(1), ..., CRC(2)
53*2168bbd0SJagpal Singh Gill if (ret < 4)
54*2168bbd0SJagpal Singh Gill {
55*2168bbd0SJagpal Singh Gill std::cerr << "Invalid Server message size:" << ret << ", drop it"
56*2168bbd0SJagpal Singh Gill << std::endl;
57*2168bbd0SJagpal Singh Gill continue;
58*2168bbd0SJagpal Singh Gill }
59*2168bbd0SJagpal Singh Gill
60*2168bbd0SJagpal Singh Gill MessageIntf response;
61*2168bbd0SJagpal Singh Gill processMessage(request, ret, response);
62*2168bbd0SJagpal Singh Gill
63*2168bbd0SJagpal Singh Gill ret = write(fd, response.raw.data(), response.len);
64*2168bbd0SJagpal Singh Gill if (ret < 0)
65*2168bbd0SJagpal Singh Gill {
66*2168bbd0SJagpal Singh Gill std::cerr << "Failed to send response" << std::endl;
67*2168bbd0SJagpal Singh Gill }
68*2168bbd0SJagpal Singh Gill }
69*2168bbd0SJagpal Singh Gill }
70*2168bbd0SJagpal Singh Gill
processMessage(MessageIntf & request,size_t requestSize,MessageIntf & response)71*2168bbd0SJagpal Singh Gill void TestServer::processMessage(MessageIntf& request, size_t requestSize,
72*2168bbd0SJagpal Singh Gill MessageIntf& response)
73*2168bbd0SJagpal Singh Gill {
74*2168bbd0SJagpal Singh Gill constexpr uint8_t readHoldingRegistersFunctionCode = 0x3;
75*2168bbd0SJagpal Singh Gill
76*2168bbd0SJagpal Singh Gill switch (request.functionCode)
77*2168bbd0SJagpal Singh Gill {
78*2168bbd0SJagpal Singh Gill case readHoldingRegistersFunctionCode:
79*2168bbd0SJagpal Singh Gill processReadHoldingRegisters(request, requestSize, response);
80*2168bbd0SJagpal Singh Gill break;
81*2168bbd0SJagpal Singh Gill default:
82*2168bbd0SJagpal Singh Gill std::cerr << "Server received unknown request" << std::endl;
83*2168bbd0SJagpal Singh Gill break;
84*2168bbd0SJagpal Singh Gill }
85*2168bbd0SJagpal Singh Gill }
86*2168bbd0SJagpal Singh Gill
processReadHoldingRegisters(MessageIntf & request,size_t requestSize,MessageIntf & response)87*2168bbd0SJagpal Singh Gill void TestServer::processReadHoldingRegisters(
88*2168bbd0SJagpal Singh Gill MessageIntf& request, size_t requestSize, MessageIntf& response)
89*2168bbd0SJagpal Singh Gill {
90*2168bbd0SJagpal Singh Gill uint16_t registerOffset = request.raw[2] << 8 | request.raw[3];
91*2168bbd0SJagpal Singh Gill uint16_t registerCount = request.raw[4] << 8 | request.raw[5];
92*2168bbd0SJagpal Singh Gill
93*2168bbd0SJagpal Singh Gill std::cout << "Received readHoldingRegisters request with size:"
94*2168bbd0SJagpal Singh Gill << requestSize << ", registerOffset:" << registerOffset
95*2168bbd0SJagpal Singh Gill << ", registerCount:" << registerCount << std::endl;
96*2168bbd0SJagpal Singh Gill
97*2168bbd0SJagpal Singh Gill response << request.raw[0] << request.raw[1] << uint8_t(2 * registerCount);
98*2168bbd0SJagpal Singh Gill for (int i = 0; i < registerCount; i++)
99*2168bbd0SJagpal Singh Gill {
100*2168bbd0SJagpal Singh Gill constexpr uint16_t readHoldingRegisterResponse = 0x4142;
101*2168bbd0SJagpal Singh Gill response << uint16_t(readHoldingRegisterResponse);
102*2168bbd0SJagpal Singh Gill }
103*2168bbd0SJagpal Singh Gill response.appendCRC();
104*2168bbd0SJagpal Singh Gill }
105*2168bbd0SJagpal Singh Gill
106*2168bbd0SJagpal Singh Gill } // namespace phosphor::modbus::test
107*2168bbd0SJagpal Singh Gill
main(int argc,char * argv[])108*2168bbd0SJagpal Singh Gill int main(int argc, char* argv[])
109*2168bbd0SJagpal Singh Gill {
110*2168bbd0SJagpal Singh Gill if (argc < 2)
111*2168bbd0SJagpal Singh Gill {
112*2168bbd0SJagpal Singh Gill std::cerr << "Usage: " << argv[0] << " <integer_value>" << std::endl;
113*2168bbd0SJagpal Singh Gill return 1;
114*2168bbd0SJagpal Singh Gill }
115*2168bbd0SJagpal Singh Gill
116*2168bbd0SJagpal Singh Gill int interfaceValue = 1;
117*2168bbd0SJagpal Singh Gill try
118*2168bbd0SJagpal Singh Gill {
119*2168bbd0SJagpal Singh Gill interfaceValue = std::stoi(argv[1]);
120*2168bbd0SJagpal Singh Gill }
121*2168bbd0SJagpal Singh Gill catch (const std::invalid_argument& e)
122*2168bbd0SJagpal Singh Gill {
123*2168bbd0SJagpal Singh Gill std::cerr << "Invalid argument: " << e.what() << std::endl;
124*2168bbd0SJagpal Singh Gill return 1;
125*2168bbd0SJagpal Singh Gill }
126*2168bbd0SJagpal Singh Gill catch (const std::out_of_range& e)
127*2168bbd0SJagpal Singh Gill {
128*2168bbd0SJagpal Singh Gill std::cerr << "Argument out of range: " << e.what() << std::endl;
129*2168bbd0SJagpal Singh Gill return 1;
130*2168bbd0SJagpal Singh Gill }
131*2168bbd0SJagpal Singh Gill
132*2168bbd0SJagpal Singh Gill using TestServerIntf = phosphor::modbus::test::TestServer;
133*2168bbd0SJagpal Singh Gill std::string devicePathStr =
134*2168bbd0SJagpal Singh Gill std::string("/dev/ttyV") + std::to_string(interfaceValue);
135*2168bbd0SJagpal Singh Gill const char* serverDevicePath = devicePathStr.c_str();
136*2168bbd0SJagpal Singh Gill std::cout << "Starting at device path" << serverDevicePath << std::endl;
137*2168bbd0SJagpal Singh Gill constexpr auto path = "/xyz/openbmc_project";
138*2168bbd0SJagpal Singh Gill constexpr auto serviceName = "xyz.openbmc_project.ModbusRTUTestServer";
139*2168bbd0SJagpal Singh Gill sdbusplus::async::context ctx;
140*2168bbd0SJagpal Singh Gill
141*2168bbd0SJagpal Singh Gill auto fdServer = open(serverDevicePath, O_RDWR | O_NOCTTY | O_NONBLOCK);
142*2168bbd0SJagpal Singh Gill if (fdServer == -1)
143*2168bbd0SJagpal Singh Gill {
144*2168bbd0SJagpal Singh Gill std::cerr << "Failed to open serial port " << serverDevicePath
145*2168bbd0SJagpal Singh Gill << " with error: " << strerror(errno) << std::endl;
146*2168bbd0SJagpal Singh Gill return 1;
147*2168bbd0SJagpal Singh Gill }
148*2168bbd0SJagpal Singh Gill
149*2168bbd0SJagpal Singh Gill std::cout << "Creating Modbus RTU test server at " << path << std::endl;
150*2168bbd0SJagpal Singh Gill TestServerIntf server{ctx, fdServer};
151*2168bbd0SJagpal Singh Gill
152*2168bbd0SJagpal Singh Gill ctx.request_name(serviceName);
153*2168bbd0SJagpal Singh Gill
154*2168bbd0SJagpal Singh Gill ctx.run();
155*2168bbd0SJagpal Singh Gill return 0;
156*2168bbd0SJagpal Singh Gill }
157