xref: /openbmc/phosphor-modbus/rtu/device_manager.cpp (revision e92aba4516471f5a01d4ab1f93eb9919ec05c21f)
1 #include "device_manager.hpp"
2 
3 #include "device/device_factory.hpp"
4 #include "port/port_factory.hpp"
5 
6 #include <phosphor-logging/lg2.hpp>
7 #include <sdbusplus/async.hpp>
8 #include <sdbusplus/server/manager.hpp>
9 #include <xyz/openbmc_project/Configuration/ModbusRTUDetect/client.hpp>
10 
11 PHOSPHOR_LOG2_USING;
12 
13 namespace phosphor::modbus::rtu
14 {
15 
16 using ModbusRTUDetectIntf =
17     sdbusplus::client::xyz::openbmc_project::configuration::ModbusRTUDetect<>;
18 using DeviceFactoryIntf = phosphor::modbus::rtu::device::DeviceFactory;
19 
20 static entity_manager::interface_list_t getInterfaces()
21 {
22     entity_manager::interface_list_t interfaces;
23 
24     auto portInterfaces = PortIntf::PortFactory::getInterfaces();
25     interfaces.insert(interfaces.end(), portInterfaces.begin(),
26                       portInterfaces.end());
27 
28     interfaces.emplace_back(ModbusRTUDetectIntf::interface);
29 
30     auto deviceInterfaces = DeviceFactoryIntf::getInterfaces();
31     interfaces.insert(interfaces.end(), deviceInterfaces.begin(),
32                       deviceInterfaces.end());
33 
34     return interfaces;
35 }
36 
37 DeviceManager::DeviceManager(sdbusplus::async::context& ctx) :
38     ctx(ctx),
39     entityManager(ctx, getInterfaces(),
40                   std::bind_front(&DeviceManager::processConfigAdded, this),
41                   std::bind_front(&DeviceManager::processConfigRemoved, this))
42 {
43     ctx.spawn(entityManager.handleInventoryGet());
44     info("DeviceManager created successfully");
45 }
46 
47 auto DeviceManager::processConfigAdded(
48     const sdbusplus::message::object_path& objectPath,
49     const std::string& interfaceName) -> sdbusplus::async::task<>
50 {
51     debug("Config added for {PATH} with {INTF}", "PATH", objectPath, "INTF",
52           interfaceName);
53     if (interfaceName == ModbusRTUDetectIntf::interface && ports.size() == 0)
54     {
55         warning(
56             "Skip processing ModbusRTUDetectIntf::interface as no serial ports detected yet");
57         co_return;
58     }
59 
60     auto portInterfaces = PortIntf::PortFactory::getInterfaces();
61     if (std::find(portInterfaces.begin(), portInterfaces.end(),
62                   interfaceName) != portInterfaces.end())
63     {
64         co_return co_await processPortAdded(objectPath, interfaceName);
65     }
66 
67     if (interfaceName == ModbusRTUDetectIntf::interface)
68     {
69         co_return co_await processInventoryAdded(objectPath);
70     }
71 
72     auto deviceInterfaces = DeviceFactoryIntf::getInterfaces();
73     if (std::find(deviceInterfaces.begin(), deviceInterfaces.end(),
74                   interfaceName) != deviceInterfaces.end())
75     {
76         co_return co_await processDeviceAdded(objectPath, interfaceName);
77     }
78 }
79 
80 auto DeviceManager::processPortAdded(
81     const sdbusplus::message::object_path& objectPath,
82     const std::string& interfaceName) -> sdbusplus::async::task<>
83 {
84     auto config = co_await PortIntf::PortFactory::getConfig(
85         ctx, objectPath, interfaceName);
86     if (!config)
87     {
88         error("Failed to get Port config for {PATH}", "PATH", objectPath);
89         co_return;
90     }
91 
92     try
93     {
94         ports[config->name] = PortIntf::PortFactory::create(ctx, *config);
95     }
96     catch (const std::exception& e)
97     {
98         error("Failed to create Port for {PATH} with {ERROR}", "PATH",
99               objectPath, "ERROR", e);
100         co_return;
101     }
102 }
103 
104 auto DeviceManager::processInventoryAdded(
105     const sdbusplus::message::object_path& objectPath)
106     -> sdbusplus::async::task<>
107 {
108     auto res = co_await InventoryIntf::config::getConfig(ctx, objectPath);
109     if (!res)
110     {
111         error("Failed to get Inventory Device config for {PATH}", "PATH",
112               objectPath);
113         co_return;
114     }
115     auto config = res.value();
116     try
117     {
118         auto inventoryDevice =
119             std::make_unique<InventoryIntf::Device>(ctx, config, ports);
120         ctx.spawn(inventoryDevice->probePorts());
121         inventoryDevices[config.name] = std::move(inventoryDevice);
122     }
123     catch (const std::exception& e)
124     {
125         error("Failed to create Inventory Device for {PATH} with {ERROR}",
126               "PATH", objectPath, "ERROR", e);
127         co_return;
128     }
129 }
130 
131 auto DeviceManager::processDeviceAdded(
132     const sdbusplus::message::object_path& objectPath,
133     const std::string& interfaceName) -> sdbusplus::async::task<>
134 {
135     auto res =
136         co_await DeviceFactoryIntf::getConfig(ctx, objectPath, interfaceName);
137     if (!res)
138     {
139         error("Failed to get Device config for {PATH}", "PATH", objectPath);
140         co_return;
141     }
142     auto config = res.value();
143 
144     try
145     {
146         auto serialPort = ports.find(config.portName);
147         if (serialPort == ports.end())
148         {
149             error("Failed to get Inventory Device config for {PATH}", "PATH",
150                   objectPath);
151             co_return;
152         }
153 
154         auto device =
155             DeviceFactoryIntf::create(ctx, config, *(serialPort->second));
156         ctx.spawn(device->readSensorRegisters());
157         devices[config.name] = std::move(device);
158     }
159     catch (const std::exception& e)
160     {
161         error("Failed to create Device for {PATH} with {ERROR}", "PATH",
162               objectPath, "ERROR", e);
163         co_return;
164     }
165 }
166 
167 auto DeviceManager::processConfigRemoved(
168     const sdbusplus::message::object_path& /*unused*/,
169     const std::string& /*unused*/) -> sdbusplus::async::task<>
170 {
171     // TODO: Implement this
172     co_return;
173 }
174 
175 } // namespace phosphor::modbus::rtu
176 
177 auto main() -> int
178 {
179     constexpr auto path = "/xyz/openbmc_project";
180     constexpr auto serviceName = "xyz.openbmc_project.ModbusRTU";
181     sdbusplus::async::context ctx;
182     sdbusplus::server::manager_t manager{ctx, path};
183 
184     info("Creating Modbus device manager at {PATH}", "PATH", path);
185     phosphor::modbus::rtu::DeviceManager deviceManager{ctx};
186 
187     ctx.request_name(serviceName);
188 
189     ctx.run();
190     return 0;
191 }
192