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