rtu: add serial port interface
Add the interface classes for serial port with Port Factory classes to
make the code extensible for future in case a new hardware port type is
introduced. This also makes the unit testing easy by creating a Mock
Port using socat.
Tested:
```
meson test -C builddir test_port
ninja: Entering directory `/host/repos/Modbus/phosphor-modbus/builddir'
ninja: no work to do.
1/1 test_port OK 5.02s
Ok: 1
Fail: 0
```
Change-Id: Ic6bd982abf1ae993f76c39e3503d3a0402a692fe
Signed-off-by: Jagpal Singh Gill <paligill@gmail.com>
diff --git a/rtu/port/base_port.cpp b/rtu/port/base_port.cpp
new file mode 100644
index 0000000..42cef57
--- /dev/null
+++ b/rtu/port/base_port.cpp
@@ -0,0 +1,72 @@
+#include "base_port.hpp"
+
+#include "common/entity_manager_interface.hpp"
+
+#include <fcntl.h>
+
+#include <phosphor-logging/lg2.hpp>
+#include <xyz/openbmc_project/Configuration/USBPort/client.hpp>
+
+#include <filesystem>
+#include <format>
+#include <optional>
+#include <regex>
+
+namespace phosphor::modbus::rtu::port
+{
+
+PHOSPHOR_LOG2_USING;
+
+BasePort::BasePort(sdbusplus::async::context& ctx, const config::Config& config,
+ const std::string& devicePath) :
+ name(config.name), mutex(config.name)
+{
+ fd = open(devicePath.c_str(), O_RDWR | O_NOCTTY);
+ if (fd == -1)
+ {
+ throw("Failed to open serial port " + devicePath +
+ " with error: " + strerror(errno));
+ }
+
+ modbus =
+ std::make_unique<ModbusIntf>(ctx, fd, config.baudRate, config.rtsDelay);
+ if (!modbus)
+ {
+ throw std::runtime_error("Failed to create Modbus interface");
+ }
+
+ info("Serial port {NAME} created successfully", "NAME", config.name);
+}
+
+auto BasePort::readHoldingRegisters(
+ uint8_t deviceAddress, uint16_t registerOffset, uint32_t baudRate,
+ Parity parity, std::vector<uint16_t>& registers)
+ -> sdbusplus::async::task<bool>
+{
+ sdbusplus::async::lock_guard lg{mutex};
+ co_await lg.lock();
+
+ if (!modbus->setProperties(baudRate, parity))
+ {
+ error("Failed to set serial port properties");
+ co_return false;
+ }
+
+ debug(
+ "Reading holding registers from device {ADDRESS} {PORT} at offset {OFFSET}",
+ "ADDRESS", deviceAddress, "PORT", name, "OFFSET", registerOffset);
+
+ auto ret = co_await modbus->readHoldingRegisters(deviceAddress,
+ registerOffset, registers);
+ if (!ret)
+ {
+ error(
+ "Failed to read holding registers from device {ADDRESS} {PORT} at offset "
+ "{OFFSET}",
+ "ADDRESS", deviceAddress, "PORT", name, "OFFSET", registerOffset);
+ }
+
+ co_return ret;
+}
+
+} // namespace phosphor::modbus::rtu::port