rtu: implement modbus rtu inventory source service

Implement phosphor-modbus-rtu inventory source service based on [1].

[1]: https://gerrit.openbmc.org/c/openbmc/docs/+/77318

Tested: Unit test passes and tested on qemu with simulated modbus
server.
```
root@bmc:~# busctl tree xyz.openbmc_project.ModbusRTU
└─ /xyz
  └─ /xyz/openbmc_project
    └─ /xyz/openbmc_project/inventory_source
      └─ /xyz/openbmc_project/inventory_source/modbus
        ├─ /xyz/openbmc_project/inventory_source/modbus/Heat_Exchanger_12_DevTTYUSB0
        ├─ /xyz/openbmc_project/inventory_source/modbus/Heat_Exchanger_12_DevTTYUSB1
        ├─ /xyz/openbmc_project/inventory_source/modbus/Reservoir_Pumping_Unit_12_DevTTYUSB0
        └─ /xyz/openbmc_project/inventory_source/modbus/Reservoir_Pumping_Unit_12_DevTTYUSB1
root@bmc:~# busctl tree xyz.openbmc_project.EntityManager
└─ /xyz
  └─ /xyz/openbmc_project
    ├─ /xyz/openbmc_project/EntityManager
    └─ /xyz/openbmc_project/inventory
      └─ /xyz/openbmc_project/inventory/system
        ├─ /xyz/openbmc_project/inventory/system/board
        │ └─ /xyz/openbmc_project/inventory/system/board/Ventura_Modbus
        │   ├─ /xyz/openbmc_project/inventory/system/board/Ventura_Modbus/DevTTYUSB0
        │   ├─ /xyz/openbmc_project/inventory/system/board/Ventura_Modbus/DevTTYUSB1
        │   ├─ /xyz/openbmc_project/inventory/system/board/Ventura_Modbus/Heat_Exchanger
        │   └─ /xyz/openbmc_project/inventory/system/board/Ventura_Modbus/Reservoir_Pumping_Unit
        └─ /xyz/openbmc_project/inventory/system/chassis
          ├─ /xyz/openbmc_project/inventory/system/chassis/Heat_Exchanger_12_DevTTYUSB0
          ├─ /xyz/openbmc_project/inventory/system/chassis/Heat_Exchanger_12_DevTTYUSB1
          ├─ /xyz/openbmc_project/inventory/system/chassis/Reservoir_Pumping_Unit_12_DevTTYUSB0
          └─ /xyz/openbmc_project/inventory/system/chassis/Reservoir_Pumping_Unit_12_DevTTYUSB1

root@bmc:~# busctl introspect xyz.openbmc_project.EntityManager /xyz/openbmc_project/inventory/system/chassis/Heat_Exchanger_12_DevTTYUSB0
NAME                                          TYPE      SIGNATURE RESULT/VALUE                             FLAGS
org.freedesktop.DBus.Introspectable           interface -         -                                        -
.Introspect                                   method    -         s                                        -
org.freedesktop.DBus.Peer                     interface -         -                                        -
.GetMachineId                                 method    -         s                                        -
.Ping                                         method    -         -                                        -
org.freedesktop.DBus.Properties               interface -         -                                        -
.Get                                          method    ss        v                                        -
.GetAll                                       method    s         a{sv}                                    -
.Set                                          method    ssv       -                                        -
.PropertiesChanged                            signal    sa{sv}as  -                                        -
xyz.openbmc_project.AddObject                 interface -         -                                        -
.AddObject                                    method    a{sv}     -                                        -
xyz.openbmc_project.Inventory.Decorator.Asset interface -         -                                        -
.BuildDate                                    property  s         "Unknown"                                emits-change
.Manufacturer                                 property  s         "Unknown"                                emits-change
.Model                                        property  s         "Unknown"                                emits-change
.PartNumber                                   property  s         "Unknown"                                emits-change
.SerialNumber                                 property  s         "Unknown"                                emits-change
.SparePartNumber                              property  s         "ABABABAB"                               emits-change
xyz.openbmc_project.Inventory.Item.Chassis    interface -         -                                        -
.Name                                         property  s         "Heat Exchanger 12 DevTTYUSB0"           emits-change
.Probe                                        property  s         "xyz.openbmc_project.Inventory.Source.M… emits-change
.Type                                         property  s         "Chassis"                                emits-change
root@bmc:~# busctl introspect xyz.openbmc_project.EntityManager /xyz/openbmc_project/inventory/system/chassis/Heat_Exchanger_12_DevTTYUSB1
NAME                                          TYPE      SIGNATURE RESULT/VALUE                             FLAGS
org.freedesktop.DBus.Introspectable           interface -         -                                        -
.Introspect                                   method    -         s                                        -
org.freedesktop.DBus.Peer                     interface -         -                                        -
.GetMachineId                                 method    -         s                                        -
.Ping                                         method    -         -                                        -
org.freedesktop.DBus.Properties               interface -         -                                        -
.Get                                          method    ss        v                                        -
.GetAll                                       method    s         a{sv}                                    -
.Set                                          method    ssv       -                                        -
.PropertiesChanged                            signal    sa{sv}as  -                                        -
xyz.openbmc_project.AddObject                 interface -         -                                        -
.AddObject                                    method    a{sv}     -                                        -
xyz.openbmc_project.Inventory.Decorator.Asset interface -         -                                        -
.BuildDate                                    property  s         "Unknown"                                emits-change
.Manufacturer                                 property  s         "Unknown"                                emits-change
.Model                                        property  s         "Unknown"                                emits-change
.PartNumber                                   property  s         "Unknown"                                emits-change
.SerialNumber                                 property  s         "Unknown"                                emits-change
.SparePartNumber                              property  s         "ABABABAB"                               emits-change
xyz.openbmc_project.Inventory.Item.Chassis    interface -         -                                        -
.Name                                         property  s         "Heat Exchanger 12 DevTTYUSB1"           emits-change
.Probe                                        property  s         "xyz.openbmc_project.Inventory.Source.M… emits-change
.Type                                         property  s         "Chassis"                                emits-change

root@bmc:~# busctl introspect xyz.openbmc_project.EntityManager /xyz/openbmc_project/inventory/system/chassis/Reservoir_Pumping_Unit_12_DevTTYUSB0
NAME                                          TYPE      SIGNATURE RESULT/VALUE                             FLAGS
org.freedesktop.DBus.Introspectable           interface -         -                                        -
.Introspect                                   method    -         s                                        -
org.freedesktop.DBus.Peer                     interface -         -                                        -
.GetMachineId                                 method    -         s                                        -
.Ping                                         method    -         -                                        -
org.freedesktop.DBus.Properties               interface -         -                                        -
.Get                                          method    ss        v                                        -
.GetAll                                       method    s         a{sv}                                    -
.Set                                          method    ssv       -                                        -
.PropertiesChanged                            signal    sa{sv}as  -                                        -
xyz.openbmc_project.AddObject                 interface -         -                                        -
.AddObject                                    method    a{sv}     -                                        -
xyz.openbmc_project.Inventory.Decorator.Asset interface -         -                                        -
.BuildDate                                    property  s         "ABABABAB"                               emits-change
.Manufacturer                                 property  s         "Unknown"                                emits-change
.Model                                        property  s         "ABABABABABABABAB"                       emits-change
.PartNumber                                   property  s         "Unknown"                                emits-change
.SerialNumber                                 property  s         "ABABABABABABABAB"                       emits-change
.SparePartNumber                              property  s         "ABABABAB"                               emits-change
xyz.openbmc_project.Inventory.Item.Chassis    interface -         -                                        -
.Name                                         property  s         "Reservoir Pumping Unit 12 DevTTYUSB0"   emits-change
.Probe                                        property  s         "xyz.openbmc_project.Inventory.Source.M… emits-change
.Type                                         property  s         "Chassis"                                emits-change
root@bmc:~# busctl introspect xyz.openbmc_project.EntityManager /xyz/openbmc_project/inventory/system/chassis/Reservoir_Pumping_Unit_12_DevTTYUSB1
NAME                                          TYPE      SIGNATURE RESULT/VALUE                             FLAGS
org.freedesktop.DBus.Introspectable           interface -         -                                        -
.Introspect                                   method    -         s                                        -
org.freedesktop.DBus.Peer                     interface -         -                                        -
.GetMachineId                                 method    -         s                                        -
.Ping                                         method    -         -                                        -
org.freedesktop.DBus.Properties               interface -         -                                        -
.Get                                          method    ss        v                                        -
.GetAll                                       method    s         a{sv}                                    -
.Set                                          method    ssv       -                                        -
.PropertiesChanged                            signal    sa{sv}as  -                                        -
xyz.openbmc_project.AddObject                 interface -         -                                        -
.AddObject                                    method    a{sv}     -                                        -
xyz.openbmc_project.Inventory.Decorator.Asset interface -         -                                        -
.BuildDate                                    property  s         "ABABABAB"                               emits-change
.Manufacturer                                 property  s         "Unknown"                                emits-change
.Model                                        property  s         "ABABABABABABABAB"                       emits-change
.PartNumber                                   property  s         "Unknown"                                emits-change
.SerialNumber                                 property  s         "ABABABABABABABAB"                       emits-change
.SparePartNumber                              property  s         "ABABABAB"                               emits-change
xyz.openbmc_project.Inventory.Item.Chassis    interface -         -                                        -
.Name                                         property  s         "Reservoir Pumping Unit 12 DevTTYUSB1"   emits-change
.Probe                                        property  s         "xyz.openbmc_project.Inventory.Source.M… emits-change
.Type                                         property  s         "Chassis"                                emits-change
```

