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;
+}