modbus_rtu_lib: define read holding register

Add the modbus rtu library commands with initial support for read
holding register. Define a base Message classes which all subsequent and
specific request & response messages can inherit from. Also add the
relevant unit testing for the added command set.

Tested:
```
> meson test -C builddir
ninja: Entering directory `/host/repos/Modbus/phosphor-modbus/builddir'
ninja: no work to do.
1/1 test_modbus_commands        OK              0.01s

Ok:                1
Fail:              0

```

Change-Id: I331b0dee66a0829e9352ae0eac8ac82a9150904c
Signed-off-by: Jagpal Singh Gill <paligill@gmail.com>
diff --git a/rtu/modbus/modbus_commands.cpp b/rtu/modbus/modbus_commands.cpp
new file mode 100644
index 0000000..64d541b
--- /dev/null
+++ b/rtu/modbus/modbus_commands.cpp
@@ -0,0 +1,59 @@
+#include "modbus_commands.hpp"
+
+#include "modbus_exception.hpp"
+
+#include <phosphor-logging/lg2.hpp>
+
+namespace phosphor::modbus::rtu
+{
+
+ReadHoldingRegistersRequest::ReadHoldingRegistersRequest(
+    uint8_t deviceAddress, uint16_t registerOffset, uint16_t registerCount) :
+    deviceAddress(deviceAddress), registerOffset(registerOffset),
+    registerCount(registerCount)
+{}
+
+auto ReadHoldingRegistersRequest::encode() -> void
+{
+    *this << deviceAddress << commandCode << registerOffset << registerCount;
+    appendCRC();
+}
+
+ReadHoldingRegistersResponse::ReadHoldingRegistersResponse(
+    uint8_t deviceAddress, std::vector<uint16_t>& registers) :
+    expectedDeviceAddress(deviceAddress), registers(registers)
+{
+    if (registers.empty())
+    {
+        throw std::underflow_error("Response registers are empty");
+    }
+    // addr(1), func(1), bytecount(1), <2 * count regs>, crc(2)
+    len = 5 + (2 * registers.size());
+}
+
+auto Response::decode() -> void
+{
+    validate();
+
+    // Error response is structured as:
+    // addr(1), errorFunctionCode(1), exceptionCode(1)
+    // Where errorFunctionCode is the response function with
+    // MSB set to 1, hence mask of 0x80.
+    bool isError = (len == 3 && (functionCode & 0x80) != 0);
+    if (isError)
+    {
+        throw ModbusException(raw[2]);
+    }
+}
+
+auto ReadHoldingRegistersResponse::decode() -> void
+{
+    Response::decode();
+    uint8_t byteCount, responseCode, deviceAddress;
+    *this >> registers >> byteCount >> responseCode >> deviceAddress;
+    verifyValue("Device Address", deviceAddress, expectedDeviceAddress);
+    verifyValue("Response Function Code", responseCode, expectedCommandCode);
+    verifyValue("Byte Count", byteCount, registers.size() * 2);
+}
+
+} // namespace phosphor::modbus::rtu