Change-Id: Ic0ea739de3833044c95da8164be1e2f3f8e6a063
Signed-off-by: Jagpal Singh Gill <paligill@gmail.com>
diff --git a/rtu/device_manager.cpp b/rtu/device_manager.cpp
new file mode 100644
index 0000000..6d2fbd6
--- /dev/null
+++ b/rtu/device_manager.cpp
@@ -0,0 +1,126 @@
+#include "device_manager.hpp"
+
+#include "port/port_factory.hpp"
+
+#include <phosphor-logging/lg2.hpp>
+#include <sdbusplus/async.hpp>
+#include <sdbusplus/server/manager.hpp>
+#include <xyz/openbmc_project/Configuration/ModbusRTUDetect/client.hpp>
+
+PHOSPHOR_LOG2_USING;
+
+namespace phosphor::modbus::rtu
+{
+
+using ModbusRTUDetectIntf =
+    sdbusplus::client::xyz::openbmc_project::configuration::ModbusRTUDetect<>;
+
+static entity_manager::interface_list_t getInterfaces()
+{
+    entity_manager::interface_list_t interfaces;
+
+    auto portInterfaces = PortIntf::PortFactory::getInterfaces();
+    interfaces.insert(interfaces.end(), portInterfaces.begin(),
+                      portInterfaces.end());
+    interfaces.emplace_back(ModbusRTUDetectIntf::interface);
+
+    return interfaces;
+}
+
+DeviceManager::DeviceManager(sdbusplus::async::context& ctx) :
+    ctx(ctx),
+    entityManager(ctx, getInterfaces(),
+                  std::bind_front(&DeviceManager::processConfigAdded, this),
+                  std::bind_front(&DeviceManager::processConfigRemoved, this))
+{
+    ctx.spawn(entityManager.handleInventoryGet());
+    info("DeviceManager created successfully");
+}
+
+auto DeviceManager::processConfigAdded(
+    const sdbusplus::message::object_path& objectPath,
+    const std::string& interfaceName) -> sdbusplus::async::task<>
+{
+    debug("Config added for {PATH} with {INTF}", "PATH", objectPath, "INTF",
+          interfaceName);
+    if (interfaceName == ModbusRTUDetectIntf::interface && ports.size() == 0)
+    {
+        warning(
+            "Skip processing ModbusRTUDetectIntf::interface as no serial ports detected yet");
+        co_return;
+    }
+
+    auto portInterfaces = PortIntf::PortFactory::getInterfaces();
+    if (std::find(portInterfaces.begin(), portInterfaces.end(),
+                  interfaceName) != portInterfaces.end())
+    {
+        auto config = co_await PortIntf::PortFactory::getConfig(
+            ctx, objectPath, interfaceName);
+        if (!config)
+        {
+            error("Failed to get Port config for {PATH}", "PATH", objectPath);
+            co_return;
+        }
+
+        try
+        {
+            ports[config->name] = PortIntf::PortFactory::create(ctx, *config);
+        }
+        catch (const std::exception& e)
+        {
+            error("Failed to create Port for {PATH} with {ERROR}", "PATH",
+                  objectPath, "ERROR", e);
+            co_return;
+        }
+    }
+    else if (interfaceName == ModbusRTUDetectIntf::interface)
+    {
+        auto res = co_await InventoryIntf::config::getConfig(ctx, objectPath);
+        if (!res)
+        {
+            error("Failed to get Inventory Device config for {PATH}", "PATH",
+                  objectPath);
+            co_return;
+        }
+        auto config = res.value();
+        try
+        {
+            auto inventoryDevice =
+                std::make_unique<InventoryIntf::Device>(ctx, config, ports);
+            ctx.spawn(inventoryDevice->probePorts());
+            inventoryDevices[config.name] = std::move(inventoryDevice);
+        }
+        catch (const std::exception& e)
+        {
+            error("Failed to create Inventory Device for {PATH} with {ERROR}",
+                  "PATH", objectPath, "ERROR", e);
+            co_return;
+        }
+    }
+}
+
+auto DeviceManager::processConfigRemoved(
+    const sdbusplus::message::object_path& /*unused*/,
+    const std::string& /*unused*/) -> sdbusplus::async::task<>
+{
+    // TODO: Implement this
+    co_return;
+}
+
+} // namespace phosphor::modbus::rtu
+
+auto main() -> int
+{
+    constexpr auto path = "/xyz/openbmc_project";
+    constexpr auto serviceName = "xyz.openbmc_project.ModbusRTU";
+    sdbusplus::async::context ctx;
+    sdbusplus::server::manager_t manager{ctx, path};
+
+    info("Creating Modbus device manager at {PATH}", "PATH", path);
+    phosphor::modbus::rtu::DeviceManager deviceManager{ctx};
+
+    ctx.request_name(serviceName);
+
+    ctx.run();
+    return 0;
+}