#include "modbus/modbus_commands.hpp" #include "modbus/modbus_exception.hpp" #include #include #include namespace RTUIntf = phosphor::modbus::rtu; class ReadHoldingRegistersResponseTest : public RTUIntf::ReadHoldingRegistersResponse { public: ReadHoldingRegistersResponseTest(uint8_t address, std::vector& registers) : RTUIntf::ReadHoldingRegistersResponse(address, registers) {} template ReadHoldingRegistersResponseTest& operator=( const std::array& expectedMessage) { len = Length; std::copy(expectedMessage.begin(), expectedMessage.end(), raw.begin()); return *this; } }; class ModbusCommandTest : public ::testing::Test { public: ModbusCommandTest() = default; static constexpr auto failureMessageLength = 11; template void TestReadHoldingRegisterResponseFailure( const std::array& expectedMessage) { constexpr uint8_t expectedAddress = 0xa; constexpr size_t expectedRegisterSize = 3; std::vector registers(expectedRegisterSize); ReadHoldingRegistersResponseTest response(expectedAddress, registers); response = expectedMessage; EXPECT_THROW(response.decode(), ExceptionType); } }; TEST_F(ModbusCommandTest, TestReadHoldingRegistersRequestSucess) { constexpr size_t expectedLength = 8; constexpr uint8_t expectedAddress = 0x1; constexpr std::array expectedMessage = { expectedAddress, // addr(1) = 0x01 0x03, // func(1) = 0x03 0x12, // reg_off(2) = 0x1234 0x34, 0x00, // reg_cnt(2) = 0x0020, 0x20, 0x00, // crc(2) (Pre-computed) = 0xa4 0xa4}; RTUIntf::ReadHoldingRegistersRequest request(expectedAddress, 0x1234, 0x20); request.encode(); std::array actualMessage; std::memcpy(actualMessage.data(), request.raw.data(), expectedLength); EXPECT_EQ(actualMessage, expectedMessage); EXPECT_EQ(request.address, expectedAddress); } TEST_F(ModbusCommandTest, TestReadHoldingRegistersResponseSucess) { constexpr size_t expectedLength = 11; constexpr uint8_t expectedAddress = 0xa; constexpr size_t expectedRegisterSize = 3; constexpr std::array expectedMessage = { expectedAddress, // addr(1) = 0x0a 0x03, // func(1) = 0x03 0x06, // bytes(1) = 0x06 0x11, // regs(3*2) = 0x1122, 0x3344, 0x5566 0x22, 0x33, 0x44, 0x55, 0x66, 0x59, // crc(2) = 0x5928 (pre-computed) 0x28}; const std::vector expectedRegisters{0x1122, 0x3344, 0x5566}; std::vector registers(expectedRegisterSize); RTUIntf::ReadHoldingRegistersResponse response(expectedAddress, registers); EXPECT_EQ(response.len, expectedLength); std::copy(expectedMessage.begin(), expectedMessage.end(), response.raw.begin()); EXPECT_EQ(response.len, expectedLength); response.decode(); EXPECT_EQ(registers, expectedRegisters); } TEST_F(ModbusCommandTest, TestReadHoldingRegistersResponseError) { constexpr std::array expectedMessage = { 0xa, // addr(1) = 0x0a 0x83, // func(1) = 0x83 0x03, // exception code(1) = 0x03 0x70, // crc(2) = 0x70f3 (pre-computed) 0xf3}; TestReadHoldingRegisterResponseFailure( expectedMessage); } TEST_F(ModbusCommandTest, TestReadHoldingRegistersResponseBadAddress) { constexpr std::array expectedMessage = { 0x1, // Bad address(1), should be 0x0a 0x03, // func(1) = 0x03 0x06, // bytes(1) = 0x06 0x11, // regs(3*2) = 0x1122, 0x3344, 0x5566 0x22, 0x33, 0x44, 0x55, 0x66, 0x2a, // crc(2) = 0x2a18 (pre-computed) 0x18}; TestReadHoldingRegisterResponseFailure( expectedMessage); } TEST_F(ModbusCommandTest, TestReadHoldingRegistersResponseBadCRC) { constexpr std::array expectedMessage = { 0xa, // addr(1) = 0x0a 0x03, // func(1) = 0x03 0x06, // bytes(1) = 0x06 0x11, // regs(3*2) = 0x1122, 0x3344, 0x5566 0x22, 0x33, 0x44, 0x55, 0x66, 0x59, // Bad crc(2), should be 0x5928 0x29}; TestReadHoldingRegisterResponseFailure( expectedMessage); } TEST_F(ModbusCommandTest, TestReadHoldingRegistersResponseBadFunctionCode) { constexpr std::array expectedMessage = { 0xa, // addr(1) = 0x0a 0x04, // Bad function code(1), should be 0x03 0x06, // bytes(1) = 0x06 0x11, // regs(3*2) = 0x1122, 0x3344, 0x5566 0x22, 0x33, 0x44, 0x55, 0x66, 0x18, // crc(2) = 0x18ce (pre-computed) 0xce}; TestReadHoldingRegisterResponseFailure( expectedMessage); } TEST_F(ModbusCommandTest, TestReadHoldingRegistersResponseBadByteCount) { constexpr std::array expectedMessage = { 0xa, // addr(1) = 0x0a 0x03, // func(1) = 0x03 0x04, // Bad bytes(1), should be 0x06 0x11, // regs(3*2) = 0x1122, 0x3344, 0x5566 0x22, 0x33, 0x44, 0x55, 0x66, 0x7a, // crc(2) = 0x7ae8 (pre-computed) 0xe8}; TestReadHoldingRegisterResponseFailure( expectedMessage); }