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