1*cad9ecf6SJagpal Singh Gill #include "modbus_inventory.hpp" 2*cad9ecf6SJagpal Singh Gill 3*cad9ecf6SJagpal Singh Gill #include "common/entity_manager_interface.hpp" 4*cad9ecf6SJagpal Singh Gill 5*cad9ecf6SJagpal Singh Gill #include <phosphor-logging/lg2.hpp> 6*cad9ecf6SJagpal Singh Gill #include <xyz/openbmc_project/Configuration/ModbusRTUDetect/client.hpp> 7*cad9ecf6SJagpal Singh Gill #include <xyz/openbmc_project/Inventory/Item/client.hpp> 8*cad9ecf6SJagpal Singh Gill 9*cad9ecf6SJagpal Singh Gill #include <flat_map> 10*cad9ecf6SJagpal Singh Gill 11*cad9ecf6SJagpal Singh Gill namespace phosphor::modbus::rtu::inventory 12*cad9ecf6SJagpal Singh Gill { 13*cad9ecf6SJagpal Singh Gill PHOSPHOR_LOG2_USING; 14*cad9ecf6SJagpal Singh Gill 15*cad9ecf6SJagpal Singh Gill namespace config 16*cad9ecf6SJagpal Singh Gill { 17*cad9ecf6SJagpal Singh Gill 18*cad9ecf6SJagpal Singh Gill using BasicVariantType = 19*cad9ecf6SJagpal Singh Gill std::variant<std::vector<std::string>, std::vector<uint8_t>, std::string, 20*cad9ecf6SJagpal Singh Gill int64_t, uint64_t, double, int32_t, uint32_t, int16_t, 21*cad9ecf6SJagpal Singh Gill uint16_t, uint8_t, bool>; 22*cad9ecf6SJagpal Singh Gill using InventoryBaseConfigMap = std::flat_map<std::string, BasicVariantType>; 23*cad9ecf6SJagpal Singh Gill using InventoryData = std::flat_map<std::string, InventoryBaseConfigMap>; 24*cad9ecf6SJagpal Singh Gill using ManagedObjectType = 25*cad9ecf6SJagpal Singh Gill std::flat_map<sdbusplus::message::object_path, InventoryData>; 26*cad9ecf6SJagpal Singh Gill 27*cad9ecf6SJagpal Singh Gill static constexpr std::array<std::pair<std::string_view, Parity>, 3> 28*cad9ecf6SJagpal Singh Gill validParities = { 29*cad9ecf6SJagpal Singh Gill {{"Odd", Parity::odd}, {"Even", Parity::even}, {"None", Parity::none}}}; 30*cad9ecf6SJagpal Singh Gill 31*cad9ecf6SJagpal Singh Gill // TODO: This API will be dropped once EM supports non-indexed interfaces for 32*cad9ecf6SJagpal Singh Gill // array objects. 33*cad9ecf6SJagpal Singh Gill static auto processModbusAddressInterface( 34*cad9ecf6SJagpal Singh Gill Config& config, const InventoryBaseConfigMap& configMap) -> bool 35*cad9ecf6SJagpal Singh Gill { 36*cad9ecf6SJagpal Singh Gill debug("Processing ModbusAddress {NAME}", "NAME", config.name); 37*cad9ecf6SJagpal Singh Gill 38*cad9ecf6SJagpal Singh Gill auto rangeStartIter = configMap.find("RangeStart"); 39*cad9ecf6SJagpal Singh Gill if (rangeStartIter == configMap.end()) 40*cad9ecf6SJagpal Singh Gill { 41*cad9ecf6SJagpal Singh Gill error("Missing RangeStart for {NAME}", "NAME", config.name); 42*cad9ecf6SJagpal Singh Gill return false; 43*cad9ecf6SJagpal Singh Gill } 44*cad9ecf6SJagpal Singh Gill auto rangeStart = std::get<uint64_t>(rangeStartIter->second); 45*cad9ecf6SJagpal Singh Gill 46*cad9ecf6SJagpal Singh Gill auto rangeEndIter = configMap.find("RangeEnd"); 47*cad9ecf6SJagpal Singh Gill if (rangeEndIter == configMap.end()) 48*cad9ecf6SJagpal Singh Gill { 49*cad9ecf6SJagpal Singh Gill error("Missing RangeEnd for {NAME}", "NAME", config.name); 50*cad9ecf6SJagpal Singh Gill return false; 51*cad9ecf6SJagpal Singh Gill } 52*cad9ecf6SJagpal Singh Gill auto rangeEnd = std::get<uint64_t>(rangeEndIter->second); 53*cad9ecf6SJagpal Singh Gill 54*cad9ecf6SJagpal Singh Gill auto serialPortIter = configMap.find("SerialPort"); 55*cad9ecf6SJagpal Singh Gill if (serialPortIter == configMap.end()) 56*cad9ecf6SJagpal Singh Gill { 57*cad9ecf6SJagpal Singh Gill error("Missing SerialPort for {NAME}", "NAME", config.name); 58*cad9ecf6SJagpal Singh Gill return false; 59*cad9ecf6SJagpal Singh Gill } 60*cad9ecf6SJagpal Singh Gill auto serialPort = std::get<std::string>(serialPortIter->second); 61*cad9ecf6SJagpal Singh Gill 62*cad9ecf6SJagpal Singh Gill config.addressMap[serialPort].push_back(AddressRange{ 63*cad9ecf6SJagpal Singh Gill static_cast<uint8_t>(rangeStart), static_cast<uint8_t>(rangeEnd)}); 64*cad9ecf6SJagpal Singh Gill 65*cad9ecf6SJagpal Singh Gill debug("ModbusAddress {NAME} {PORT} {START} {END}", "NAME", config.name, 66*cad9ecf6SJagpal Singh Gill "PORT", serialPort, "START", rangeStart, "END", rangeEnd); 67*cad9ecf6SJagpal Singh Gill 68*cad9ecf6SJagpal Singh Gill return true; 69*cad9ecf6SJagpal Singh Gill } 70*cad9ecf6SJagpal Singh Gill 71*cad9ecf6SJagpal Singh Gill // TODO: This API will be dropped once EM supports non-indexed interfaces for 72*cad9ecf6SJagpal Singh Gill // array objects. 73*cad9ecf6SJagpal Singh Gill static auto processModbusRegistersInterface( 74*cad9ecf6SJagpal Singh Gill Config& config, const InventoryBaseConfigMap& configMap) -> bool 75*cad9ecf6SJagpal Singh Gill { 76*cad9ecf6SJagpal Singh Gill debug("Processing ModbusRegisters {NAME}", "NAME", config.name); 77*cad9ecf6SJagpal Singh Gill Register registerConfig = {}; 78*cad9ecf6SJagpal Singh Gill 79*cad9ecf6SJagpal Singh Gill auto nameIter = configMap.find("Name"); 80*cad9ecf6SJagpal Singh Gill if (nameIter == configMap.end()) 81*cad9ecf6SJagpal Singh Gill { 82*cad9ecf6SJagpal Singh Gill error("Missing Name for {NAME}", "NAME", config.name); 83*cad9ecf6SJagpal Singh Gill return false; 84*cad9ecf6SJagpal Singh Gill } 85*cad9ecf6SJagpal Singh Gill registerConfig.name = std::get<std::string>(nameIter->second); 86*cad9ecf6SJagpal Singh Gill 87*cad9ecf6SJagpal Singh Gill auto address = configMap.find("Address"); 88*cad9ecf6SJagpal Singh Gill if (address == configMap.end()) 89*cad9ecf6SJagpal Singh Gill { 90*cad9ecf6SJagpal Singh Gill error("Missing Address for {NAME}", "NAME", config.name); 91*cad9ecf6SJagpal Singh Gill return false; 92*cad9ecf6SJagpal Singh Gill } 93*cad9ecf6SJagpal Singh Gill registerConfig.offset = std::get<uint64_t>(address->second); 94*cad9ecf6SJagpal Singh Gill 95*cad9ecf6SJagpal Singh Gill auto sizeIter = configMap.find("Size"); 96*cad9ecf6SJagpal Singh Gill if (sizeIter == configMap.end()) 97*cad9ecf6SJagpal Singh Gill { 98*cad9ecf6SJagpal Singh Gill error("Missing Size for {NAME}", "NAME", config.name); 99*cad9ecf6SJagpal Singh Gill return false; 100*cad9ecf6SJagpal Singh Gill } 101*cad9ecf6SJagpal Singh Gill registerConfig.size = std::get<uint64_t>(sizeIter->second); 102*cad9ecf6SJagpal Singh Gill 103*cad9ecf6SJagpal Singh Gill config.registers.push_back(registerConfig); 104*cad9ecf6SJagpal Singh Gill 105*cad9ecf6SJagpal Singh Gill debug("ModbusRegisters {NAME} {ADDRESS} {SIZE}", "NAME", 106*cad9ecf6SJagpal Singh Gill registerConfig.name, "ADDRESS", registerConfig.offset, "SIZE", 107*cad9ecf6SJagpal Singh Gill registerConfig.size); 108*cad9ecf6SJagpal Singh Gill 109*cad9ecf6SJagpal Singh Gill return true; 110*cad9ecf6SJagpal Singh Gill } 111*cad9ecf6SJagpal Singh Gill 112*cad9ecf6SJagpal Singh Gill static auto printConfig(const Config& config) -> void 113*cad9ecf6SJagpal Singh Gill { 114*cad9ecf6SJagpal Singh Gill info("Inventory device config: {NAME} {BAUDRATE} {PARITY}", "NAME", 115*cad9ecf6SJagpal Singh Gill config.name, "BAUDRATE", config.baudRate, "PARITY", config.parity); 116*cad9ecf6SJagpal Singh Gill 117*cad9ecf6SJagpal Singh Gill for (const auto& [port, addressRanges] : config.addressMap) 118*cad9ecf6SJagpal Singh Gill { 119*cad9ecf6SJagpal Singh Gill for (const auto& addressRange : addressRanges) 120*cad9ecf6SJagpal Singh Gill { 121*cad9ecf6SJagpal Singh Gill info( 122*cad9ecf6SJagpal Singh Gill "Inventory device config: {PORT} {ADDRESS_START} {ADDRESS_END}", 123*cad9ecf6SJagpal Singh Gill "PORT", port, "ADDRESS_START", addressRange.start, 124*cad9ecf6SJagpal Singh Gill "ADDRESS_END", addressRange.end); 125*cad9ecf6SJagpal Singh Gill } 126*cad9ecf6SJagpal Singh Gill } 127*cad9ecf6SJagpal Singh Gill 128*cad9ecf6SJagpal Singh Gill for (const auto& registerConfig : config.registers) 129*cad9ecf6SJagpal Singh Gill { 130*cad9ecf6SJagpal Singh Gill info("Inventory device config: {NAME} {ADDRESS} {SIZE}", "NAME", 131*cad9ecf6SJagpal Singh Gill registerConfig.name, "ADDRESS", registerConfig.offset, "SIZE", 132*cad9ecf6SJagpal Singh Gill registerConfig.size); 133*cad9ecf6SJagpal Singh Gill } 134*cad9ecf6SJagpal Singh Gill } 135*cad9ecf6SJagpal Singh Gill 136*cad9ecf6SJagpal Singh Gill auto getConfigSubInterfaces(sdbusplus::async::context& ctx, 137*cad9ecf6SJagpal Singh Gill sdbusplus::message::object_path objectPath, 138*cad9ecf6SJagpal Singh Gill Config& config) -> sdbusplus::async::task<bool> 139*cad9ecf6SJagpal Singh Gill { 140*cad9ecf6SJagpal Singh Gill constexpr auto modbusAddressInterface = 141*cad9ecf6SJagpal Singh Gill "xyz.openbmc_project.Configuration.ModbusRTUDetect.Address"; 142*cad9ecf6SJagpal Singh Gill constexpr auto modbusRegistersInterface = 143*cad9ecf6SJagpal Singh Gill "xyz.openbmc_project.Configuration.ModbusRTUDetect.Registers"; 144*cad9ecf6SJagpal Singh Gill 145*cad9ecf6SJagpal Singh Gill using InventoryIntf = 146*cad9ecf6SJagpal Singh Gill sdbusplus::client::xyz::openbmc_project::inventory::Item<>; 147*cad9ecf6SJagpal Singh Gill 148*cad9ecf6SJagpal Singh Gill constexpr auto entityManager = 149*cad9ecf6SJagpal Singh Gill sdbusplus::async::proxy() 150*cad9ecf6SJagpal Singh Gill .service(entity_manager::EntityManagerInterface::serviceName) 151*cad9ecf6SJagpal Singh Gill .path(InventoryIntf::namespace_path) 152*cad9ecf6SJagpal Singh Gill .interface("org.freedesktop.DBus.ObjectManager"); 153*cad9ecf6SJagpal Singh Gill 154*cad9ecf6SJagpal Singh Gill for (const auto& [path, deviceConfig] : 155*cad9ecf6SJagpal Singh Gill co_await entityManager.call<ManagedObjectType>(ctx, 156*cad9ecf6SJagpal Singh Gill "GetManagedObjects")) 157*cad9ecf6SJagpal Singh Gill { 158*cad9ecf6SJagpal Singh Gill if (!(path.str).starts_with(objectPath.str)) 159*cad9ecf6SJagpal Singh Gill { 160*cad9ecf6SJagpal Singh Gill debug("Skipping device {PATH}", "PATH", path.str); 161*cad9ecf6SJagpal Singh Gill continue; 162*cad9ecf6SJagpal Singh Gill } 163*cad9ecf6SJagpal Singh Gill debug("Processing device {PATH}", "PATH", path.str); 164*cad9ecf6SJagpal Singh Gill for (const auto& [interfaceName, interfaceConfig] : deviceConfig) 165*cad9ecf6SJagpal Singh Gill { 166*cad9ecf6SJagpal Singh Gill if (interfaceName.starts_with(modbusAddressInterface)) 167*cad9ecf6SJagpal Singh Gill { 168*cad9ecf6SJagpal Singh Gill if (!processModbusAddressInterface(config, interfaceConfig)) 169*cad9ecf6SJagpal Singh Gill { 170*cad9ecf6SJagpal Singh Gill error("Failed to process {INTERFACE} for {NAME}", 171*cad9ecf6SJagpal Singh Gill "INTERFACE", modbusAddressInterface, "NAME", 172*cad9ecf6SJagpal Singh Gill config.name); 173*cad9ecf6SJagpal Singh Gill co_return false; 174*cad9ecf6SJagpal Singh Gill } 175*cad9ecf6SJagpal Singh Gill } 176*cad9ecf6SJagpal Singh Gill else if (interfaceName.starts_with(modbusRegistersInterface)) 177*cad9ecf6SJagpal Singh Gill { 178*cad9ecf6SJagpal Singh Gill if (!processModbusRegistersInterface(config, interfaceConfig)) 179*cad9ecf6SJagpal Singh Gill { 180*cad9ecf6SJagpal Singh Gill error("Failed to process {INTERFACE} for {NAME}", 181*cad9ecf6SJagpal Singh Gill "INTERFACE", modbusRegistersInterface, "NAME", 182*cad9ecf6SJagpal Singh Gill config.name); 183*cad9ecf6SJagpal Singh Gill co_return false; 184*cad9ecf6SJagpal Singh Gill } 185*cad9ecf6SJagpal Singh Gill } 186*cad9ecf6SJagpal Singh Gill } 187*cad9ecf6SJagpal Singh Gill } 188*cad9ecf6SJagpal Singh Gill 189*cad9ecf6SJagpal Singh Gill co_return true; 190*cad9ecf6SJagpal Singh Gill } 191*cad9ecf6SJagpal Singh Gill 192*cad9ecf6SJagpal Singh Gill auto getConfig(sdbusplus::async::context& ctx, 193*cad9ecf6SJagpal Singh Gill sdbusplus::message::object_path objectPath) 194*cad9ecf6SJagpal Singh Gill -> sdbusplus::async::task<std::optional<Config>> 195*cad9ecf6SJagpal Singh Gill { 196*cad9ecf6SJagpal Singh Gill using ModbusRTUDetectIntf = sdbusplus::client::xyz::openbmc_project:: 197*cad9ecf6SJagpal Singh Gill configuration::ModbusRTUDetect<>; 198*cad9ecf6SJagpal Singh Gill 199*cad9ecf6SJagpal Singh Gill Config config = {}; 200*cad9ecf6SJagpal Singh Gill 201*cad9ecf6SJagpal Singh Gill auto properties = 202*cad9ecf6SJagpal Singh Gill co_await ModbusRTUDetectIntf(ctx) 203*cad9ecf6SJagpal Singh Gill .service(entity_manager::EntityManagerInterface::serviceName) 204*cad9ecf6SJagpal Singh Gill .path(objectPath.str) 205*cad9ecf6SJagpal Singh Gill .properties(); 206*cad9ecf6SJagpal Singh Gill 207*cad9ecf6SJagpal Singh Gill config.name = properties.name; 208*cad9ecf6SJagpal Singh Gill config.baudRate = properties.baud_rate; 209*cad9ecf6SJagpal Singh Gill 210*cad9ecf6SJagpal Singh Gill for (const auto& [parityStr, parity] : config::validParities) 211*cad9ecf6SJagpal Singh Gill { 212*cad9ecf6SJagpal Singh Gill if (parityStr == properties.data_parity) 213*cad9ecf6SJagpal Singh Gill { 214*cad9ecf6SJagpal Singh Gill config.parity = parity; 215*cad9ecf6SJagpal Singh Gill break; 216*cad9ecf6SJagpal Singh Gill } 217*cad9ecf6SJagpal Singh Gill } 218*cad9ecf6SJagpal Singh Gill if (config.parity == Parity::unknown) 219*cad9ecf6SJagpal Singh Gill { 220*cad9ecf6SJagpal Singh Gill error("Invalid parity {PARITY} for {NAME}", "PARITY", 221*cad9ecf6SJagpal Singh Gill properties.data_parity, "NAME", properties.name); 222*cad9ecf6SJagpal Singh Gill co_return std::nullopt; 223*cad9ecf6SJagpal Singh Gill } 224*cad9ecf6SJagpal Singh Gill 225*cad9ecf6SJagpal Singh Gill if (!co_await getConfigSubInterfaces(ctx, objectPath, config)) 226*cad9ecf6SJagpal Singh Gill { 227*cad9ecf6SJagpal Singh Gill co_return std::nullopt; 228*cad9ecf6SJagpal Singh Gill } 229*cad9ecf6SJagpal Singh Gill 230*cad9ecf6SJagpal Singh Gill printConfig(config); 231*cad9ecf6SJagpal Singh Gill 232*cad9ecf6SJagpal Singh Gill co_return config; 233*cad9ecf6SJagpal Singh Gill } 234*cad9ecf6SJagpal Singh Gill 235*cad9ecf6SJagpal Singh Gill } // namespace config 236*cad9ecf6SJagpal Singh Gill 237*cad9ecf6SJagpal Singh Gill Device::Device(sdbusplus::async::context& ctx, const config::Config& config, 238*cad9ecf6SJagpal Singh Gill serial_port_map_t& serialPorts) : 239*cad9ecf6SJagpal Singh Gill ctx(ctx), config(config), serialPorts(serialPorts) 240*cad9ecf6SJagpal Singh Gill { 241*cad9ecf6SJagpal Singh Gill for (const auto& [serialPort, _] : config.addressMap) 242*cad9ecf6SJagpal Singh Gill { 243*cad9ecf6SJagpal Singh Gill if (serialPorts.find(serialPort) == serialPorts.end()) 244*cad9ecf6SJagpal Singh Gill { 245*cad9ecf6SJagpal Singh Gill error("Serial port {PORT} not found for {NAME}", "PORT", serialPort, 246*cad9ecf6SJagpal Singh Gill "NAME", config.name); 247*cad9ecf6SJagpal Singh Gill continue; 248*cad9ecf6SJagpal Singh Gill } 249*cad9ecf6SJagpal Singh Gill } 250*cad9ecf6SJagpal Singh Gill } 251*cad9ecf6SJagpal Singh Gill 252*cad9ecf6SJagpal Singh Gill auto Device::probePorts() -> sdbusplus::async::task<void> 253*cad9ecf6SJagpal Singh Gill { 254*cad9ecf6SJagpal Singh Gill debug("Probing ports for {NAME}", "NAME", config.name); 255*cad9ecf6SJagpal Singh Gill while (!ctx.stop_requested()) 256*cad9ecf6SJagpal Singh Gill { 257*cad9ecf6SJagpal Singh Gill for (const auto& [serialPort, _] : config.addressMap) 258*cad9ecf6SJagpal Singh Gill { 259*cad9ecf6SJagpal Singh Gill if (serialPorts.find(serialPort) == serialPorts.end()) 260*cad9ecf6SJagpal Singh Gill { 261*cad9ecf6SJagpal Singh Gill continue; 262*cad9ecf6SJagpal Singh Gill } 263*cad9ecf6SJagpal Singh Gill ctx.spawn(probePort(serialPort)); 264*cad9ecf6SJagpal Singh Gill } 265*cad9ecf6SJagpal Singh Gill constexpr auto probeInterval = 3; 266*cad9ecf6SJagpal Singh Gill co_await sdbusplus::async::sleep_for( 267*cad9ecf6SJagpal Singh Gill ctx, std::chrono::seconds(probeInterval)); 268*cad9ecf6SJagpal Singh Gill debug("Probing ports for {NAME} in {INTERVAL} seconds", "NAME", 269*cad9ecf6SJagpal Singh Gill config.name, "INTERVAL", probeInterval); 270*cad9ecf6SJagpal Singh Gill } 271*cad9ecf6SJagpal Singh Gill } 272*cad9ecf6SJagpal Singh Gill 273*cad9ecf6SJagpal Singh Gill auto Device::probePort(std::string portName) -> sdbusplus::async::task<void> 274*cad9ecf6SJagpal Singh Gill { 275*cad9ecf6SJagpal Singh Gill debug("Probing port {PORT}", "PORT", portName); 276*cad9ecf6SJagpal Singh Gill 277*cad9ecf6SJagpal Singh Gill auto portConfig = config.addressMap.find(portName); 278*cad9ecf6SJagpal Singh Gill if (portConfig == config.addressMap.end()) 279*cad9ecf6SJagpal Singh Gill { 280*cad9ecf6SJagpal Singh Gill error("Serial port {PORT} address map not found for {NAME}", "PORT", 281*cad9ecf6SJagpal Singh Gill portName, "NAME", config.name); 282*cad9ecf6SJagpal Singh Gill co_return; 283*cad9ecf6SJagpal Singh Gill } 284*cad9ecf6SJagpal Singh Gill auto addressRanges = portConfig->second; 285*cad9ecf6SJagpal Singh Gill 286*cad9ecf6SJagpal Singh Gill auto port = serialPorts.find(portName); 287*cad9ecf6SJagpal Singh Gill if (port == serialPorts.end()) 288*cad9ecf6SJagpal Singh Gill { 289*cad9ecf6SJagpal Singh Gill error("Serial port {PORT} not found for {NAME}", "PORT", portName, 290*cad9ecf6SJagpal Singh Gill "NAME", config.name); 291*cad9ecf6SJagpal Singh Gill co_return; 292*cad9ecf6SJagpal Singh Gill } 293*cad9ecf6SJagpal Singh Gill 294*cad9ecf6SJagpal Singh Gill for (const auto& addressRange : addressRanges) 295*cad9ecf6SJagpal Singh Gill { 296*cad9ecf6SJagpal Singh Gill for (auto address = addressRange.start; address <= addressRange.end; 297*cad9ecf6SJagpal Singh Gill address++) 298*cad9ecf6SJagpal Singh Gill { 299*cad9ecf6SJagpal Singh Gill co_await probeDevice(address, portName, *port->second); 300*cad9ecf6SJagpal Singh Gill } 301*cad9ecf6SJagpal Singh Gill } 302*cad9ecf6SJagpal Singh Gill } 303*cad9ecf6SJagpal Singh Gill 304*cad9ecf6SJagpal Singh Gill auto Device::probeDevice(uint8_t address, const std::string& portName, 305*cad9ecf6SJagpal Singh Gill SerialPortIntf& port) -> sdbusplus::async::task<void> 306*cad9ecf6SJagpal Singh Gill { 307*cad9ecf6SJagpal Singh Gill debug("Probing device at {ADDRESS} on port {PORT}", "ADDRESS", address, 308*cad9ecf6SJagpal Singh Gill "PORT", portName); 309*cad9ecf6SJagpal Singh Gill 310*cad9ecf6SJagpal Singh Gill if (config.registers.size() == 0) 311*cad9ecf6SJagpal Singh Gill { 312*cad9ecf6SJagpal Singh Gill error("No registers configured for {NAME}", "NAME", config.name); 313*cad9ecf6SJagpal Singh Gill co_return; 314*cad9ecf6SJagpal Singh Gill } 315*cad9ecf6SJagpal Singh Gill auto probeRegister = config.registers[0].offset; 316*cad9ecf6SJagpal Singh Gill auto registers = std::vector<uint16_t>(config.registers[0].size); 317*cad9ecf6SJagpal Singh Gill 318*cad9ecf6SJagpal Singh Gill auto sourceId = std::to_string(address) + "_" + portName; 319*cad9ecf6SJagpal Singh Gill 320*cad9ecf6SJagpal Singh Gill auto ret = co_await port.readHoldingRegisters( 321*cad9ecf6SJagpal Singh Gill address, probeRegister, config.baudRate, config.parity, registers); 322*cad9ecf6SJagpal Singh Gill if (ret) 323*cad9ecf6SJagpal Singh Gill { 324*cad9ecf6SJagpal Singh Gill if (inventorySources.find(sourceId) == inventorySources.end()) 325*cad9ecf6SJagpal Singh Gill { 326*cad9ecf6SJagpal Singh Gill debug("Device found at {ADDRESS}", "ADDRESS", address); 327*cad9ecf6SJagpal Singh Gill co_await addInventorySource(address, portName, port); 328*cad9ecf6SJagpal Singh Gill } 329*cad9ecf6SJagpal Singh Gill else 330*cad9ecf6SJagpal Singh Gill { 331*cad9ecf6SJagpal Singh Gill debug("Device already exists at {ADDRESS}", "ADDRESS", address); 332*cad9ecf6SJagpal Singh Gill } 333*cad9ecf6SJagpal Singh Gill } 334*cad9ecf6SJagpal Singh Gill else 335*cad9ecf6SJagpal Singh Gill { 336*cad9ecf6SJagpal Singh Gill if (inventorySources.find(sourceId) != inventorySources.end()) 337*cad9ecf6SJagpal Singh Gill { 338*cad9ecf6SJagpal Singh Gill warning( 339*cad9ecf6SJagpal Singh Gill "Device removed at {ADDRESS} due to probe failure for {PROBE_REGISTER}", 340*cad9ecf6SJagpal Singh Gill "ADDRESS", address, "PROBE_REGISTER", probeRegister); 341*cad9ecf6SJagpal Singh Gill inventorySources[sourceId]->emit_removed(); 342*cad9ecf6SJagpal Singh Gill inventorySources.erase(sourceId); 343*cad9ecf6SJagpal Singh Gill } 344*cad9ecf6SJagpal Singh Gill } 345*cad9ecf6SJagpal Singh Gill } 346*cad9ecf6SJagpal Singh Gill 347*cad9ecf6SJagpal Singh Gill static auto fillInventorySourceProperties( 348*cad9ecf6SJagpal Singh Gill InventorySourceIntf::properties_t& properties, const std::string& regName, 349*cad9ecf6SJagpal Singh Gill std::string& strValue) -> void 350*cad9ecf6SJagpal Singh Gill { 351*cad9ecf6SJagpal Singh Gill constexpr auto partNumber = "PartNumber"; 352*cad9ecf6SJagpal Singh Gill constexpr auto sparePartNumber = "SparePartNumber"; 353*cad9ecf6SJagpal Singh Gill constexpr auto serialNumber = "SerialNumber"; 354*cad9ecf6SJagpal Singh Gill constexpr auto buildDate = "BuildDate"; 355*cad9ecf6SJagpal Singh Gill constexpr auto model = "Model"; 356*cad9ecf6SJagpal Singh Gill constexpr auto manufacturer = "Manufacturer"; 357*cad9ecf6SJagpal Singh Gill 358*cad9ecf6SJagpal Singh Gill if (regName == partNumber) 359*cad9ecf6SJagpal Singh Gill { 360*cad9ecf6SJagpal Singh Gill properties.part_number = strValue; 361*cad9ecf6SJagpal Singh Gill } 362*cad9ecf6SJagpal Singh Gill else if (regName == sparePartNumber) 363*cad9ecf6SJagpal Singh Gill { 364*cad9ecf6SJagpal Singh Gill properties.spare_part_number = strValue; 365*cad9ecf6SJagpal Singh Gill } 366*cad9ecf6SJagpal Singh Gill else if (regName == serialNumber) 367*cad9ecf6SJagpal Singh Gill { 368*cad9ecf6SJagpal Singh Gill properties.serial_number = strValue; 369*cad9ecf6SJagpal Singh Gill } 370*cad9ecf6SJagpal Singh Gill else if (regName == buildDate) 371*cad9ecf6SJagpal Singh Gill { 372*cad9ecf6SJagpal Singh Gill properties.build_date = strValue; 373*cad9ecf6SJagpal Singh Gill } 374*cad9ecf6SJagpal Singh Gill else if (regName == model) 375*cad9ecf6SJagpal Singh Gill { 376*cad9ecf6SJagpal Singh Gill properties.model = strValue; 377*cad9ecf6SJagpal Singh Gill } 378*cad9ecf6SJagpal Singh Gill else if (regName == manufacturer) 379*cad9ecf6SJagpal Singh Gill { 380*cad9ecf6SJagpal Singh Gill properties.manufacturer = strValue; 381*cad9ecf6SJagpal Singh Gill } 382*cad9ecf6SJagpal Singh Gill } 383*cad9ecf6SJagpal Singh Gill 384*cad9ecf6SJagpal Singh Gill auto Device::addInventorySource(uint8_t address, const std::string& portName, 385*cad9ecf6SJagpal Singh Gill SerialPortIntf& port) 386*cad9ecf6SJagpal Singh Gill -> sdbusplus::async::task<void> 387*cad9ecf6SJagpal Singh Gill { 388*cad9ecf6SJagpal Singh Gill InventorySourceIntf::properties_t properties; 389*cad9ecf6SJagpal Singh Gill 390*cad9ecf6SJagpal Singh Gill for (const auto& reg : config.registers) 391*cad9ecf6SJagpal Singh Gill { 392*cad9ecf6SJagpal Singh Gill auto registers = std::vector<uint16_t>(reg.size); 393*cad9ecf6SJagpal Singh Gill auto ret = co_await port.readHoldingRegisters( 394*cad9ecf6SJagpal Singh Gill address, reg.offset, config.baudRate, config.parity, registers); 395*cad9ecf6SJagpal Singh Gill if (!ret) 396*cad9ecf6SJagpal Singh Gill { 397*cad9ecf6SJagpal Singh Gill error( 398*cad9ecf6SJagpal Singh Gill "Failed to read holding registers {NAME} for {DEVICE_ADDRESS}", 399*cad9ecf6SJagpal Singh Gill "NAME", reg.name, "DEVICE_ADDRESS", address); 400*cad9ecf6SJagpal Singh Gill continue; 401*cad9ecf6SJagpal Singh Gill } 402*cad9ecf6SJagpal Singh Gill 403*cad9ecf6SJagpal Singh Gill std::string strValue = ""; 404*cad9ecf6SJagpal Singh Gill 405*cad9ecf6SJagpal Singh Gill // Reswap bytes in each register for string conversion 406*cad9ecf6SJagpal Singh Gill for (const auto& value : registers) 407*cad9ecf6SJagpal Singh Gill { 408*cad9ecf6SJagpal Singh Gill strValue += static_cast<char>((value >> 8) & 0xFF); 409*cad9ecf6SJagpal Singh Gill strValue += static_cast<char>(value & 0xFF); 410*cad9ecf6SJagpal Singh Gill } 411*cad9ecf6SJagpal Singh Gill 412*cad9ecf6SJagpal Singh Gill fillInventorySourceProperties(properties, reg.name, strValue); 413*cad9ecf6SJagpal Singh Gill } 414*cad9ecf6SJagpal Singh Gill 415*cad9ecf6SJagpal Singh Gill auto pathSuffix = 416*cad9ecf6SJagpal Singh Gill config.name + " " + std::to_string(address) + " " + portName; 417*cad9ecf6SJagpal Singh Gill 418*cad9ecf6SJagpal Singh Gill properties.name = pathSuffix; 419*cad9ecf6SJagpal Singh Gill properties.address = address; 420*cad9ecf6SJagpal Singh Gill properties.link_tty = portName; 421*cad9ecf6SJagpal Singh Gill 422*cad9ecf6SJagpal Singh Gill std::replace(pathSuffix.begin(), pathSuffix.end(), ' ', '_'); 423*cad9ecf6SJagpal Singh Gill 424*cad9ecf6SJagpal Singh Gill auto objectPath = 425*cad9ecf6SJagpal Singh Gill std::string(InventorySourceIntf::namespace_path) + "/" + pathSuffix; 426*cad9ecf6SJagpal Singh Gill auto sourceId = std::to_string(address) + "_" + portName; 427*cad9ecf6SJagpal Singh Gill 428*cad9ecf6SJagpal Singh Gill inventorySources[sourceId] = std::make_unique<InventorySourceIntf>( 429*cad9ecf6SJagpal Singh Gill ctx, objectPath.c_str(), properties); 430*cad9ecf6SJagpal Singh Gill inventorySources[sourceId]->emit_added(); 431*cad9ecf6SJagpal Singh Gill 432*cad9ecf6SJagpal Singh Gill info("Added InventorySource at {PATH}", "PATH", objectPath); 433*cad9ecf6SJagpal Singh Gill } 434*cad9ecf6SJagpal Singh Gill 435*cad9ecf6SJagpal Singh Gill } // namespace phosphor::modbus::rtu::inventory 436