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