xref: /openbmc/intel-ipmi-oem/include/sdrutils.hpp (revision fcd2d3a943c4fb518d399d8a0addd1cc661e5628)
13f7c5e40SJason M. Bills /*
23f7c5e40SJason M. Bills // Copyright (c) 2018 Intel Corporation
33f7c5e40SJason M. Bills //
43f7c5e40SJason M. Bills // Licensed under the Apache License, Version 2.0 (the "License");
53f7c5e40SJason M. Bills // you may not use this file except in compliance with the License.
63f7c5e40SJason M. Bills // You may obtain a copy of the License at
73f7c5e40SJason M. Bills //
83f7c5e40SJason M. Bills //      http://www.apache.org/licenses/LICENSE-2.0
93f7c5e40SJason M. Bills //
103f7c5e40SJason M. Bills // Unless required by applicable law or agreed to in writing, software
113f7c5e40SJason M. Bills // distributed under the License is distributed on an "AS IS" BASIS,
123f7c5e40SJason M. Bills // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133f7c5e40SJason M. Bills // See the License for the specific language governing permissions and
143f7c5e40SJason M. Bills // limitations under the License.
153f7c5e40SJason M. Bills */
163f7c5e40SJason M. Bills 
17262276f4SPatrick Venture #include "commandutils.hpp"
18262276f4SPatrick Venture 
193f7c5e40SJason M. Bills #include <boost/algorithm/string.hpp>
20a9423b6eSJason M. Bills #include <boost/bimap.hpp>
213f7c5e40SJason M. Bills #include <boost/container/flat_map.hpp>
22*fcd2d3a9SJames Feist #include <phosphor-logging/log.hpp>
23*fcd2d3a9SJames Feist #include <sdbusplus/bus/match.hpp>
24*fcd2d3a9SJames Feist 
25262276f4SPatrick Venture #include <cstdio>
263f7c5e40SJason M. Bills #include <cstring>
27262276f4SPatrick Venture #include <exception>
28262276f4SPatrick Venture #include <filesystem>
29262276f4SPatrick Venture #include <map>
30262276f4SPatrick Venture #include <string>
31262276f4SPatrick Venture #include <vector>
323f7c5e40SJason M. Bills 
333f7c5e40SJason M. Bills #pragma once
343f7c5e40SJason M. Bills 
353f7c5e40SJason M. Bills struct CmpStrVersion
363f7c5e40SJason M. Bills {
373f7c5e40SJason M. Bills     bool operator()(std::string a, std::string b) const
383f7c5e40SJason M. Bills     {
393f7c5e40SJason M. Bills         return strverscmp(a.c_str(), b.c_str()) < 0;
403f7c5e40SJason M. Bills     }
413f7c5e40SJason M. Bills };
423f7c5e40SJason M. Bills 
433f7c5e40SJason M. Bills using SensorSubTree = boost::container::flat_map<
443f7c5e40SJason M. Bills     std::string,
453f7c5e40SJason M. Bills     boost::container::flat_map<std::string, std::vector<std::string>>,
463f7c5e40SJason M. Bills     CmpStrVersion>;
473f7c5e40SJason M. Bills 
48a9423b6eSJason M. Bills using SensorNumMap = boost::bimap<int, std::string>;
49a9423b6eSJason M. Bills 
50a9423b6eSJason M. Bills namespace details
513f7c5e40SJason M. Bills {
52a9423b6eSJason M. Bills inline static bool getSensorSubtree(std::shared_ptr<SensorSubTree>& subtree)
53a9423b6eSJason M. Bills {
54a9423b6eSJason M. Bills     static std::shared_ptr<SensorSubTree> sensorTreePtr;
553f7c5e40SJason M. Bills     sd_bus* bus = NULL;
563f7c5e40SJason M. Bills     int ret = sd_bus_default_system(&bus);
573f7c5e40SJason M. Bills     if (ret < 0)
583f7c5e40SJason M. Bills     {
593f7c5e40SJason M. Bills         phosphor::logging::log<phosphor::logging::level::ERR>(
603f7c5e40SJason M. Bills             "Failed to connect to system bus",
613f7c5e40SJason M. Bills             phosphor::logging::entry("ERRNO=0x%X", -ret));
623f7c5e40SJason M. Bills         sd_bus_unref(bus);
633f7c5e40SJason M. Bills         return false;
643f7c5e40SJason M. Bills     }
653f7c5e40SJason M. Bills     sdbusplus::bus::bus dbus(bus);
66a9423b6eSJason M. Bills     static sdbusplus::bus::match::match sensorAdded(
67a9423b6eSJason M. Bills         dbus,
68a9423b6eSJason M. Bills         "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/"
69a9423b6eSJason M. Bills         "sensors/'",
70a9423b6eSJason M. Bills         [](sdbusplus::message::message& m) { sensorTreePtr.reset(); });
71a9423b6eSJason M. Bills 
72a9423b6eSJason M. Bills     static sdbusplus::bus::match::match sensorRemoved(
73a9423b6eSJason M. Bills         dbus,
74a9423b6eSJason M. Bills         "type='signal',member='InterfacesRemoved',arg0path='/xyz/"
75a9423b6eSJason M. Bills         "openbmc_project/sensors/'",
76a9423b6eSJason M. Bills         [](sdbusplus::message::message& m) { sensorTreePtr.reset(); });
77a9423b6eSJason M. Bills 
78a9423b6eSJason M. Bills     bool sensorTreeUpdated = false;
79a9423b6eSJason M. Bills     if (sensorTreePtr)
80a9423b6eSJason M. Bills     {
81a9423b6eSJason M. Bills         subtree = sensorTreePtr;
82a9423b6eSJason M. Bills         return sensorTreeUpdated;
83a9423b6eSJason M. Bills     }
84a9423b6eSJason M. Bills 
85a9423b6eSJason M. Bills     sensorTreePtr = std::make_shared<SensorSubTree>();
86a9423b6eSJason M. Bills 
873f7c5e40SJason M. Bills     auto mapperCall =
883f7c5e40SJason M. Bills         dbus.new_method_call("xyz.openbmc_project.ObjectMapper",
893f7c5e40SJason M. Bills                              "/xyz/openbmc_project/object_mapper",
903f7c5e40SJason M. Bills                              "xyz.openbmc_project.ObjectMapper", "GetSubTree");
9152341e85SJason M. Bills     static constexpr const auto depth = 2;
923f7c5e40SJason M. Bills     static constexpr std::array<const char*, 3> interfaces = {
933f7c5e40SJason M. Bills         "xyz.openbmc_project.Sensor.Value",
943f7c5e40SJason M. Bills         "xyz.openbmc_project.Sensor.Threshold.Warning",
953f7c5e40SJason M. Bills         "xyz.openbmc_project.Sensor.Threshold.Critical"};
963f7c5e40SJason M. Bills     mapperCall.append("/xyz/openbmc_project/sensors", depth, interfaces);
973f7c5e40SJason M. Bills 
983f7c5e40SJason M. Bills     try
993f7c5e40SJason M. Bills     {
1003f7c5e40SJason M. Bills         auto mapperReply = dbus.call(mapperCall);
101a9423b6eSJason M. Bills         mapperReply.read(*sensorTreePtr);
1023f7c5e40SJason M. Bills     }
10352341e85SJason M. Bills     catch (sdbusplus::exception_t& e)
1043f7c5e40SJason M. Bills     {
10552341e85SJason M. Bills         phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
106a9423b6eSJason M. Bills         return sensorTreeUpdated;
107a9423b6eSJason M. Bills     }
108a9423b6eSJason M. Bills     subtree = sensorTreePtr;
109a9423b6eSJason M. Bills     sensorTreeUpdated = true;
110a9423b6eSJason M. Bills     return sensorTreeUpdated;
111a9423b6eSJason M. Bills }
112a9423b6eSJason M. Bills 
113a9423b6eSJason M. Bills inline static bool getSensorNumMap(std::shared_ptr<SensorNumMap>& sensorNumMap)
114a9423b6eSJason M. Bills {
115a9423b6eSJason M. Bills     static std::shared_ptr<SensorNumMap> sensorNumMapPtr;
116a9423b6eSJason M. Bills     bool sensorNumMapUpated = false;
117a9423b6eSJason M. Bills 
118a9423b6eSJason M. Bills     std::shared_ptr<SensorSubTree> sensorTree;
119a9423b6eSJason M. Bills     bool sensorTreeUpdated = details::getSensorSubtree(sensorTree);
120a9423b6eSJason M. Bills     if (!sensorTree)
121a9423b6eSJason M. Bills     {
122a9423b6eSJason M. Bills         return sensorNumMapUpated;
123a9423b6eSJason M. Bills     }
124a9423b6eSJason M. Bills 
125a9423b6eSJason M. Bills     if (!sensorTreeUpdated && sensorNumMapPtr)
126a9423b6eSJason M. Bills     {
127a9423b6eSJason M. Bills         sensorNumMap = sensorNumMapPtr;
128a9423b6eSJason M. Bills         return sensorNumMapUpated;
129a9423b6eSJason M. Bills     }
130a9423b6eSJason M. Bills 
131a9423b6eSJason M. Bills     sensorNumMapPtr = std::make_shared<SensorNumMap>();
132a9423b6eSJason M. Bills 
133caed905dSJason M. Bills     uint8_t sensorNum = 0;
134a9423b6eSJason M. Bills     for (const auto& sensor : *sensorTree)
135a9423b6eSJason M. Bills     {
136a9423b6eSJason M. Bills         sensorNumMapPtr->insert(
137a9423b6eSJason M. Bills             SensorNumMap::value_type(sensorNum++, sensor.first));
138a9423b6eSJason M. Bills     }
139a9423b6eSJason M. Bills     sensorNumMap = sensorNumMapPtr;
140a9423b6eSJason M. Bills     sensorNumMapUpated = true;
141a9423b6eSJason M. Bills     return sensorNumMapUpated;
142a9423b6eSJason M. Bills }
143a9423b6eSJason M. Bills } // namespace details
144a9423b6eSJason M. Bills 
145a9423b6eSJason M. Bills inline static bool getSensorSubtree(SensorSubTree& subtree)
146a9423b6eSJason M. Bills {
147a9423b6eSJason M. Bills     std::shared_ptr<SensorSubTree> sensorTree;
148a9423b6eSJason M. Bills     details::getSensorSubtree(sensorTree);
149a9423b6eSJason M. Bills     if (!sensorTree)
150a9423b6eSJason M. Bills     {
1513f7c5e40SJason M. Bills         return false;
1523f7c5e40SJason M. Bills     }
153a9423b6eSJason M. Bills 
154a9423b6eSJason M. Bills     subtree = *sensorTree;
1553f7c5e40SJason M. Bills     return true;
1563f7c5e40SJason M. Bills }
1573f7c5e40SJason M. Bills 
1583f7c5e40SJason M. Bills struct CmpStr
1593f7c5e40SJason M. Bills {
1603f7c5e40SJason M. Bills     bool operator()(const char* a, const char* b) const
1613f7c5e40SJason M. Bills     {
1623f7c5e40SJason M. Bills         return std::strcmp(a, b) < 0;
1633f7c5e40SJason M. Bills     }
1643f7c5e40SJason M. Bills };
1653f7c5e40SJason M. Bills 
16652341e85SJason M. Bills enum class SensorTypeCodes : uint8_t
16752341e85SJason M. Bills {
16852341e85SJason M. Bills     reserved = 0x0,
16952341e85SJason M. Bills     temperature = 0x1,
17052341e85SJason M. Bills     voltage = 0x2,
17152341e85SJason M. Bills     current = 0x3,
17252341e85SJason M. Bills     fan = 0x4,
17352341e85SJason M. Bills     other = 0xB,
17452341e85SJason M. Bills };
17552341e85SJason M. Bills 
1763f7c5e40SJason M. Bills const static boost::container::flat_map<const char*, SensorTypeCodes, CmpStr>
1773f7c5e40SJason M. Bills     sensorTypes{{{"temperature", SensorTypeCodes::temperature},
1783f7c5e40SJason M. Bills                  {"voltage", SensorTypeCodes::voltage},
1793f7c5e40SJason M. Bills                  {"current", SensorTypeCodes::current},
1803f7c5e40SJason M. Bills                  {"fan_tach", SensorTypeCodes::fan},
181f426f334SJames Feist                  {"fan_pwm", SensorTypeCodes::fan},
1823f7c5e40SJason M. Bills                  {"power", SensorTypeCodes::other}}};
1833f7c5e40SJason M. Bills 
1843f7c5e40SJason M. Bills inline static std::string getSensorTypeStringFromPath(const std::string& path)
1853f7c5e40SJason M. Bills {
1863f7c5e40SJason M. Bills     // get sensor type string from path, path is defined as
1873f7c5e40SJason M. Bills     // /xyz/openbmc_project/sensors/<type>/label
1883f7c5e40SJason M. Bills     size_t typeEnd = path.rfind("/");
189360f593bSJason M. Bills     if (typeEnd == std::string::npos)
1903f7c5e40SJason M. Bills     {
1913f7c5e40SJason M. Bills         return path;
1923f7c5e40SJason M. Bills     }
193360f593bSJason M. Bills     size_t typeStart = path.rfind("/", typeEnd - 1);
194360f593bSJason M. Bills     if (typeStart == std::string::npos)
195360f593bSJason M. Bills     {
196360f593bSJason M. Bills         return path;
197360f593bSJason M. Bills     }
198360f593bSJason M. Bills     // Start at the character after the '/'
199360f593bSJason M. Bills     typeStart++;
200360f593bSJason M. Bills     return path.substr(typeStart, typeEnd - typeStart);
201360f593bSJason M. Bills }
2023f7c5e40SJason M. Bills 
2033f7c5e40SJason M. Bills inline static uint8_t getSensorTypeFromPath(const std::string& path)
2043f7c5e40SJason M. Bills {
2053f7c5e40SJason M. Bills     uint8_t sensorType = 0;
2063f7c5e40SJason M. Bills     std::string type = getSensorTypeStringFromPath(path);
2073f7c5e40SJason M. Bills     auto findSensor = sensorTypes.find(type.c_str());
2083f7c5e40SJason M. Bills     if (findSensor != sensorTypes.end())
2093f7c5e40SJason M. Bills     {
2103f7c5e40SJason M. Bills         sensorType = static_cast<uint8_t>(findSensor->second);
2113f7c5e40SJason M. Bills     } // else default 0x0 RESERVED
2123f7c5e40SJason M. Bills 
2133f7c5e40SJason M. Bills     return sensorType;
2143f7c5e40SJason M. Bills }
2153f7c5e40SJason M. Bills 
2163f7c5e40SJason M. Bills inline static uint8_t getSensorNumberFromPath(const std::string& path)
2173f7c5e40SJason M. Bills {
218a9423b6eSJason M. Bills     std::shared_ptr<SensorNumMap> sensorNumMapPtr;
219a9423b6eSJason M. Bills     details::getSensorNumMap(sensorNumMapPtr);
220a9423b6eSJason M. Bills     if (!sensorNumMapPtr)
221a9423b6eSJason M. Bills     {
2223f7c5e40SJason M. Bills         return 0xFF;
223a9423b6eSJason M. Bills     }
2243f7c5e40SJason M. Bills 
225a9423b6eSJason M. Bills     try
2263f7c5e40SJason M. Bills     {
227a9423b6eSJason M. Bills         return sensorNumMapPtr->right.at(path);
228a9423b6eSJason M. Bills     }
229a9423b6eSJason M. Bills     catch (std::out_of_range& e)
2303f7c5e40SJason M. Bills     {
231a9423b6eSJason M. Bills         phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
232a9423b6eSJason M. Bills         return 0xFF;
2333f7c5e40SJason M. Bills     }
2343f7c5e40SJason M. Bills }
2353f7c5e40SJason M. Bills 
2363f7c5e40SJason M. Bills inline static uint8_t getSensorEventTypeFromPath(const std::string& path)
2373f7c5e40SJason M. Bills {
2383f7c5e40SJason M. Bills     // TODO: Add support for additional reading types as needed
2393f7c5e40SJason M. Bills     return 0x1; // reading type = threshold
2403f7c5e40SJason M. Bills }
2413f7c5e40SJason M. Bills 
2423f7c5e40SJason M. Bills inline static std::string getPathFromSensorNumber(uint8_t sensorNum)
2433f7c5e40SJason M. Bills {
244a9423b6eSJason M. Bills     std::shared_ptr<SensorNumMap> sensorNumMapPtr;
245a9423b6eSJason M. Bills     details::getSensorNumMap(sensorNumMapPtr);
246a9423b6eSJason M. Bills     if (!sensorNumMapPtr)
2473f7c5e40SJason M. Bills     {
248a9423b6eSJason M. Bills         return std::string();
2493f7c5e40SJason M. Bills     }
2503f7c5e40SJason M. Bills 
251a9423b6eSJason M. Bills     try
2523f7c5e40SJason M. Bills     {
253a9423b6eSJason M. Bills         return sensorNumMapPtr->left.at(sensorNum);
254a9423b6eSJason M. Bills     }
255a9423b6eSJason M. Bills     catch (std::out_of_range& e)
2563f7c5e40SJason M. Bills     {
257a9423b6eSJason M. Bills         phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
258a9423b6eSJason M. Bills         return std::string();
2593f7c5e40SJason M. Bills     }
2603f7c5e40SJason M. Bills }
261262276f4SPatrick Venture 
262262276f4SPatrick Venture namespace ipmi
263262276f4SPatrick Venture {
264262276f4SPatrick Venture 
265262276f4SPatrick Venture static inline std::map<std::string, std::vector<std::string>>
266262276f4SPatrick Venture     getObjectInterfaces(const char* path)
267262276f4SPatrick Venture {
268262276f4SPatrick Venture     std::map<std::string, std::vector<std::string>> interfacesResponse;
269262276f4SPatrick Venture     std::vector<std::string> interfaces;
270262276f4SPatrick Venture     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
271262276f4SPatrick Venture 
272262276f4SPatrick Venture     sdbusplus::message::message getObjectMessage =
273262276f4SPatrick Venture         dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
274262276f4SPatrick Venture                               "/xyz/openbmc_project/object_mapper",
275262276f4SPatrick Venture                               "xyz.openbmc_project.ObjectMapper", "GetObject");
276262276f4SPatrick Venture     getObjectMessage.append(path, interfaces);
277262276f4SPatrick Venture 
278262276f4SPatrick Venture     try
279262276f4SPatrick Venture     {
280262276f4SPatrick Venture         sdbusplus::message::message response = dbus->call(getObjectMessage);
281262276f4SPatrick Venture         response.read(interfacesResponse);
282262276f4SPatrick Venture     }
283262276f4SPatrick Venture     catch (const std::exception& e)
284262276f4SPatrick Venture     {
285262276f4SPatrick Venture         phosphor::logging::log<phosphor::logging::level::ERR>(
286262276f4SPatrick Venture             "Failed to GetObject", phosphor::logging::entry("PATH=%s", path),
287262276f4SPatrick Venture             phosphor::logging::entry("WHAT=%s", e.what()));
288262276f4SPatrick Venture     }
289262276f4SPatrick Venture 
290262276f4SPatrick Venture     return interfacesResponse;
291262276f4SPatrick Venture }
292262276f4SPatrick Venture 
293262276f4SPatrick Venture static inline std::map<std::string, DbusVariant>
294262276f4SPatrick Venture     getEntityManagerProperties(const char* path, const char* interface)
295262276f4SPatrick Venture {
296262276f4SPatrick Venture     std::map<std::string, DbusVariant> properties;
297262276f4SPatrick Venture     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
298262276f4SPatrick Venture 
299262276f4SPatrick Venture     sdbusplus::message::message getProperties =
300262276f4SPatrick Venture         dbus->new_method_call("xyz.openbmc_project.EntityManager", path,
301262276f4SPatrick Venture                               "org.freedesktop.DBus.Properties", "GetAll");
302262276f4SPatrick Venture     getProperties.append(interface);
303262276f4SPatrick Venture 
304262276f4SPatrick Venture     try
305262276f4SPatrick Venture     {
306262276f4SPatrick Venture         sdbusplus::message::message response = dbus->call(getProperties);
307262276f4SPatrick Venture         response.read(properties);
308262276f4SPatrick Venture     }
309262276f4SPatrick Venture     catch (const std::exception& e)
310262276f4SPatrick Venture     {
311262276f4SPatrick Venture         phosphor::logging::log<phosphor::logging::level::ERR>(
312262276f4SPatrick Venture             "Failed to GetAll", phosphor::logging::entry("PATH=%s", path),
313262276f4SPatrick Venture             phosphor::logging::entry("INTF=%s", interface),
314262276f4SPatrick Venture             phosphor::logging::entry("WHAT=%s", e.what()));
315262276f4SPatrick Venture     }
316262276f4SPatrick Venture 
317262276f4SPatrick Venture     return properties;
318262276f4SPatrick Venture }
319262276f4SPatrick Venture 
320262276f4SPatrick Venture static inline const std::string* getSensorConfigurationInterface(
321262276f4SPatrick Venture     const std::map<std::string, std::vector<std::string>>&
322262276f4SPatrick Venture         sensorInterfacesResponse)
323262276f4SPatrick Venture {
324262276f4SPatrick Venture     auto entityManagerService =
325262276f4SPatrick Venture         sensorInterfacesResponse.find("xyz.openbmc_project.EntityManager");
326262276f4SPatrick Venture     if (entityManagerService == sensorInterfacesResponse.end())
327262276f4SPatrick Venture     {
328262276f4SPatrick Venture         return nullptr;
329262276f4SPatrick Venture     }
330262276f4SPatrick Venture 
331262276f4SPatrick Venture     // Find the fan configuration first (fans can have multiple configuration
332262276f4SPatrick Venture     // interfaces).
333262276f4SPatrick Venture     for (const auto& entry : entityManagerService->second)
334262276f4SPatrick Venture     {
335262276f4SPatrick Venture         if (entry == "xyz.openbmc_project.Configuration.AspeedFan" ||
336262276f4SPatrick Venture             entry == "xyz.openbmc_project.Configuration.I2CFan" ||
337262276f4SPatrick Venture             entry == "xyz.openbmc_project.Configuration.NuvotonFan")
338262276f4SPatrick Venture         {
339262276f4SPatrick Venture             return &entry;
340262276f4SPatrick Venture         }
341262276f4SPatrick Venture     }
342262276f4SPatrick Venture 
343262276f4SPatrick Venture     for (const auto& entry : entityManagerService->second)
344262276f4SPatrick Venture     {
345262276f4SPatrick Venture         if (boost::algorithm::starts_with(entry,
346262276f4SPatrick Venture                                           "xyz.openbmc_project.Configuration."))
347262276f4SPatrick Venture         {
348262276f4SPatrick Venture             return &entry;
349262276f4SPatrick Venture         }
350262276f4SPatrick Venture     }
351262276f4SPatrick Venture 
352262276f4SPatrick Venture     return nullptr;
353262276f4SPatrick Venture }
354262276f4SPatrick Venture 
355262276f4SPatrick Venture // Follow Association properties for Sensor back to the Board dbus object to
356262276f4SPatrick Venture // check for an EntityId and EntityInstance property.
357262276f4SPatrick Venture static inline void updateIpmiFromAssociation(const std::string& path,
358262276f4SPatrick Venture                                              const SensorMap& sensorMap,
359262276f4SPatrick Venture                                              uint8_t& entityId,
360262276f4SPatrick Venture                                              uint8_t& entityInstance)
361262276f4SPatrick Venture {
362262276f4SPatrick Venture     namespace fs = std::filesystem;
363262276f4SPatrick Venture 
364262276f4SPatrick Venture     auto sensorAssociationObject =
365262276f4SPatrick Venture         sensorMap.find("xyz.openbmc_project.Association.Definitions");
366262276f4SPatrick Venture     if (sensorAssociationObject == sensorMap.end())
367262276f4SPatrick Venture     {
368262276f4SPatrick Venture         if constexpr (debug)
369262276f4SPatrick Venture         {
370262276f4SPatrick Venture             std::fprintf(stderr, "path=%s, no association interface found\n",
371262276f4SPatrick Venture                          path.c_str());
372262276f4SPatrick Venture         }
373262276f4SPatrick Venture 
374262276f4SPatrick Venture         return;
375262276f4SPatrick Venture     }
376262276f4SPatrick Venture 
377262276f4SPatrick Venture     auto associationObject =
378262276f4SPatrick Venture         sensorAssociationObject->second.find("Associations");
379262276f4SPatrick Venture     if (associationObject == sensorAssociationObject->second.end())
380262276f4SPatrick Venture     {
381262276f4SPatrick Venture         if constexpr (debug)
382262276f4SPatrick Venture         {
383262276f4SPatrick Venture             std::fprintf(stderr, "path=%s, no association records found\n",
384262276f4SPatrick Venture                          path.c_str());
385262276f4SPatrick Venture         }
386262276f4SPatrick Venture 
387262276f4SPatrick Venture         return;
388262276f4SPatrick Venture     }
389262276f4SPatrick Venture 
390262276f4SPatrick Venture     std::vector<Association> associationValues =
391262276f4SPatrick Venture         std::get<std::vector<Association>>(associationObject->second);
392262276f4SPatrick Venture 
393262276f4SPatrick Venture     // loop through the Associations looking for the right one:
394262276f4SPatrick Venture     for (const auto& entry : associationValues)
395262276f4SPatrick Venture     {
396262276f4SPatrick Venture         // forward, reverse, endpoint
397262276f4SPatrick Venture         const std::string& forward = std::get<0>(entry);
398262276f4SPatrick Venture         const std::string& reverse = std::get<1>(entry);
399262276f4SPatrick Venture         const std::string& endpoint = std::get<2>(entry);
400262276f4SPatrick Venture 
401262276f4SPatrick Venture         // We only currently concern ourselves with chassis+all_sensors.
402262276f4SPatrick Venture         if (!(forward == "chassis" && reverse == "all_sensors"))
403262276f4SPatrick Venture         {
404262276f4SPatrick Venture             continue;
405262276f4SPatrick Venture         }
406262276f4SPatrick Venture 
407262276f4SPatrick Venture         // the endpoint is the board entry provided by
408262276f4SPatrick Venture         // Entity-Manager. so let's grab its properties if it has
409262276f4SPatrick Venture         // the right interface.
410262276f4SPatrick Venture 
411262276f4SPatrick Venture         // just try grabbing the properties first.
412262276f4SPatrick Venture         std::map<std::string, DbusVariant> ipmiProperties =
413262276f4SPatrick Venture             getEntityManagerProperties(
414262276f4SPatrick Venture                 endpoint.c_str(),
415262276f4SPatrick Venture                 "xyz.openbmc_project.Inventory.Decorator.Ipmi");
416262276f4SPatrick Venture 
417262276f4SPatrick Venture         auto entityIdProp = ipmiProperties.find("EntityId");
418262276f4SPatrick Venture         auto entityInstanceProp = ipmiProperties.find("EntityInstance");
419262276f4SPatrick Venture         if (entityIdProp != ipmiProperties.end())
420262276f4SPatrick Venture         {
421262276f4SPatrick Venture             entityId =
422262276f4SPatrick Venture                 static_cast<uint8_t>(std::get<uint64_t>(entityIdProp->second));
423262276f4SPatrick Venture         }
424262276f4SPatrick Venture         if (entityInstanceProp != ipmiProperties.end())
425262276f4SPatrick Venture         {
426262276f4SPatrick Venture             entityInstance = static_cast<uint8_t>(
427262276f4SPatrick Venture                 std::get<uint64_t>(entityInstanceProp->second));
428262276f4SPatrick Venture         }
429262276f4SPatrick Venture 
430262276f4SPatrick Venture         // Now check the entity-manager entry for this sensor to see
431262276f4SPatrick Venture         // if it has its own value and use that instead.
432262276f4SPatrick Venture         //
433262276f4SPatrick Venture         // In theory, checking this first saves us from checking
434262276f4SPatrick Venture         // both, except in most use-cases identified, there won't be
435262276f4SPatrick Venture         // a per sensor override, so we need to always check both.
436262276f4SPatrick Venture         std::string sensorNameFromPath = fs::path(path).filename();
437262276f4SPatrick Venture 
438262276f4SPatrick Venture         std::string sensorConfigPath = endpoint + "/" + sensorNameFromPath;
439262276f4SPatrick Venture 
440262276f4SPatrick Venture         // Download the interfaces for the sensor from
441262276f4SPatrick Venture         // Entity-Manager to find the name of the configuration
442262276f4SPatrick Venture         // interface.
443262276f4SPatrick Venture         std::map<std::string, std::vector<std::string>>
444262276f4SPatrick Venture             sensorInterfacesResponse =
445262276f4SPatrick Venture                 getObjectInterfaces(sensorConfigPath.c_str());
446262276f4SPatrick Venture 
447262276f4SPatrick Venture         const std::string* configurationInterface =
448262276f4SPatrick Venture             getSensorConfigurationInterface(sensorInterfacesResponse);
449262276f4SPatrick Venture 
450262276f4SPatrick Venture         // We didnt' find a configuration interface for this sensor, but we
451262276f4SPatrick Venture         // followed the Association property to get here, so we're done
452262276f4SPatrick Venture         // searching.
453262276f4SPatrick Venture         if (!configurationInterface)
454262276f4SPatrick Venture         {
455262276f4SPatrick Venture             break;
456262276f4SPatrick Venture         }
457262276f4SPatrick Venture 
458262276f4SPatrick Venture         // We found a configuration interface.
459262276f4SPatrick Venture         std::map<std::string, DbusVariant> configurationProperties =
460262276f4SPatrick Venture             getEntityManagerProperties(sensorConfigPath.c_str(),
461262276f4SPatrick Venture                                        configurationInterface->c_str());
462262276f4SPatrick Venture 
463262276f4SPatrick Venture         entityIdProp = configurationProperties.find("EntityId");
464262276f4SPatrick Venture         entityInstanceProp = configurationProperties.find("EntityInstance");
465262276f4SPatrick Venture         if (entityIdProp != configurationProperties.end())
466262276f4SPatrick Venture         {
467262276f4SPatrick Venture             entityId =
468262276f4SPatrick Venture                 static_cast<uint8_t>(std::get<uint64_t>(entityIdProp->second));
469262276f4SPatrick Venture         }
470262276f4SPatrick Venture         if (entityInstanceProp != configurationProperties.end())
471262276f4SPatrick Venture         {
472262276f4SPatrick Venture             entityInstance = static_cast<uint8_t>(
473262276f4SPatrick Venture                 std::get<uint64_t>(entityInstanceProp->second));
474262276f4SPatrick Venture         }
475262276f4SPatrick Venture 
476262276f4SPatrick Venture         // stop searching Association records.
477262276f4SPatrick Venture         break;
478262276f4SPatrick Venture     } // end for Association vectors.
479262276f4SPatrick Venture 
480262276f4SPatrick Venture     if constexpr (debug)
481262276f4SPatrick Venture     {
482262276f4SPatrick Venture         std::fprintf(stderr, "path=%s, entityId=%d, entityInstance=%d\n",
483262276f4SPatrick Venture                      path.c_str(), entityId, entityInstance);
484262276f4SPatrick Venture     }
485262276f4SPatrick Venture }
486262276f4SPatrick Venture 
487262276f4SPatrick Venture } // namespace ipmi
488