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