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