rtu: implement modbus sensor read

Read the modbus device config from the Entity Manager configuration and
create the sensor interfaces for related sensor register config.

Tested:
Added new Unit test named test_sensors -
```
> meson test -t 10 -C builddir/ --print-errorlogs --wrapper="valgrind --error-exitcode=1" test_sensors
ninja: Entering directory `/host/repos/Modbus/phosphor-modbus/builddir'
[2/2] Linking target tests/test_sensors
1/1 test_sensors        OK              13.98s

Ok:                1
Fail:              0
```

Tested on Qemu using Mock Modbus Device -
```
root@ventura:~# busctl tree xyz.openbmc_project.ModbusRTU
└─ /xyz
  └─ /xyz/openbmc_project
    ├─ /xyz/openbmc_project/inventory_source
    │ ├─ /xyz/openbmc_project/inventory_source/Heat_Exchanger_12_DevTTYUSB0
    │ ├─ /xyz/openbmc_project/inventory_source/Heat_Exchanger_12_DevTTYUSB1
    │ ├─ /xyz/openbmc_project/inventory_source/Reservoir_Pumping_Unit_12_DevTTYUSB0
    │ └─ /xyz/openbmc_project/inventory_source/Reservoir_Pumping_Unit_12_DevTTYUSB1
    └─ /xyz/openbmc_project/sensors
      └─ /xyz/openbmc_project/sensors/temperature
        ├─ /xyz/openbmc_project/sensors/temperature/Reservoir_Pumping_Unit_12_DevTTYUSB0_RPU_Coolant_Inlet_Temp_C
        ├─ /xyz/openbmc_project/sensors/temperature/Reservoir_Pumping_Unit_12_DevTTYUSB0_RPU_Coolant_Outlet_Temp_C
        ├─ /xyz/openbmc_project/sensors/temperature/Reservoir_Pumping_Unit_12_DevTTYUSB1_RPU_Coolant_Inlet_Temp_C
        └─ /xyz/openbmc_project/sensors/temperature/Reservoir_Pumping_Unit_12_DevTTYUSB1_RPU_Coolant_Outlet_Temp_C

busctl introspect xyz.openbmc_project.ModbusRTU /xyz/openbmc_project/sensors/temperature/Reservoir_Pumping_Unit_12_DevTTYUSB1_RPU_Coolant_Outlet_Temp_C
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.Sensor.Value    interface -         -                                        -
.MaxValue                           property  d         nan                                      emits-change writable
.MinValue                           property  d         nan                                      emits-change writable
.Unit                               property  s         "xyz.openbmc_project.Sensor.Value.Unit.… emits-change writable
.Value                              property  d         1670.6                                   emits-change writable
```

Change-Id: I1368e8df5999b5cee9ac19d185ee110a9ecc3021
Signed-off-by: Jagpal Singh Gill <paligill@gmail.com>
diff --git a/rtu/device_manager.cpp b/rtu/device_manager.cpp
index 6d2fbd6..804f6eb 100644
--- a/rtu/device_manager.cpp
+++ b/rtu/device_manager.cpp
@@ -1,5 +1,6 @@
 #include "device_manager.hpp"
 
+#include "device/device_factory.hpp"
 #include "port/port_factory.hpp"
 
 #include <phosphor-logging/lg2.hpp>
@@ -14,6 +15,7 @@
 
 using ModbusRTUDetectIntf =
     sdbusplus::client::xyz::openbmc_project::configuration::ModbusRTUDetect<>;
+using DeviceFactoryIntf = phosphor::modbus::rtu::device::DeviceFactory;
 
 static entity_manager::interface_list_t getInterfaces()
 {
@@ -22,8 +24,13 @@
     auto portInterfaces = PortIntf::PortFactory::getInterfaces();
     interfaces.insert(interfaces.end(), portInterfaces.begin(),
                       portInterfaces.end());
+
     interfaces.emplace_back(ModbusRTUDetectIntf::interface);
 
+    auto deviceInterfaces = DeviceFactoryIntf::getInterfaces();
+    interfaces.insert(interfaces.end(), deviceInterfaces.begin(),
+                      deviceInterfaces.end());
+
     return interfaces;
 }
 
@@ -54,48 +61,106 @@
     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;
-        }
+        co_return co_await processPortAdded(objectPath, interfaceName);
     }
-    else if (interfaceName == ModbusRTUDetectIntf::interface)
+
+    if (interfaceName == ModbusRTUDetectIntf::interface)
     {
-        auto res = co_await InventoryIntf::config::getConfig(ctx, objectPath);
-        if (!res)
+        co_return co_await processInventoryAdded(objectPath);
+    }
+
+    auto deviceInterfaces = DeviceFactoryIntf::getInterfaces();
+    if (std::find(deviceInterfaces.begin(), deviceInterfaces.end(),
+                  interfaceName) != deviceInterfaces.end())
+    {
+        co_return co_await processDeviceAdded(objectPath, interfaceName);
+    }
+}
+
+auto DeviceManager::processPortAdded(
+    const sdbusplus::message::object_path& objectPath,
+    const std::string& interfaceName) -> sdbusplus::async::task<>
+{
+    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;
+    }
+}
+
+auto DeviceManager::processInventoryAdded(
+    const sdbusplus::message::object_path& objectPath)
+    -> sdbusplus::async::task<>
+{
+    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::processDeviceAdded(
+    const sdbusplus::message::object_path& objectPath,
+    const std::string& interfaceName) -> sdbusplus::async::task<>
+{
+    auto res =
+        co_await DeviceFactoryIntf::getConfig(ctx, objectPath, interfaceName);
+    if (!res)
+    {
+        error("Failed to get Device config for {PATH}", "PATH", objectPath);
+        co_return;
+    }
+    auto config = res.value();
+
+    try
+    {
+        auto serialPort = ports.find(config.portName);
+        if (serialPort == ports.end())
         {
             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 device =
+            DeviceFactoryIntf::create(ctx, config, *(serialPort->second));
+        ctx.spawn(device->readSensorRegisters());
+        devices[config.name] = std::move(device);
+    }
+    catch (const std::exception& e)
+    {
+        error("Failed to create Device for {PATH} with {ERROR}", "PATH",
+              objectPath, "ERROR", e);
+        co_return;
     }
 }