xref: /openbmc/dbus-sensors/src/Utils.hpp (revision 201a1015)
1e73bd0a1SAndrew Jeffery #pragma once
2e73bd0a1SAndrew Jeffery 
3e73bd0a1SAndrew Jeffery #include "VariantVisitors.hpp"
4e73bd0a1SAndrew Jeffery 
5e73bd0a1SAndrew Jeffery #include <boost/algorithm/string/replace.hpp>
6e73bd0a1SAndrew Jeffery #include <boost/asio/steady_timer.hpp>
7e73bd0a1SAndrew Jeffery #include <boost/container/flat_map.hpp>
8e73bd0a1SAndrew Jeffery #include <sdbusplus/asio/connection.hpp>
9e73bd0a1SAndrew Jeffery #include <sdbusplus/asio/object_server.hpp>
10e73bd0a1SAndrew Jeffery #include <sdbusplus/message/types.hpp>
11e73bd0a1SAndrew Jeffery 
12e73bd0a1SAndrew Jeffery #include <filesystem>
13e73bd0a1SAndrew Jeffery #include <functional>
14e73bd0a1SAndrew Jeffery #include <iostream>
15e73bd0a1SAndrew Jeffery #include <memory>
16e73bd0a1SAndrew Jeffery #include <optional>
17e73bd0a1SAndrew Jeffery #include <regex>
18e73bd0a1SAndrew Jeffery #include <span>
19e73bd0a1SAndrew Jeffery #include <string>
20e73bd0a1SAndrew Jeffery #include <tuple>
21e73bd0a1SAndrew Jeffery #include <utility>
22e73bd0a1SAndrew Jeffery #include <variant>
23e73bd0a1SAndrew Jeffery #include <vector>
24e73bd0a1SAndrew Jeffery 
25e73bd0a1SAndrew Jeffery const constexpr char* jsonStore = "/var/configuration/flattened.json";
26e73bd0a1SAndrew Jeffery const constexpr char* inventoryPath = "/xyz/openbmc_project/inventory";
27e73bd0a1SAndrew Jeffery const constexpr char* entityManagerName = "xyz.openbmc_project.EntityManager";
28e73bd0a1SAndrew Jeffery 
29e73bd0a1SAndrew Jeffery constexpr const char* cpuInventoryPath =
30e73bd0a1SAndrew Jeffery     "/xyz/openbmc_project/inventory/system/chassis/motherboard";
31e73bd0a1SAndrew Jeffery const std::regex illegalDbusRegex("[^A-Za-z0-9_]");
32e73bd0a1SAndrew Jeffery 
33e73bd0a1SAndrew Jeffery using BasicVariantType =
34e73bd0a1SAndrew Jeffery     std::variant<std::vector<std::string>, std::string, int64_t, uint64_t,
35e73bd0a1SAndrew Jeffery                  double, int32_t, uint32_t, int16_t, uint16_t, uint8_t, bool>;
36e73bd0a1SAndrew Jeffery using SensorBaseConfigMap =
37e73bd0a1SAndrew Jeffery     boost::container::flat_map<std::string, BasicVariantType>;
38e73bd0a1SAndrew Jeffery using SensorBaseConfiguration = std::pair<std::string, SensorBaseConfigMap>;
39e73bd0a1SAndrew Jeffery using SensorData = boost::container::flat_map<std::string, SensorBaseConfigMap>;
40e73bd0a1SAndrew Jeffery using ManagedObjectType =
41e73bd0a1SAndrew Jeffery     boost::container::flat_map<sdbusplus::message::object_path, SensorData>;
42e73bd0a1SAndrew Jeffery 
43e73bd0a1SAndrew Jeffery using GetSubTreeType = std::vector<
44e73bd0a1SAndrew Jeffery     std::pair<std::string,
45e73bd0a1SAndrew Jeffery               std::vector<std::pair<std::string, std::vector<std::string>>>>>;
46e73bd0a1SAndrew Jeffery using Association = std::tuple<std::string, std::string, std::string>;
47e73bd0a1SAndrew Jeffery 
48e73bd0a1SAndrew Jeffery inline std::string escapeName(const std::string& sensorName)
49e73bd0a1SAndrew Jeffery {
50e73bd0a1SAndrew Jeffery     return boost::replace_all_copy(sensorName, " ", "_");
51e73bd0a1SAndrew Jeffery }
52e73bd0a1SAndrew Jeffery 
53e73bd0a1SAndrew Jeffery enum class PowerState
54e73bd0a1SAndrew Jeffery {
55e73bd0a1SAndrew Jeffery     on,
56e73bd0a1SAndrew Jeffery     biosPost,
57e73bd0a1SAndrew Jeffery     always,
58e73bd0a1SAndrew Jeffery     chassisOn
59e73bd0a1SAndrew Jeffery };
60e73bd0a1SAndrew Jeffery 
61e73bd0a1SAndrew Jeffery std::optional<std::string> openAndRead(const std::string& hwmonFile);
62e73bd0a1SAndrew Jeffery std::optional<std::string>
63e73bd0a1SAndrew Jeffery     getFullHwmonFilePath(const std::string& directory,
64e73bd0a1SAndrew Jeffery                          const std::string& hwmonBaseName,
65e73bd0a1SAndrew Jeffery                          const std::set<std::string>& permitSet);
66e73bd0a1SAndrew Jeffery std::set<std::string> getPermitSet(const SensorBaseConfigMap& config);
67e73bd0a1SAndrew Jeffery bool findFiles(const std::filesystem::path& dirPath,
68e73bd0a1SAndrew Jeffery                std::string_view matchString,
69e73bd0a1SAndrew Jeffery                std::vector<std::filesystem::path>& foundPaths,
70e73bd0a1SAndrew Jeffery                int symlinkDepth = 1);
71*201a1015SEd Tanous bool isPowerOn();
72*201a1015SEd Tanous bool hasBiosPost();
73*201a1015SEd Tanous bool isChassisOn();
74e73bd0a1SAndrew Jeffery void setupPowerMatchCallback(
75e73bd0a1SAndrew Jeffery     const std::shared_ptr<sdbusplus::asio::connection>& conn,
76e73bd0a1SAndrew Jeffery     std::function<void(PowerState type, bool state)>&& callback);
77e73bd0a1SAndrew Jeffery void setupPowerMatch(const std::shared_ptr<sdbusplus::asio::connection>& conn);
78e73bd0a1SAndrew Jeffery bool getSensorConfiguration(
79e73bd0a1SAndrew Jeffery     const std::string& type,
80e73bd0a1SAndrew Jeffery     const std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
81e73bd0a1SAndrew Jeffery     ManagedObjectType& resp, bool useCache);
82e73bd0a1SAndrew Jeffery 
83e73bd0a1SAndrew Jeffery void createAssociation(
84e73bd0a1SAndrew Jeffery     std::shared_ptr<sdbusplus::asio::dbus_interface>& association,
85e73bd0a1SAndrew Jeffery     const std::string& path);
86e73bd0a1SAndrew Jeffery 
87e73bd0a1SAndrew Jeffery // replaces limits if MinReading and MaxReading are found.
88e73bd0a1SAndrew Jeffery void findLimits(std::pair<double, double>& limits,
89e73bd0a1SAndrew Jeffery                 const SensorBaseConfiguration* data);
90e73bd0a1SAndrew Jeffery 
91e73bd0a1SAndrew Jeffery bool readingStateGood(const PowerState& powerState);
92e73bd0a1SAndrew Jeffery 
93e73bd0a1SAndrew Jeffery constexpr const char* configInterfacePrefix =
94e73bd0a1SAndrew Jeffery     "xyz.openbmc_project.Configuration.";
95e73bd0a1SAndrew Jeffery 
96e73bd0a1SAndrew Jeffery inline std::string configInterfaceName(const std::string& type)
97e73bd0a1SAndrew Jeffery {
98e73bd0a1SAndrew Jeffery     return std::string(configInterfacePrefix) + type;
99e73bd0a1SAndrew Jeffery }
100e73bd0a1SAndrew Jeffery 
101e73bd0a1SAndrew Jeffery namespace mapper
102e73bd0a1SAndrew Jeffery {
103e73bd0a1SAndrew Jeffery constexpr const char* busName = "xyz.openbmc_project.ObjectMapper";
104e73bd0a1SAndrew Jeffery constexpr const char* path = "/xyz/openbmc_project/object_mapper";
105e73bd0a1SAndrew Jeffery constexpr const char* interface = "xyz.openbmc_project.ObjectMapper";
106e73bd0a1SAndrew Jeffery constexpr const char* subtree = "GetSubTree";
107e73bd0a1SAndrew Jeffery } // namespace mapper
108e73bd0a1SAndrew Jeffery 
109e73bd0a1SAndrew Jeffery namespace properties
110e73bd0a1SAndrew Jeffery {
111e73bd0a1SAndrew Jeffery constexpr const char* interface = "org.freedesktop.DBus.Properties";
112e73bd0a1SAndrew Jeffery constexpr const char* get = "Get";
113e73bd0a1SAndrew Jeffery constexpr const char* set = "Set";
114e73bd0a1SAndrew Jeffery } // namespace properties
115e73bd0a1SAndrew Jeffery 
116e73bd0a1SAndrew Jeffery namespace power
117e73bd0a1SAndrew Jeffery {
118e73bd0a1SAndrew Jeffery const static constexpr char* busname = "xyz.openbmc_project.State.Host";
119e73bd0a1SAndrew Jeffery const static constexpr char* interface = "xyz.openbmc_project.State.Host";
120e73bd0a1SAndrew Jeffery const static constexpr char* path = "/xyz/openbmc_project/state/host0";
121e73bd0a1SAndrew Jeffery const static constexpr char* property = "CurrentHostState";
122e73bd0a1SAndrew Jeffery } // namespace power
123e73bd0a1SAndrew Jeffery 
124e73bd0a1SAndrew Jeffery namespace chassis
125e73bd0a1SAndrew Jeffery {
126ea14f14aSPatrick Williams const static constexpr char* busname = "xyz.openbmc_project.State.Chassis0";
127e73bd0a1SAndrew Jeffery const static constexpr char* interface = "xyz.openbmc_project.State.Chassis";
128e73bd0a1SAndrew Jeffery const static constexpr char* path = "/xyz/openbmc_project/state/chassis0";
129e73bd0a1SAndrew Jeffery const static constexpr char* property = "CurrentPowerState";
130819eb323SThang Tran const static constexpr char* sOn = ".On";
131e73bd0a1SAndrew Jeffery } // namespace chassis
132e73bd0a1SAndrew Jeffery 
133e73bd0a1SAndrew Jeffery namespace post
134e73bd0a1SAndrew Jeffery {
135e73bd0a1SAndrew Jeffery const static constexpr char* busname =
136e73bd0a1SAndrew Jeffery     "xyz.openbmc_project.State.OperatingSystem";
137e73bd0a1SAndrew Jeffery const static constexpr char* interface =
138e73bd0a1SAndrew Jeffery     "xyz.openbmc_project.State.OperatingSystem.Status";
139e73bd0a1SAndrew Jeffery const static constexpr char* path = "/xyz/openbmc_project/state/os";
140e73bd0a1SAndrew Jeffery const static constexpr char* property = "OperatingSystemState";
141e73bd0a1SAndrew Jeffery } // namespace post
142e73bd0a1SAndrew Jeffery 
143e73bd0a1SAndrew Jeffery namespace association
144e73bd0a1SAndrew Jeffery {
145e73bd0a1SAndrew Jeffery const static constexpr char* interface =
146e73bd0a1SAndrew Jeffery     "xyz.openbmc_project.Association.Definitions";
147e73bd0a1SAndrew Jeffery } // namespace association
148e73bd0a1SAndrew Jeffery 
149e73bd0a1SAndrew Jeffery template <typename T>
150e73bd0a1SAndrew Jeffery inline T loadVariant(const SensorBaseConfigMap& data, const std::string& key)
151e73bd0a1SAndrew Jeffery {
152e73bd0a1SAndrew Jeffery     auto it = data.find(key);
153e73bd0a1SAndrew Jeffery     if (it == data.end())
154e73bd0a1SAndrew Jeffery     {
155e73bd0a1SAndrew Jeffery         std::cerr << "Configuration missing " << key << "\n";
156e73bd0a1SAndrew Jeffery         throw std::invalid_argument("Key Missing");
157e73bd0a1SAndrew Jeffery     }
158e73bd0a1SAndrew Jeffery     if constexpr (std::is_same_v<T, double>)
159e73bd0a1SAndrew Jeffery     {
160e73bd0a1SAndrew Jeffery         return std::visit(VariantToDoubleVisitor(), it->second);
161e73bd0a1SAndrew Jeffery     }
162e73bd0a1SAndrew Jeffery     else if constexpr (std::is_unsigned_v<T>)
163e73bd0a1SAndrew Jeffery     {
164e73bd0a1SAndrew Jeffery         return std::visit(VariantToUnsignedIntVisitor(), it->second);
165e73bd0a1SAndrew Jeffery     }
166e73bd0a1SAndrew Jeffery     else if constexpr (std::is_same_v<T, std::string>)
167e73bd0a1SAndrew Jeffery     {
168e73bd0a1SAndrew Jeffery         return std::visit(VariantToStringVisitor(), it->second);
169e73bd0a1SAndrew Jeffery     }
170e73bd0a1SAndrew Jeffery     else
171e73bd0a1SAndrew Jeffery     {
172e73bd0a1SAndrew Jeffery         static_assert(!std::is_same_v<T, T>, "Type Not Implemented");
173e73bd0a1SAndrew Jeffery     }
174e73bd0a1SAndrew Jeffery }
175e73bd0a1SAndrew Jeffery 
176e73bd0a1SAndrew Jeffery inline void setReadState(const std::string& str, PowerState& val)
177e73bd0a1SAndrew Jeffery {
178e73bd0a1SAndrew Jeffery     if (str == "On")
179e73bd0a1SAndrew Jeffery     {
180e73bd0a1SAndrew Jeffery         val = PowerState::on;
181e73bd0a1SAndrew Jeffery     }
182e73bd0a1SAndrew Jeffery     else if (str == "BiosPost")
183e73bd0a1SAndrew Jeffery     {
184e73bd0a1SAndrew Jeffery         val = PowerState::biosPost;
185e73bd0a1SAndrew Jeffery     }
186e73bd0a1SAndrew Jeffery     else if (str == "Always")
187e73bd0a1SAndrew Jeffery     {
188e73bd0a1SAndrew Jeffery         val = PowerState::always;
189e73bd0a1SAndrew Jeffery     }
190e73bd0a1SAndrew Jeffery     else if (str == "ChassisOn")
191e73bd0a1SAndrew Jeffery     {
192e73bd0a1SAndrew Jeffery         val = PowerState::chassisOn;
193e73bd0a1SAndrew Jeffery     }
194e73bd0a1SAndrew Jeffery }
195e73bd0a1SAndrew Jeffery 
196e73bd0a1SAndrew Jeffery inline PowerState getPowerState(const SensorBaseConfigMap& cfg)
197e73bd0a1SAndrew Jeffery {
198e73bd0a1SAndrew Jeffery     PowerState state = PowerState::always;
199e73bd0a1SAndrew Jeffery     auto findPowerState = cfg.find("PowerState");
200e73bd0a1SAndrew Jeffery     if (findPowerState != cfg.end())
201e73bd0a1SAndrew Jeffery     {
202779c96a2SPatrick Williams         std::string powerState = std::visit(VariantToStringVisitor(),
203779c96a2SPatrick Williams                                             findPowerState->second);
204e73bd0a1SAndrew Jeffery         setReadState(powerState, state);
205e73bd0a1SAndrew Jeffery     }
206e73bd0a1SAndrew Jeffery     return state;
207e73bd0a1SAndrew Jeffery }
208e73bd0a1SAndrew Jeffery 
209e73bd0a1SAndrew Jeffery inline float getPollRate(const SensorBaseConfigMap& cfg, float dflt)
210e73bd0a1SAndrew Jeffery {
211e73bd0a1SAndrew Jeffery     float pollRate = dflt;
212e73bd0a1SAndrew Jeffery     auto findPollRate = cfg.find("PollRate");
213e73bd0a1SAndrew Jeffery     if (findPollRate != cfg.end())
214e73bd0a1SAndrew Jeffery     {
215e73bd0a1SAndrew Jeffery         pollRate = std::visit(VariantToFloatVisitor(), findPollRate->second);
216e73bd0a1SAndrew Jeffery         if (!std::isfinite(pollRate) || pollRate <= 0.0F)
217e73bd0a1SAndrew Jeffery         {
218e73bd0a1SAndrew Jeffery             pollRate = dflt; // poll time invalid, fall back to default
219e73bd0a1SAndrew Jeffery         }
220e73bd0a1SAndrew Jeffery     }
221e73bd0a1SAndrew Jeffery     return pollRate;
222e73bd0a1SAndrew Jeffery }
223e73bd0a1SAndrew Jeffery 
224e73bd0a1SAndrew Jeffery inline void setLed(const std::shared_ptr<sdbusplus::asio::connection>& conn,
225e73bd0a1SAndrew Jeffery                    const std::string& name, bool on)
226e73bd0a1SAndrew Jeffery {
227e73bd0a1SAndrew Jeffery     conn->async_method_call(
228e73bd0a1SAndrew Jeffery         [name](const boost::system::error_code ec) {
229e73bd0a1SAndrew Jeffery         if (ec)
230e73bd0a1SAndrew Jeffery         {
231e73bd0a1SAndrew Jeffery             std::cerr << "Failed to set LED " << name << "\n";
232e73bd0a1SAndrew Jeffery         }
233e73bd0a1SAndrew Jeffery     },
234e73bd0a1SAndrew Jeffery         "xyz.openbmc_project.LED.GroupManager",
235e73bd0a1SAndrew Jeffery         "/xyz/openbmc_project/led/groups/" + name, properties::interface,
236e73bd0a1SAndrew Jeffery         properties::set, "xyz.openbmc_project.Led.Group", "Asserted",
237e73bd0a1SAndrew Jeffery         std::variant<bool>(on));
238e73bd0a1SAndrew Jeffery }
239e73bd0a1SAndrew Jeffery 
240e73bd0a1SAndrew Jeffery void createInventoryAssoc(
241e73bd0a1SAndrew Jeffery     const std::shared_ptr<sdbusplus::asio::connection>& conn,
242e73bd0a1SAndrew Jeffery     const std::shared_ptr<sdbusplus::asio::dbus_interface>& association,
243e73bd0a1SAndrew Jeffery     const std::string& path);
244e73bd0a1SAndrew Jeffery 
245e73bd0a1SAndrew Jeffery struct GetSensorConfiguration :
246e73bd0a1SAndrew Jeffery     std::enable_shared_from_this<GetSensorConfiguration>
247e73bd0a1SAndrew Jeffery {
248e73bd0a1SAndrew Jeffery     GetSensorConfiguration(
249e73bd0a1SAndrew Jeffery         std::shared_ptr<sdbusplus::asio::connection> connection,
250e73bd0a1SAndrew Jeffery         std::function<void(ManagedObjectType& resp)>&& callbackFunc) :
251e73bd0a1SAndrew Jeffery         dbusConnection(std::move(connection)),
252e73bd0a1SAndrew Jeffery         callback(std::move(callbackFunc))
253e73bd0a1SAndrew Jeffery     {}
254e73bd0a1SAndrew Jeffery 
255e73bd0a1SAndrew Jeffery     void getPath(const std::string& path, const std::string& interface,
256e73bd0a1SAndrew Jeffery                  const std::string& owner, size_t retries = 5)
257e73bd0a1SAndrew Jeffery     {
258e73bd0a1SAndrew Jeffery         if (retries > 5)
259e73bd0a1SAndrew Jeffery         {
260e73bd0a1SAndrew Jeffery             retries = 5;
261e73bd0a1SAndrew Jeffery         }
262e73bd0a1SAndrew Jeffery         std::shared_ptr<GetSensorConfiguration> self = shared_from_this();
263e73bd0a1SAndrew Jeffery 
264e73bd0a1SAndrew Jeffery         self->dbusConnection->async_method_call(
265e73bd0a1SAndrew Jeffery             [self, path, interface, owner, retries](
266e73bd0a1SAndrew Jeffery                 const boost::system::error_code ec, SensorBaseConfigMap& data) {
267e73bd0a1SAndrew Jeffery             if (ec)
268e73bd0a1SAndrew Jeffery             {
269e73bd0a1SAndrew Jeffery                 std::cerr << "Error getting " << path << ": retries left"
270e73bd0a1SAndrew Jeffery                           << retries - 1 << "\n";
271e73bd0a1SAndrew Jeffery                 if (retries == 0U)
272e73bd0a1SAndrew Jeffery                 {
273e73bd0a1SAndrew Jeffery                     return;
274e73bd0a1SAndrew Jeffery                 }
275e73bd0a1SAndrew Jeffery                 auto timer = std::make_shared<boost::asio::steady_timer>(
276e73bd0a1SAndrew Jeffery                     self->dbusConnection->get_io_context());
277e73bd0a1SAndrew Jeffery                 timer->expires_after(std::chrono::seconds(10));
278e73bd0a1SAndrew Jeffery                 timer->async_wait([self, timer, path, interface, owner,
279e73bd0a1SAndrew Jeffery                                    retries](boost::system::error_code ec) {
280e73bd0a1SAndrew Jeffery                     if (ec)
281e73bd0a1SAndrew Jeffery                     {
282e73bd0a1SAndrew Jeffery                         std::cerr << "Timer error!\n";
283e73bd0a1SAndrew Jeffery                         return;
284e73bd0a1SAndrew Jeffery                     }
285e73bd0a1SAndrew Jeffery                     self->getPath(path, interface, owner, retries - 1);
286e73bd0a1SAndrew Jeffery                 });
287e73bd0a1SAndrew Jeffery                 return;
288e73bd0a1SAndrew Jeffery             }
289e73bd0a1SAndrew Jeffery 
290e73bd0a1SAndrew Jeffery             self->respData[path][interface] = std::move(data);
291e73bd0a1SAndrew Jeffery         },
292e73bd0a1SAndrew Jeffery             owner, path, "org.freedesktop.DBus.Properties", "GetAll",
293e73bd0a1SAndrew Jeffery             interface);
294e73bd0a1SAndrew Jeffery     }
295e73bd0a1SAndrew Jeffery 
296e73bd0a1SAndrew Jeffery     void getConfiguration(const std::vector<std::string>& types,
297e73bd0a1SAndrew Jeffery                           size_t retries = 0)
298e73bd0a1SAndrew Jeffery     {
299e73bd0a1SAndrew Jeffery         if (retries > 5)
300e73bd0a1SAndrew Jeffery         {
301e73bd0a1SAndrew Jeffery             retries = 5;
302e73bd0a1SAndrew Jeffery         }
303e73bd0a1SAndrew Jeffery 
304e73bd0a1SAndrew Jeffery         std::vector<std::string> interfaces(types.size());
305e73bd0a1SAndrew Jeffery         for (const auto& type : types)
306e73bd0a1SAndrew Jeffery         {
307e73bd0a1SAndrew Jeffery             interfaces.push_back(configInterfaceName(type));
308e73bd0a1SAndrew Jeffery         }
309e73bd0a1SAndrew Jeffery 
310e73bd0a1SAndrew Jeffery         std::shared_ptr<GetSensorConfiguration> self = shared_from_this();
311e73bd0a1SAndrew Jeffery         dbusConnection->async_method_call(
312e73bd0a1SAndrew Jeffery             [self, interfaces, retries](const boost::system::error_code ec,
313e73bd0a1SAndrew Jeffery                                         const GetSubTreeType& ret) {
314e73bd0a1SAndrew Jeffery             if (ec)
315e73bd0a1SAndrew Jeffery             {
316e73bd0a1SAndrew Jeffery                 std::cerr << "Error calling mapper\n";
317e73bd0a1SAndrew Jeffery                 if (retries == 0U)
318e73bd0a1SAndrew Jeffery                 {
319e73bd0a1SAndrew Jeffery                     return;
320e73bd0a1SAndrew Jeffery                 }
321e73bd0a1SAndrew Jeffery                 auto timer = std::make_shared<boost::asio::steady_timer>(
322e73bd0a1SAndrew Jeffery                     self->dbusConnection->get_io_context());
323e73bd0a1SAndrew Jeffery                 timer->expires_after(std::chrono::seconds(10));
324e73bd0a1SAndrew Jeffery                 timer->async_wait([self, timer, interfaces,
325e73bd0a1SAndrew Jeffery                                    retries](boost::system::error_code ec) {
326e73bd0a1SAndrew Jeffery                     if (ec)
327e73bd0a1SAndrew Jeffery                     {
328e73bd0a1SAndrew Jeffery                         std::cerr << "Timer error!\n";
329e73bd0a1SAndrew Jeffery                         return;
330e73bd0a1SAndrew Jeffery                     }
331e73bd0a1SAndrew Jeffery                     self->getConfiguration(interfaces, retries - 1);
332e73bd0a1SAndrew Jeffery                 });
333e73bd0a1SAndrew Jeffery 
334e73bd0a1SAndrew Jeffery                 return;
335e73bd0a1SAndrew Jeffery             }
336e73bd0a1SAndrew Jeffery             for (const auto& [path, objDict] : ret)
337e73bd0a1SAndrew Jeffery             {
338e73bd0a1SAndrew Jeffery                 if (objDict.empty())
339e73bd0a1SAndrew Jeffery                 {
340e73bd0a1SAndrew Jeffery                     return;
341e73bd0a1SAndrew Jeffery                 }
342e73bd0a1SAndrew Jeffery                 const std::string& owner = objDict.begin()->first;
343e73bd0a1SAndrew Jeffery 
344e73bd0a1SAndrew Jeffery                 for (const std::string& interface : objDict.begin()->second)
345e73bd0a1SAndrew Jeffery                 {
346e73bd0a1SAndrew Jeffery                     // anything that starts with a requested configuration
347e73bd0a1SAndrew Jeffery                     // is good
348e73bd0a1SAndrew Jeffery                     if (std::find_if(interfaces.begin(), interfaces.end(),
349e73bd0a1SAndrew Jeffery                                      [interface](const std::string& possible) {
350e73bd0a1SAndrew Jeffery                         return interface.starts_with(possible);
351e73bd0a1SAndrew Jeffery                     }) == interfaces.end())
352e73bd0a1SAndrew Jeffery                     {
353e73bd0a1SAndrew Jeffery                         continue;
354e73bd0a1SAndrew Jeffery                     }
355e73bd0a1SAndrew Jeffery                     self->getPath(path, interface, owner);
356e73bd0a1SAndrew Jeffery                 }
357e73bd0a1SAndrew Jeffery             }
358e73bd0a1SAndrew Jeffery         },
359e73bd0a1SAndrew Jeffery             mapper::busName, mapper::path, mapper::interface, mapper::subtree,
360e73bd0a1SAndrew Jeffery             "/", 0, interfaces);
361e73bd0a1SAndrew Jeffery     }
362e73bd0a1SAndrew Jeffery 
363e73bd0a1SAndrew Jeffery     ~GetSensorConfiguration()
364e73bd0a1SAndrew Jeffery     {
365e73bd0a1SAndrew Jeffery         callback(respData);
366e73bd0a1SAndrew Jeffery     }
367e73bd0a1SAndrew Jeffery 
368e73bd0a1SAndrew Jeffery     std::shared_ptr<sdbusplus::asio::connection> dbusConnection;
369e73bd0a1SAndrew Jeffery     std::function<void(ManagedObjectType& resp)> callback;
370e73bd0a1SAndrew Jeffery     ManagedObjectType respData;
371e73bd0a1SAndrew Jeffery };
372e73bd0a1SAndrew Jeffery 
373e73bd0a1SAndrew Jeffery // The common scheme for sysfs files naming is: <type><number>_<item>.
374e73bd0a1SAndrew Jeffery // This function returns optionally these 3 elements as a tuple.
375e73bd0a1SAndrew Jeffery std::optional<std::tuple<std::string, std::string, std::string>>
376e73bd0a1SAndrew Jeffery     splitFileName(const std::filesystem::path& filePath);
377e73bd0a1SAndrew Jeffery std::optional<double> readFile(const std::string& thresholdFile,
378e73bd0a1SAndrew Jeffery                                const double& scaleFactor);
379e73bd0a1SAndrew Jeffery void setupManufacturingModeMatch(sdbusplus::asio::connection& conn);
380e73bd0a1SAndrew Jeffery bool getManufacturingMode();
381e73bd0a1SAndrew Jeffery std::vector<std::unique_ptr<sdbusplus::bus::match_t>>
382e73bd0a1SAndrew Jeffery     setupPropertiesChangedMatches(
383e73bd0a1SAndrew Jeffery         sdbusplus::asio::connection& bus, std::span<const char* const> types,
384e73bd0a1SAndrew Jeffery         const std::function<void(sdbusplus::message_t&)>& handler);
385278e177fSTom Tung 
386278e177fSTom Tung template <typename T>
387278e177fSTom Tung bool getDeviceBusAddr(const std::string& deviceName, T& bus, T& addr)
388278e177fSTom Tung {
389278e177fSTom Tung     auto findHyphen = deviceName.find('-');
390278e177fSTom Tung     if (findHyphen == std::string::npos)
391278e177fSTom Tung     {
392278e177fSTom Tung         std::cerr << "found bad device " << deviceName << "\n";
393278e177fSTom Tung         return false;
394278e177fSTom Tung     }
395278e177fSTom Tung     std::string busStr = deviceName.substr(0, findHyphen);
396278e177fSTom Tung     std::string addrStr = deviceName.substr(findHyphen + 1);
397278e177fSTom Tung 
398278e177fSTom Tung     std::from_chars_result res{};
399278e177fSTom Tung     res = std::from_chars(&*busStr.begin(), &*busStr.end(), bus);
400278e177fSTom Tung     if (res.ec != std::errc{} || res.ptr != &*busStr.end())
401278e177fSTom Tung     {
402278e177fSTom Tung         std::cerr << "Error finding bus for " << deviceName << "\n";
403278e177fSTom Tung         return false;
404278e177fSTom Tung     }
405278e177fSTom Tung     res = std::from_chars(&*addrStr.begin(), &*addrStr.end(), addr, 16);
406278e177fSTom Tung     if (res.ec != std::errc{} || res.ptr != &*addrStr.end())
407278e177fSTom Tung     {
408278e177fSTom Tung         std::cerr << "Error finding addr for " << deviceName << "\n";
409278e177fSTom Tung         return false;
410278e177fSTom Tung     }
411278e177fSTom Tung 
412278e177fSTom Tung     return true;
413278e177fSTom Tung }
414