xref: /openbmc/dbus-sensors/src/Utils.hpp (revision ef85e0bb)
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 
escapeName(const std::string & sensorName)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);
71201a1015SEd Tanous bool isPowerOn();
72201a1015SEd Tanous bool hasBiosPost();
73201a1015SEd 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 
configInterfaceName(const std::string & type)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 {
118*ef85e0bbSPotin Lai const static constexpr char* busname = "xyz.openbmc_project.State.Host0";
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 {
135*ef85e0bbSPotin Lai const static constexpr char* busname = "xyz.openbmc_project.State.Host0";
136e73bd0a1SAndrew Jeffery const static constexpr char* interface =
137e73bd0a1SAndrew Jeffery     "xyz.openbmc_project.State.OperatingSystem.Status";
138*ef85e0bbSPotin Lai const static constexpr char* path = "/xyz/openbmc_project/state/host0";
139e73bd0a1SAndrew Jeffery const static constexpr char* property = "OperatingSystemState";
140e73bd0a1SAndrew Jeffery } // namespace post
141e73bd0a1SAndrew Jeffery 
142e73bd0a1SAndrew Jeffery namespace association
143e73bd0a1SAndrew Jeffery {
144e73bd0a1SAndrew Jeffery const static constexpr char* interface =
145e73bd0a1SAndrew Jeffery     "xyz.openbmc_project.Association.Definitions";
146e73bd0a1SAndrew Jeffery } // namespace association
147e73bd0a1SAndrew Jeffery 
148e73bd0a1SAndrew Jeffery template <typename T>
loadVariant(const SensorBaseConfigMap & data,const std::string & key)149e73bd0a1SAndrew Jeffery inline T loadVariant(const SensorBaseConfigMap& data, const std::string& key)
150e73bd0a1SAndrew Jeffery {
151e73bd0a1SAndrew Jeffery     auto it = data.find(key);
152e73bd0a1SAndrew Jeffery     if (it == data.end())
153e73bd0a1SAndrew Jeffery     {
154e73bd0a1SAndrew Jeffery         std::cerr << "Configuration missing " << key << "\n";
155e73bd0a1SAndrew Jeffery         throw std::invalid_argument("Key Missing");
156e73bd0a1SAndrew Jeffery     }
157e73bd0a1SAndrew Jeffery     if constexpr (std::is_same_v<T, double>)
158e73bd0a1SAndrew Jeffery     {
159e73bd0a1SAndrew Jeffery         return std::visit(VariantToDoubleVisitor(), it->second);
160e73bd0a1SAndrew Jeffery     }
161e73bd0a1SAndrew Jeffery     else if constexpr (std::is_unsigned_v<T>)
162e73bd0a1SAndrew Jeffery     {
163e73bd0a1SAndrew Jeffery         return std::visit(VariantToUnsignedIntVisitor(), it->second);
164e73bd0a1SAndrew Jeffery     }
165e73bd0a1SAndrew Jeffery     else if constexpr (std::is_same_v<T, std::string>)
166e73bd0a1SAndrew Jeffery     {
167e73bd0a1SAndrew Jeffery         return std::visit(VariantToStringVisitor(), it->second);
168e73bd0a1SAndrew Jeffery     }
169e73bd0a1SAndrew Jeffery     else
170e73bd0a1SAndrew Jeffery     {
171e73bd0a1SAndrew Jeffery         static_assert(!std::is_same_v<T, T>, "Type Not Implemented");
172e73bd0a1SAndrew Jeffery     }
173e73bd0a1SAndrew Jeffery }
174e73bd0a1SAndrew Jeffery 
setReadState(const std::string & str,PowerState & val)175e73bd0a1SAndrew Jeffery inline void setReadState(const std::string& str, PowerState& val)
176e73bd0a1SAndrew Jeffery {
177e73bd0a1SAndrew Jeffery     if (str == "On")
178e73bd0a1SAndrew Jeffery     {
179e73bd0a1SAndrew Jeffery         val = PowerState::on;
180e73bd0a1SAndrew Jeffery     }
181e73bd0a1SAndrew Jeffery     else if (str == "BiosPost")
182e73bd0a1SAndrew Jeffery     {
183e73bd0a1SAndrew Jeffery         val = PowerState::biosPost;
184e73bd0a1SAndrew Jeffery     }
185e73bd0a1SAndrew Jeffery     else if (str == "Always")
186e73bd0a1SAndrew Jeffery     {
187e73bd0a1SAndrew Jeffery         val = PowerState::always;
188e73bd0a1SAndrew Jeffery     }
189e73bd0a1SAndrew Jeffery     else if (str == "ChassisOn")
190e73bd0a1SAndrew Jeffery     {
191e73bd0a1SAndrew Jeffery         val = PowerState::chassisOn;
192e73bd0a1SAndrew Jeffery     }
193e73bd0a1SAndrew Jeffery }
194e73bd0a1SAndrew Jeffery 
getPowerState(const SensorBaseConfigMap & cfg)195e73bd0a1SAndrew Jeffery inline PowerState getPowerState(const SensorBaseConfigMap& cfg)
196e73bd0a1SAndrew Jeffery {
197e73bd0a1SAndrew Jeffery     PowerState state = PowerState::always;
198e73bd0a1SAndrew Jeffery     auto findPowerState = cfg.find("PowerState");
199e73bd0a1SAndrew Jeffery     if (findPowerState != cfg.end())
200e73bd0a1SAndrew Jeffery     {
201779c96a2SPatrick Williams         std::string powerState = std::visit(VariantToStringVisitor(),
202779c96a2SPatrick Williams                                             findPowerState->second);
203e73bd0a1SAndrew Jeffery         setReadState(powerState, state);
204e73bd0a1SAndrew Jeffery     }
205e73bd0a1SAndrew Jeffery     return state;
206e73bd0a1SAndrew Jeffery }
207e73bd0a1SAndrew Jeffery 
getPollRate(const SensorBaseConfigMap & cfg,float dflt)208e73bd0a1SAndrew Jeffery inline float getPollRate(const SensorBaseConfigMap& cfg, float dflt)
209e73bd0a1SAndrew Jeffery {
210e73bd0a1SAndrew Jeffery     float pollRate = dflt;
211e73bd0a1SAndrew Jeffery     auto findPollRate = cfg.find("PollRate");
212e73bd0a1SAndrew Jeffery     if (findPollRate != cfg.end())
213e73bd0a1SAndrew Jeffery     {
214e73bd0a1SAndrew Jeffery         pollRate = std::visit(VariantToFloatVisitor(), findPollRate->second);
215e73bd0a1SAndrew Jeffery         if (!std::isfinite(pollRate) || pollRate <= 0.0F)
216e73bd0a1SAndrew Jeffery         {
217e73bd0a1SAndrew Jeffery             pollRate = dflt; // poll time invalid, fall back to default
218e73bd0a1SAndrew Jeffery         }
219e73bd0a1SAndrew Jeffery     }
220e73bd0a1SAndrew Jeffery     return pollRate;
221e73bd0a1SAndrew Jeffery }
222e73bd0a1SAndrew Jeffery 
setLed(const std::shared_ptr<sdbusplus::asio::connection> & conn,const std::string & name,bool on)223e73bd0a1SAndrew Jeffery inline void setLed(const std::shared_ptr<sdbusplus::asio::connection>& conn,
224e73bd0a1SAndrew Jeffery                    const std::string& name, bool on)
225e73bd0a1SAndrew Jeffery {
226e73bd0a1SAndrew Jeffery     conn->async_method_call(
227e73bd0a1SAndrew Jeffery         [name](const boost::system::error_code ec) {
228e73bd0a1SAndrew Jeffery         if (ec)
229e73bd0a1SAndrew Jeffery         {
230e73bd0a1SAndrew Jeffery             std::cerr << "Failed to set LED " << name << "\n";
231e73bd0a1SAndrew Jeffery         }
232e73bd0a1SAndrew Jeffery     },
233e73bd0a1SAndrew Jeffery         "xyz.openbmc_project.LED.GroupManager",
234e73bd0a1SAndrew Jeffery         "/xyz/openbmc_project/led/groups/" + name, properties::interface,
235e73bd0a1SAndrew Jeffery         properties::set, "xyz.openbmc_project.Led.Group", "Asserted",
236e73bd0a1SAndrew Jeffery         std::variant<bool>(on));
237e73bd0a1SAndrew Jeffery }
238e73bd0a1SAndrew Jeffery 
239e73bd0a1SAndrew Jeffery void createInventoryAssoc(
240e73bd0a1SAndrew Jeffery     const std::shared_ptr<sdbusplus::asio::connection>& conn,
241e73bd0a1SAndrew Jeffery     const std::shared_ptr<sdbusplus::asio::dbus_interface>& association,
242e73bd0a1SAndrew Jeffery     const std::string& path);
243e73bd0a1SAndrew Jeffery 
244e73bd0a1SAndrew Jeffery struct GetSensorConfiguration :
245e73bd0a1SAndrew Jeffery     std::enable_shared_from_this<GetSensorConfiguration>
246e73bd0a1SAndrew Jeffery {
GetSensorConfigurationGetSensorConfiguration247e73bd0a1SAndrew Jeffery     GetSensorConfiguration(
248e73bd0a1SAndrew Jeffery         std::shared_ptr<sdbusplus::asio::connection> connection,
249e73bd0a1SAndrew Jeffery         std::function<void(ManagedObjectType& resp)>&& callbackFunc) :
250e73bd0a1SAndrew Jeffery         dbusConnection(std::move(connection)),
251e73bd0a1SAndrew Jeffery         callback(std::move(callbackFunc))
252e73bd0a1SAndrew Jeffery     {}
253e73bd0a1SAndrew Jeffery 
getPathGetSensorConfiguration254e73bd0a1SAndrew Jeffery     void getPath(const std::string& path, const std::string& interface,
255e73bd0a1SAndrew Jeffery                  const std::string& owner, size_t retries = 5)
256e73bd0a1SAndrew Jeffery     {
257e73bd0a1SAndrew Jeffery         if (retries > 5)
258e73bd0a1SAndrew Jeffery         {
259e73bd0a1SAndrew Jeffery             retries = 5;
260e73bd0a1SAndrew Jeffery         }
261e73bd0a1SAndrew Jeffery         std::shared_ptr<GetSensorConfiguration> self = shared_from_this();
262e73bd0a1SAndrew Jeffery 
263e73bd0a1SAndrew Jeffery         self->dbusConnection->async_method_call(
264e73bd0a1SAndrew Jeffery             [self, path, interface, owner, retries](
265e73bd0a1SAndrew Jeffery                 const boost::system::error_code ec, SensorBaseConfigMap& data) {
266e73bd0a1SAndrew Jeffery             if (ec)
267e73bd0a1SAndrew Jeffery             {
268e73bd0a1SAndrew Jeffery                 std::cerr << "Error getting " << path << ": retries left"
269e73bd0a1SAndrew Jeffery                           << retries - 1 << "\n";
270e73bd0a1SAndrew Jeffery                 if (retries == 0U)
271e73bd0a1SAndrew Jeffery                 {
272e73bd0a1SAndrew Jeffery                     return;
273e73bd0a1SAndrew Jeffery                 }
274e73bd0a1SAndrew Jeffery                 auto timer = std::make_shared<boost::asio::steady_timer>(
275e73bd0a1SAndrew Jeffery                     self->dbusConnection->get_io_context());
276e73bd0a1SAndrew Jeffery                 timer->expires_after(std::chrono::seconds(10));
277e73bd0a1SAndrew Jeffery                 timer->async_wait([self, timer, path, interface, owner,
278e73bd0a1SAndrew Jeffery                                    retries](boost::system::error_code ec) {
279e73bd0a1SAndrew Jeffery                     if (ec)
280e73bd0a1SAndrew Jeffery                     {
281e73bd0a1SAndrew Jeffery                         std::cerr << "Timer error!\n";
282e73bd0a1SAndrew Jeffery                         return;
283e73bd0a1SAndrew Jeffery                     }
284e73bd0a1SAndrew Jeffery                     self->getPath(path, interface, owner, retries - 1);
285e73bd0a1SAndrew Jeffery                 });
286e73bd0a1SAndrew Jeffery                 return;
287e73bd0a1SAndrew Jeffery             }
288e73bd0a1SAndrew Jeffery 
289e73bd0a1SAndrew Jeffery             self->respData[path][interface] = std::move(data);
290e73bd0a1SAndrew Jeffery         },
291e73bd0a1SAndrew Jeffery             owner, path, "org.freedesktop.DBus.Properties", "GetAll",
292e73bd0a1SAndrew Jeffery             interface);
293e73bd0a1SAndrew Jeffery     }
294e73bd0a1SAndrew Jeffery 
getConfigurationGetSensorConfiguration295e73bd0a1SAndrew Jeffery     void getConfiguration(const std::vector<std::string>& types,
296e73bd0a1SAndrew Jeffery                           size_t retries = 0)
297e73bd0a1SAndrew Jeffery     {
298e73bd0a1SAndrew Jeffery         if (retries > 5)
299e73bd0a1SAndrew Jeffery         {
300e73bd0a1SAndrew Jeffery             retries = 5;
301e73bd0a1SAndrew Jeffery         }
302e73bd0a1SAndrew Jeffery 
303e73bd0a1SAndrew Jeffery         std::vector<std::string> interfaces(types.size());
304e73bd0a1SAndrew Jeffery         for (const auto& type : types)
305e73bd0a1SAndrew Jeffery         {
306e73bd0a1SAndrew Jeffery             interfaces.push_back(configInterfaceName(type));
307e73bd0a1SAndrew Jeffery         }
308e73bd0a1SAndrew Jeffery 
309e73bd0a1SAndrew Jeffery         std::shared_ptr<GetSensorConfiguration> self = shared_from_this();
310e73bd0a1SAndrew Jeffery         dbusConnection->async_method_call(
311e73bd0a1SAndrew Jeffery             [self, interfaces, retries](const boost::system::error_code ec,
312e73bd0a1SAndrew Jeffery                                         const GetSubTreeType& ret) {
313e73bd0a1SAndrew Jeffery             if (ec)
314e73bd0a1SAndrew Jeffery             {
315e73bd0a1SAndrew Jeffery                 std::cerr << "Error calling mapper\n";
316e73bd0a1SAndrew Jeffery                 if (retries == 0U)
317e73bd0a1SAndrew Jeffery                 {
318e73bd0a1SAndrew Jeffery                     return;
319e73bd0a1SAndrew Jeffery                 }
320e73bd0a1SAndrew Jeffery                 auto timer = std::make_shared<boost::asio::steady_timer>(
321e73bd0a1SAndrew Jeffery                     self->dbusConnection->get_io_context());
322e73bd0a1SAndrew Jeffery                 timer->expires_after(std::chrono::seconds(10));
323e73bd0a1SAndrew Jeffery                 timer->async_wait([self, timer, interfaces,
324e73bd0a1SAndrew Jeffery                                    retries](boost::system::error_code ec) {
325e73bd0a1SAndrew Jeffery                     if (ec)
326e73bd0a1SAndrew Jeffery                     {
327e73bd0a1SAndrew Jeffery                         std::cerr << "Timer error!\n";
328e73bd0a1SAndrew Jeffery                         return;
329e73bd0a1SAndrew Jeffery                     }
330e73bd0a1SAndrew Jeffery                     self->getConfiguration(interfaces, retries - 1);
331e73bd0a1SAndrew Jeffery                 });
332e73bd0a1SAndrew Jeffery 
333e73bd0a1SAndrew Jeffery                 return;
334e73bd0a1SAndrew Jeffery             }
335e73bd0a1SAndrew Jeffery             for (const auto& [path, objDict] : ret)
336e73bd0a1SAndrew Jeffery             {
337e73bd0a1SAndrew Jeffery                 if (objDict.empty())
338e73bd0a1SAndrew Jeffery                 {
339e73bd0a1SAndrew Jeffery                     return;
340e73bd0a1SAndrew Jeffery                 }
341e73bd0a1SAndrew Jeffery                 const std::string& owner = objDict.begin()->first;
342e73bd0a1SAndrew Jeffery 
343e73bd0a1SAndrew Jeffery                 for (const std::string& interface : objDict.begin()->second)
344e73bd0a1SAndrew Jeffery                 {
345e73bd0a1SAndrew Jeffery                     // anything that starts with a requested configuration
346e73bd0a1SAndrew Jeffery                     // is good
347e73bd0a1SAndrew Jeffery                     if (std::find_if(interfaces.begin(), interfaces.end(),
348e73bd0a1SAndrew Jeffery                                      [interface](const std::string& possible) {
349e73bd0a1SAndrew Jeffery                         return interface.starts_with(possible);
350e73bd0a1SAndrew Jeffery                     }) == interfaces.end())
351e73bd0a1SAndrew Jeffery                     {
352e73bd0a1SAndrew Jeffery                         continue;
353e73bd0a1SAndrew Jeffery                     }
354e73bd0a1SAndrew Jeffery                     self->getPath(path, interface, owner);
355e73bd0a1SAndrew Jeffery                 }
356e73bd0a1SAndrew Jeffery             }
357e73bd0a1SAndrew Jeffery         },
358e73bd0a1SAndrew Jeffery             mapper::busName, mapper::path, mapper::interface, mapper::subtree,
359e73bd0a1SAndrew Jeffery             "/", 0, interfaces);
360e73bd0a1SAndrew Jeffery     }
361e73bd0a1SAndrew Jeffery 
~GetSensorConfigurationGetSensorConfiguration362e73bd0a1SAndrew Jeffery     ~GetSensorConfiguration()
363e73bd0a1SAndrew Jeffery     {
364e73bd0a1SAndrew Jeffery         callback(respData);
365e73bd0a1SAndrew Jeffery     }
366e73bd0a1SAndrew Jeffery 
367e73bd0a1SAndrew Jeffery     std::shared_ptr<sdbusplus::asio::connection> dbusConnection;
368e73bd0a1SAndrew Jeffery     std::function<void(ManagedObjectType& resp)> callback;
369e73bd0a1SAndrew Jeffery     ManagedObjectType respData;
370e73bd0a1SAndrew Jeffery };
371e73bd0a1SAndrew Jeffery 
372e73bd0a1SAndrew Jeffery // The common scheme for sysfs files naming is: <type><number>_<item>.
373e73bd0a1SAndrew Jeffery // This function returns optionally these 3 elements as a tuple.
374e73bd0a1SAndrew Jeffery std::optional<std::tuple<std::string, std::string, std::string>>
375e73bd0a1SAndrew Jeffery     splitFileName(const std::filesystem::path& filePath);
376e73bd0a1SAndrew Jeffery std::optional<double> readFile(const std::string& thresholdFile,
377e73bd0a1SAndrew Jeffery                                const double& scaleFactor);
378e73bd0a1SAndrew Jeffery void setupManufacturingModeMatch(sdbusplus::asio::connection& conn);
379e73bd0a1SAndrew Jeffery bool getManufacturingMode();
380e73bd0a1SAndrew Jeffery std::vector<std::unique_ptr<sdbusplus::bus::match_t>>
381e73bd0a1SAndrew Jeffery     setupPropertiesChangedMatches(
382e73bd0a1SAndrew Jeffery         sdbusplus::asio::connection& bus, std::span<const char* const> types,
383e73bd0a1SAndrew Jeffery         const std::function<void(sdbusplus::message_t&)>& handler);
384278e177fSTom Tung 
385278e177fSTom Tung template <typename T>
getDeviceBusAddr(const std::string & deviceName,T & bus,T & addr)386278e177fSTom Tung bool getDeviceBusAddr(const std::string& deviceName, T& bus, T& addr)
387278e177fSTom Tung {
388278e177fSTom Tung     auto findHyphen = deviceName.find('-');
389278e177fSTom Tung     if (findHyphen == std::string::npos)
390278e177fSTom Tung     {
391278e177fSTom Tung         std::cerr << "found bad device " << deviceName << "\n";
392278e177fSTom Tung         return false;
393278e177fSTom Tung     }
394278e177fSTom Tung     std::string busStr = deviceName.substr(0, findHyphen);
395278e177fSTom Tung     std::string addrStr = deviceName.substr(findHyphen + 1);
396278e177fSTom Tung 
397278e177fSTom Tung     std::from_chars_result res{};
398278e177fSTom Tung     res = std::from_chars(&*busStr.begin(), &*busStr.end(), bus);
399278e177fSTom Tung     if (res.ec != std::errc{} || res.ptr != &*busStr.end())
400278e177fSTom Tung     {
401278e177fSTom Tung         std::cerr << "Error finding bus for " << deviceName << "\n";
402278e177fSTom Tung         return false;
403278e177fSTom Tung     }
404278e177fSTom Tung     res = std::from_chars(&*addrStr.begin(), &*addrStr.end(), addr, 16);
405278e177fSTom Tung     if (res.ec != std::errc{} || res.ptr != &*addrStr.end())
406278e177fSTom Tung     {
407278e177fSTom Tung         std::cerr << "Error finding addr for " << deviceName << "\n";
408278e177fSTom Tung         return false;
409278e177fSTom Tung     }
410278e177fSTom Tung 
411278e177fSTom Tung     return true;
412278e177fSTom Tung }
413