xref: /openbmc/phosphor-modbus/tests/test_modbus_commands.cpp (revision 9695bd284570b51677c11529103929c8e51da6b6)
1 #include "modbus/modbus_commands.hpp"
2 #include "modbus/modbus_exception.hpp"
3 
4 #include <cstring>
5 
6 #include <gmock/gmock.h>
7 #include <gtest/gtest.h>
8 
9 namespace RTUIntf = phosphor::modbus::rtu;
10 
11 class ReadHoldingRegistersResponseTest :
12     public RTUIntf::ReadHoldingRegistersResponse
13 {
14   public:
ReadHoldingRegistersResponseTest(uint8_t address,std::vector<uint16_t> & registers)15     ReadHoldingRegistersResponseTest(uint8_t address,
16                                      std::vector<uint16_t>& registers) :
17         RTUIntf::ReadHoldingRegistersResponse(address, registers)
18     {}
19 
20     template <std::size_t Length>
operator =(const std::array<uint8_t,Length> & expectedMessage)21     ReadHoldingRegistersResponseTest& operator=(
22         const std::array<uint8_t, Length>& expectedMessage)
23     {
24         len = Length;
25         std::copy(expectedMessage.begin(), expectedMessage.end(), raw.begin());
26         return *this;
27     }
28 };
29 
30 class ModbusCommandTest : public ::testing::Test
31 {
32   public:
33     ModbusCommandTest() = default;
34 
35     static constexpr auto failureMessageLength = 11;
36 
37     template <typename ExceptionType, std::size_t Length>
TestReadHoldingRegisterResponseFailure(const std::array<uint8_t,Length> & expectedMessage)38     void TestReadHoldingRegisterResponseFailure(
39         const std::array<uint8_t, Length>& expectedMessage)
40     {
41         constexpr uint8_t expectedAddress = 0xa;
42         constexpr size_t expectedRegisterSize = 3;
43         std::vector<uint16_t> registers(expectedRegisterSize);
44         ReadHoldingRegistersResponseTest response(expectedAddress, registers);
45         response = expectedMessage;
46 
47         EXPECT_THROW(response.decode(), ExceptionType);
48     }
49 };
50 
TEST_F(ModbusCommandTest,TestReadHoldingRegistersRequestSucess)51 TEST_F(ModbusCommandTest, TestReadHoldingRegistersRequestSucess)
52 {
53     constexpr size_t expectedLength = 8;
54     constexpr uint8_t expectedAddress = 0x1;
55     constexpr std::array<uint8_t, expectedLength> expectedMessage = {
56         expectedAddress, // addr(1) = 0x01
57         0x03,            // func(1) = 0x03
58         0x12,            // reg_off(2) = 0x1234
59         0x34,
60         0x00,            // reg_cnt(2) = 0x0020,
61         0x20,
62         0x00,            // crc(2) (Pre-computed) = 0xa4
63         0xa4};
64 
65     RTUIntf::ReadHoldingRegistersRequest request(expectedAddress, 0x1234, 0x20);
66     request.encode();
67 
68     std::array<uint8_t, expectedLength> actualMessage;
69     std::memcpy(actualMessage.data(), request.raw.data(), expectedLength);
70 
71     EXPECT_EQ(actualMessage, expectedMessage);
72     EXPECT_EQ(request.address, expectedAddress);
73 }
74 
TEST_F(ModbusCommandTest,TestReadHoldingRegistersResponseSucess)75 TEST_F(ModbusCommandTest, TestReadHoldingRegistersResponseSucess)
76 {
77     constexpr size_t expectedLength = 11;
78     constexpr uint8_t expectedAddress = 0xa;
79     constexpr size_t expectedRegisterSize = 3;
80     constexpr std::array<uint8_t, expectedLength> expectedMessage = {
81         expectedAddress, // addr(1) = 0x0a
82         0x03,            // func(1) = 0x03
83         0x06,            // bytes(1) = 0x06
84         0x11,            // regs(3*2) = 0x1122, 0x3344, 0x5566
85         0x22,
86         0x33,
87         0x44,
88         0x55,
89         0x66,
90         0x59, // crc(2) = 0x5928 (pre-computed)
91         0x28};
92     const std::vector<uint16_t> expectedRegisters{0x1122, 0x3344, 0x5566};
93     std::vector<uint16_t> registers(expectedRegisterSize);
94 
95     RTUIntf::ReadHoldingRegistersResponse response(expectedAddress, registers);
96     EXPECT_EQ(response.len, expectedLength);
97 
98     std::copy(expectedMessage.begin(), expectedMessage.end(),
99               response.raw.begin());
100 
101     EXPECT_EQ(response.len, expectedLength);
102     response.decode();
103     EXPECT_EQ(registers, expectedRegisters);
104 }
105 
TEST_F(ModbusCommandTest,TestReadHoldingRegistersResponseError)106 TEST_F(ModbusCommandTest, TestReadHoldingRegistersResponseError)
107 {
108     constexpr std::array<uint8_t, 5> expectedMessage = {
109         0xa,  // addr(1) = 0x0a
110         0x83, // func(1) = 0x83
111         0x03, // exception code(1) = 0x03
112         0x70, // crc(2) = 0x70f3 (pre-computed)
113         0xf3};
114 
115     TestReadHoldingRegisterResponseFailure<RTUIntf::ModbusException>(
116         expectedMessage);
117 }
118 
TEST_F(ModbusCommandTest,TestReadHoldingRegistersResponseBadAddress)119 TEST_F(ModbusCommandTest, TestReadHoldingRegistersResponseBadAddress)
120 {
121     constexpr std::array<uint8_t, failureMessageLength> expectedMessage = {
122         0x1,  // Bad address(1), should be 0x0a
123         0x03, // func(1) = 0x03
124         0x06, // bytes(1) = 0x06
125         0x11, // regs(3*2) = 0x1122, 0x3344, 0x5566
126         0x22, 0x33, 0x44, 0x55, 0x66,
127         0x2a, // crc(2) = 0x2a18 (pre-computed)
128         0x18};
129 
130     TestReadHoldingRegisterResponseFailure<RTUIntf::ModbusBadResponseException>(
131         expectedMessage);
132 }
133 
TEST_F(ModbusCommandTest,TestReadHoldingRegistersResponseBadCRC)134 TEST_F(ModbusCommandTest, TestReadHoldingRegistersResponseBadCRC)
135 {
136     constexpr std::array<uint8_t, failureMessageLength> expectedMessage = {
137         0xa,  // addr(1) = 0x0a
138         0x03, // func(1) = 0x03
139         0x06, // bytes(1) = 0x06
140         0x11, // regs(3*2) = 0x1122, 0x3344, 0x5566
141         0x22, 0x33, 0x44, 0x55, 0x66,
142         0x59, // Bad crc(2), should be 0x5928
143         0x29};
144 
145     TestReadHoldingRegisterResponseFailure<RTUIntf::ModbusCRCException>(
146         expectedMessage);
147 }
148 
TEST_F(ModbusCommandTest,TestReadHoldingRegistersResponseBadFunctionCode)149 TEST_F(ModbusCommandTest, TestReadHoldingRegistersResponseBadFunctionCode)
150 {
151     constexpr std::array<uint8_t, failureMessageLength> expectedMessage = {
152         0xa,  // addr(1) = 0x0a
153         0x04, // Bad function code(1), should be 0x03
154         0x06, // bytes(1) = 0x06
155         0x11, // regs(3*2) = 0x1122, 0x3344, 0x5566
156         0x22, 0x33, 0x44, 0x55, 0x66,
157         0x18, // crc(2) = 0x18ce (pre-computed)
158         0xce};
159 
160     TestReadHoldingRegisterResponseFailure<RTUIntf::ModbusBadResponseException>(
161         expectedMessage);
162 }
163 
TEST_F(ModbusCommandTest,TestReadHoldingRegistersResponseBadByteCount)164 TEST_F(ModbusCommandTest, TestReadHoldingRegistersResponseBadByteCount)
165 {
166     constexpr std::array<uint8_t, failureMessageLength> expectedMessage = {
167         0xa,  // addr(1) = 0x0a
168         0x03, // func(1) = 0x03
169         0x04, // Bad bytes(1), should be 0x06
170         0x11, // regs(3*2) = 0x1122, 0x3344, 0x5566
171         0x22, 0x33, 0x44, 0x55, 0x66,
172         0x7a, // crc(2) = 0x7ae8 (pre-computed)
173         0xe8};
174 
175     TestReadHoldingRegisterResponseFailure<RTUIntf::ModbusBadResponseException>(
176         expectedMessage);
177 }
178