xref: /openbmc/intel-ipmi-oem/include/sdrutils.hpp (revision 262276f4964191d780aeab3a821de54b01c0a8ff)
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 
17*262276f4SPatrick Venture #include "commandutils.hpp"
18*262276f4SPatrick 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*262276f4SPatrick Venture #include <cstdio>
233f7c5e40SJason M. Bills #include <cstring>
24*262276f4SPatrick Venture #include <exception>
25*262276f4SPatrick Venture #include <filesystem>
26*262276f4SPatrick Venture #include <map>
273f7c5e40SJason M. Bills #include <phosphor-logging/log.hpp>
28a9423b6eSJason M. Bills #include <sdbusplus/bus/match.hpp>
29*262276f4SPatrick Venture #include <string>
30*262276f4SPatrick Venture #include <vector>
313f7c5e40SJason M. Bills 
323f7c5e40SJason M. Bills #pragma once
333f7c5e40SJason M. Bills 
343f7c5e40SJason M. Bills struct CmpStrVersion
353f7c5e40SJason M. Bills {
363f7c5e40SJason M. Bills     bool operator()(std::string a, std::string b) const
373f7c5e40SJason M. Bills     {
383f7c5e40SJason M. Bills         return strverscmp(a.c_str(), b.c_str()) < 0;
393f7c5e40SJason M. Bills     }
403f7c5e40SJason M. Bills };
413f7c5e40SJason M. Bills 
423f7c5e40SJason M. Bills using SensorSubTree = boost::container::flat_map<
433f7c5e40SJason M. Bills     std::string,
443f7c5e40SJason M. Bills     boost::container::flat_map<std::string, std::vector<std::string>>,
453f7c5e40SJason M. Bills     CmpStrVersion>;
463f7c5e40SJason M. Bills 
47a9423b6eSJason M. Bills using SensorNumMap = boost::bimap<int, std::string>;
48a9423b6eSJason M. Bills 
49a9423b6eSJason M. Bills namespace details
503f7c5e40SJason M. Bills {
51a9423b6eSJason M. Bills inline static bool getSensorSubtree(std::shared_ptr<SensorSubTree>& subtree)
52a9423b6eSJason M. Bills {
53a9423b6eSJason M. Bills     static std::shared_ptr<SensorSubTree> sensorTreePtr;
543f7c5e40SJason M. Bills     sd_bus* bus = NULL;
553f7c5e40SJason M. Bills     int ret = sd_bus_default_system(&bus);
563f7c5e40SJason M. Bills     if (ret < 0)
573f7c5e40SJason M. Bills     {
583f7c5e40SJason M. Bills         phosphor::logging::log<phosphor::logging::level::ERR>(
593f7c5e40SJason M. Bills             "Failed to connect to system bus",
603f7c5e40SJason M. Bills             phosphor::logging::entry("ERRNO=0x%X", -ret));
613f7c5e40SJason M. Bills         sd_bus_unref(bus);
623f7c5e40SJason M. Bills         return false;
633f7c5e40SJason M. Bills     }
643f7c5e40SJason M. Bills     sdbusplus::bus::bus dbus(bus);
65a9423b6eSJason M. Bills     static sdbusplus::bus::match::match sensorAdded(
66a9423b6eSJason M. Bills         dbus,
67a9423b6eSJason M. Bills         "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/"
68a9423b6eSJason M. Bills         "sensors/'",
69a9423b6eSJason M. Bills         [](sdbusplus::message::message& m) { sensorTreePtr.reset(); });
70a9423b6eSJason M. Bills 
71a9423b6eSJason M. Bills     static sdbusplus::bus::match::match sensorRemoved(
72a9423b6eSJason M. Bills         dbus,
73a9423b6eSJason M. Bills         "type='signal',member='InterfacesRemoved',arg0path='/xyz/"
74a9423b6eSJason M. Bills         "openbmc_project/sensors/'",
75a9423b6eSJason M. Bills         [](sdbusplus::message::message& m) { sensorTreePtr.reset(); });
76a9423b6eSJason M. Bills 
77a9423b6eSJason M. Bills     bool sensorTreeUpdated = false;
78a9423b6eSJason M. Bills     if (sensorTreePtr)
79a9423b6eSJason M. Bills     {
80a9423b6eSJason M. Bills         subtree = sensorTreePtr;
81a9423b6eSJason M. Bills         return sensorTreeUpdated;
82a9423b6eSJason M. Bills     }
83a9423b6eSJason M. Bills 
84a9423b6eSJason M. Bills     sensorTreePtr = std::make_shared<SensorSubTree>();
85a9423b6eSJason M. Bills 
863f7c5e40SJason M. Bills     auto mapperCall =
873f7c5e40SJason M. Bills         dbus.new_method_call("xyz.openbmc_project.ObjectMapper",
883f7c5e40SJason M. Bills                              "/xyz/openbmc_project/object_mapper",
893f7c5e40SJason M. Bills                              "xyz.openbmc_project.ObjectMapper", "GetSubTree");
9052341e85SJason M. Bills     static constexpr const auto depth = 2;
913f7c5e40SJason M. Bills     static constexpr std::array<const char*, 3> interfaces = {
923f7c5e40SJason M. Bills         "xyz.openbmc_project.Sensor.Value",
933f7c5e40SJason M. Bills         "xyz.openbmc_project.Sensor.Threshold.Warning",
943f7c5e40SJason M. Bills         "xyz.openbmc_project.Sensor.Threshold.Critical"};
953f7c5e40SJason M. Bills     mapperCall.append("/xyz/openbmc_project/sensors", depth, interfaces);
963f7c5e40SJason M. Bills 
973f7c5e40SJason M. Bills     try
983f7c5e40SJason M. Bills     {
993f7c5e40SJason M. Bills         auto mapperReply = dbus.call(mapperCall);
100a9423b6eSJason M. Bills         mapperReply.read(*sensorTreePtr);
1013f7c5e40SJason M. Bills     }
10252341e85SJason M. Bills     catch (sdbusplus::exception_t& e)
1033f7c5e40SJason M. Bills     {
10452341e85SJason M. Bills         phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
105a9423b6eSJason M. Bills         return sensorTreeUpdated;
106a9423b6eSJason M. Bills     }
107a9423b6eSJason M. Bills     subtree = sensorTreePtr;
108a9423b6eSJason M. Bills     sensorTreeUpdated = true;
109a9423b6eSJason M. Bills     return sensorTreeUpdated;
110a9423b6eSJason M. Bills }
111a9423b6eSJason M. Bills 
112a9423b6eSJason M. Bills inline static bool getSensorNumMap(std::shared_ptr<SensorNumMap>& sensorNumMap)
113a9423b6eSJason M. Bills {
114a9423b6eSJason M. Bills     static std::shared_ptr<SensorNumMap> sensorNumMapPtr;
115a9423b6eSJason M. Bills     bool sensorNumMapUpated = false;
116a9423b6eSJason M. Bills 
117a9423b6eSJason M. Bills     std::shared_ptr<SensorSubTree> sensorTree;
118a9423b6eSJason M. Bills     bool sensorTreeUpdated = details::getSensorSubtree(sensorTree);
119a9423b6eSJason M. Bills     if (!sensorTree)
120a9423b6eSJason M. Bills     {
121a9423b6eSJason M. Bills         return sensorNumMapUpated;
122a9423b6eSJason M. Bills     }
123a9423b6eSJason M. Bills 
124a9423b6eSJason M. Bills     if (!sensorTreeUpdated && sensorNumMapPtr)
125a9423b6eSJason M. Bills     {
126a9423b6eSJason M. Bills         sensorNumMap = sensorNumMapPtr;
127a9423b6eSJason M. Bills         return sensorNumMapUpated;
128a9423b6eSJason M. Bills     }
129a9423b6eSJason M. Bills 
130a9423b6eSJason M. Bills     sensorNumMapPtr = std::make_shared<SensorNumMap>();
131a9423b6eSJason M. Bills 
132caed905dSJason M. Bills     uint8_t sensorNum = 0;
133a9423b6eSJason M. Bills     for (const auto& sensor : *sensorTree)
134a9423b6eSJason M. Bills     {
135a9423b6eSJason M. Bills         sensorNumMapPtr->insert(
136a9423b6eSJason M. Bills             SensorNumMap::value_type(sensorNum++, sensor.first));
137a9423b6eSJason M. Bills     }
138a9423b6eSJason M. Bills     sensorNumMap = sensorNumMapPtr;
139a9423b6eSJason M. Bills     sensorNumMapUpated = true;
140a9423b6eSJason M. Bills     return sensorNumMapUpated;
141a9423b6eSJason M. Bills }
142a9423b6eSJason M. Bills } // namespace details
143a9423b6eSJason M. Bills 
144a9423b6eSJason M. Bills inline static bool getSensorSubtree(SensorSubTree& subtree)
145a9423b6eSJason M. Bills {
146a9423b6eSJason M. Bills     std::shared_ptr<SensorSubTree> sensorTree;
147a9423b6eSJason M. Bills     details::getSensorSubtree(sensorTree);
148a9423b6eSJason M. Bills     if (!sensorTree)
149a9423b6eSJason M. Bills     {
1503f7c5e40SJason M. Bills         return false;
1513f7c5e40SJason M. Bills     }
152a9423b6eSJason M. Bills 
153a9423b6eSJason M. Bills     subtree = *sensorTree;
1543f7c5e40SJason M. Bills     return true;
1553f7c5e40SJason M. Bills }
1563f7c5e40SJason M. Bills 
1573f7c5e40SJason M. Bills struct CmpStr
1583f7c5e40SJason M. Bills {
1593f7c5e40SJason M. Bills     bool operator()(const char* a, const char* b) const
1603f7c5e40SJason M. Bills     {
1613f7c5e40SJason M. Bills         return std::strcmp(a, b) < 0;
1623f7c5e40SJason M. Bills     }
1633f7c5e40SJason M. Bills };
1643f7c5e40SJason M. Bills 
16552341e85SJason M. Bills enum class SensorTypeCodes : uint8_t
16652341e85SJason M. Bills {
16752341e85SJason M. Bills     reserved = 0x0,
16852341e85SJason M. Bills     temperature = 0x1,
16952341e85SJason M. Bills     voltage = 0x2,
17052341e85SJason M. Bills     current = 0x3,
17152341e85SJason M. Bills     fan = 0x4,
17252341e85SJason M. Bills     other = 0xB,
17352341e85SJason M. Bills };
17452341e85SJason M. Bills 
1753f7c5e40SJason M. Bills const static boost::container::flat_map<const char*, SensorTypeCodes, CmpStr>
1763f7c5e40SJason M. Bills     sensorTypes{{{"temperature", SensorTypeCodes::temperature},
1773f7c5e40SJason M. Bills                  {"voltage", SensorTypeCodes::voltage},
1783f7c5e40SJason M. Bills                  {"current", SensorTypeCodes::current},
1793f7c5e40SJason M. Bills                  {"fan_tach", SensorTypeCodes::fan},
180f426f334SJames Feist                  {"fan_pwm", SensorTypeCodes::fan},
1813f7c5e40SJason M. Bills                  {"power", SensorTypeCodes::other}}};
1823f7c5e40SJason M. Bills 
1833f7c5e40SJason M. Bills inline static std::string getSensorTypeStringFromPath(const std::string& path)
1843f7c5e40SJason M. Bills {
1853f7c5e40SJason M. Bills     // get sensor type string from path, path is defined as
1863f7c5e40SJason M. Bills     // /xyz/openbmc_project/sensors/<type>/label
1873f7c5e40SJason M. Bills     size_t typeEnd = path.rfind("/");
188360f593bSJason M. Bills     if (typeEnd == std::string::npos)
1893f7c5e40SJason M. Bills     {
1903f7c5e40SJason M. Bills         return path;
1913f7c5e40SJason M. Bills     }
192360f593bSJason M. Bills     size_t typeStart = path.rfind("/", typeEnd - 1);
193360f593bSJason M. Bills     if (typeStart == std::string::npos)
194360f593bSJason M. Bills     {
195360f593bSJason M. Bills         return path;
196360f593bSJason M. Bills     }
197360f593bSJason M. Bills     // Start at the character after the '/'
198360f593bSJason M. Bills     typeStart++;
199360f593bSJason M. Bills     return path.substr(typeStart, typeEnd - typeStart);
200360f593bSJason M. Bills }
2013f7c5e40SJason M. Bills 
2023f7c5e40SJason M. Bills inline static uint8_t getSensorTypeFromPath(const std::string& path)
2033f7c5e40SJason M. Bills {
2043f7c5e40SJason M. Bills     uint8_t sensorType = 0;
2053f7c5e40SJason M. Bills     std::string type = getSensorTypeStringFromPath(path);
2063f7c5e40SJason M. Bills     auto findSensor = sensorTypes.find(type.c_str());
2073f7c5e40SJason M. Bills     if (findSensor != sensorTypes.end())
2083f7c5e40SJason M. Bills     {
2093f7c5e40SJason M. Bills         sensorType = static_cast<uint8_t>(findSensor->second);
2103f7c5e40SJason M. Bills     } // else default 0x0 RESERVED
2113f7c5e40SJason M. Bills 
2123f7c5e40SJason M. Bills     return sensorType;
2133f7c5e40SJason M. Bills }
2143f7c5e40SJason M. Bills 
2153f7c5e40SJason M. Bills inline static uint8_t getSensorNumberFromPath(const std::string& path)
2163f7c5e40SJason M. Bills {
217a9423b6eSJason M. Bills     std::shared_ptr<SensorNumMap> sensorNumMapPtr;
218a9423b6eSJason M. Bills     details::getSensorNumMap(sensorNumMapPtr);
219a9423b6eSJason M. Bills     if (!sensorNumMapPtr)
220a9423b6eSJason M. Bills     {
2213f7c5e40SJason M. Bills         return 0xFF;
222a9423b6eSJason M. Bills     }
2233f7c5e40SJason M. Bills 
224a9423b6eSJason M. Bills     try
2253f7c5e40SJason M. Bills     {
226a9423b6eSJason M. Bills         return sensorNumMapPtr->right.at(path);
227a9423b6eSJason M. Bills     }
228a9423b6eSJason M. Bills     catch (std::out_of_range& e)
2293f7c5e40SJason M. Bills     {
230a9423b6eSJason M. Bills         phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
231a9423b6eSJason M. Bills         return 0xFF;
2323f7c5e40SJason M. Bills     }
2333f7c5e40SJason M. Bills }
2343f7c5e40SJason M. Bills 
2353f7c5e40SJason M. Bills inline static uint8_t getSensorEventTypeFromPath(const std::string& path)
2363f7c5e40SJason M. Bills {
2373f7c5e40SJason M. Bills     // TODO: Add support for additional reading types as needed
2383f7c5e40SJason M. Bills     return 0x1; // reading type = threshold
2393f7c5e40SJason M. Bills }
2403f7c5e40SJason M. Bills 
2413f7c5e40SJason M. Bills inline static std::string getPathFromSensorNumber(uint8_t sensorNum)
2423f7c5e40SJason M. Bills {
243a9423b6eSJason M. Bills     std::shared_ptr<SensorNumMap> sensorNumMapPtr;
244a9423b6eSJason M. Bills     details::getSensorNumMap(sensorNumMapPtr);
245a9423b6eSJason M. Bills     if (!sensorNumMapPtr)
2463f7c5e40SJason M. Bills     {
247a9423b6eSJason M. Bills         return std::string();
2483f7c5e40SJason M. Bills     }
2493f7c5e40SJason M. Bills 
250a9423b6eSJason M. Bills     try
2513f7c5e40SJason M. Bills     {
252a9423b6eSJason M. Bills         return sensorNumMapPtr->left.at(sensorNum);
253a9423b6eSJason M. Bills     }
254a9423b6eSJason M. Bills     catch (std::out_of_range& e)
2553f7c5e40SJason M. Bills     {
256a9423b6eSJason M. Bills         phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
257a9423b6eSJason M. Bills         return std::string();
2583f7c5e40SJason M. Bills     }
2593f7c5e40SJason M. Bills }
260*262276f4SPatrick Venture 
261*262276f4SPatrick Venture namespace ipmi
262*262276f4SPatrick Venture {
263*262276f4SPatrick Venture 
264*262276f4SPatrick Venture static inline std::map<std::string, std::vector<std::string>>
265*262276f4SPatrick Venture     getObjectInterfaces(const char* path)
266*262276f4SPatrick Venture {
267*262276f4SPatrick Venture     std::map<std::string, std::vector<std::string>> interfacesResponse;
268*262276f4SPatrick Venture     std::vector<std::string> interfaces;
269*262276f4SPatrick Venture     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
270*262276f4SPatrick Venture 
271*262276f4SPatrick Venture     sdbusplus::message::message getObjectMessage =
272*262276f4SPatrick Venture         dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
273*262276f4SPatrick Venture                               "/xyz/openbmc_project/object_mapper",
274*262276f4SPatrick Venture                               "xyz.openbmc_project.ObjectMapper", "GetObject");
275*262276f4SPatrick Venture     getObjectMessage.append(path, interfaces);
276*262276f4SPatrick Venture 
277*262276f4SPatrick Venture     try
278*262276f4SPatrick Venture     {
279*262276f4SPatrick Venture         sdbusplus::message::message response = dbus->call(getObjectMessage);
280*262276f4SPatrick Venture         response.read(interfacesResponse);
281*262276f4SPatrick Venture     }
282*262276f4SPatrick Venture     catch (const std::exception& e)
283*262276f4SPatrick Venture     {
284*262276f4SPatrick Venture         phosphor::logging::log<phosphor::logging::level::ERR>(
285*262276f4SPatrick Venture             "Failed to GetObject", phosphor::logging::entry("PATH=%s", path),
286*262276f4SPatrick Venture             phosphor::logging::entry("WHAT=%s", e.what()));
287*262276f4SPatrick Venture     }
288*262276f4SPatrick Venture 
289*262276f4SPatrick Venture     return interfacesResponse;
290*262276f4SPatrick Venture }
291*262276f4SPatrick Venture 
292*262276f4SPatrick Venture static inline std::map<std::string, DbusVariant>
293*262276f4SPatrick Venture     getEntityManagerProperties(const char* path, const char* interface)
294*262276f4SPatrick Venture {
295*262276f4SPatrick Venture     std::map<std::string, DbusVariant> properties;
296*262276f4SPatrick Venture     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
297*262276f4SPatrick Venture 
298*262276f4SPatrick Venture     sdbusplus::message::message getProperties =
299*262276f4SPatrick Venture         dbus->new_method_call("xyz.openbmc_project.EntityManager", path,
300*262276f4SPatrick Venture                               "org.freedesktop.DBus.Properties", "GetAll");
301*262276f4SPatrick Venture     getProperties.append(interface);
302*262276f4SPatrick Venture 
303*262276f4SPatrick Venture     try
304*262276f4SPatrick Venture     {
305*262276f4SPatrick Venture         sdbusplus::message::message response = dbus->call(getProperties);
306*262276f4SPatrick Venture         response.read(properties);
307*262276f4SPatrick Venture     }
308*262276f4SPatrick Venture     catch (const std::exception& e)
309*262276f4SPatrick Venture     {
310*262276f4SPatrick Venture         phosphor::logging::log<phosphor::logging::level::ERR>(
311*262276f4SPatrick Venture             "Failed to GetAll", phosphor::logging::entry("PATH=%s", path),
312*262276f4SPatrick Venture             phosphor::logging::entry("INTF=%s", interface),
313*262276f4SPatrick Venture             phosphor::logging::entry("WHAT=%s", e.what()));
314*262276f4SPatrick Venture     }
315*262276f4SPatrick Venture 
316*262276f4SPatrick Venture     return properties;
317*262276f4SPatrick Venture }
318*262276f4SPatrick Venture 
319*262276f4SPatrick Venture static inline const std::string* getSensorConfigurationInterface(
320*262276f4SPatrick Venture     const std::map<std::string, std::vector<std::string>>&
321*262276f4SPatrick Venture         sensorInterfacesResponse)
322*262276f4SPatrick Venture {
323*262276f4SPatrick Venture     auto entityManagerService =
324*262276f4SPatrick Venture         sensorInterfacesResponse.find("xyz.openbmc_project.EntityManager");
325*262276f4SPatrick Venture     if (entityManagerService == sensorInterfacesResponse.end())
326*262276f4SPatrick Venture     {
327*262276f4SPatrick Venture         return nullptr;
328*262276f4SPatrick Venture     }
329*262276f4SPatrick Venture 
330*262276f4SPatrick Venture     // Find the fan configuration first (fans can have multiple configuration
331*262276f4SPatrick Venture     // interfaces).
332*262276f4SPatrick Venture     for (const auto& entry : entityManagerService->second)
333*262276f4SPatrick Venture     {
334*262276f4SPatrick Venture         if (entry == "xyz.openbmc_project.Configuration.AspeedFan" ||
335*262276f4SPatrick Venture             entry == "xyz.openbmc_project.Configuration.I2CFan" ||
336*262276f4SPatrick Venture             entry == "xyz.openbmc_project.Configuration.NuvotonFan")
337*262276f4SPatrick Venture         {
338*262276f4SPatrick Venture             return &entry;
339*262276f4SPatrick Venture         }
340*262276f4SPatrick Venture     }
341*262276f4SPatrick Venture 
342*262276f4SPatrick Venture     for (const auto& entry : entityManagerService->second)
343*262276f4SPatrick Venture     {
344*262276f4SPatrick Venture         if (boost::algorithm::starts_with(entry,
345*262276f4SPatrick Venture                                           "xyz.openbmc_project.Configuration."))
346*262276f4SPatrick Venture         {
347*262276f4SPatrick Venture             return &entry;
348*262276f4SPatrick Venture         }
349*262276f4SPatrick Venture     }
350*262276f4SPatrick Venture 
351*262276f4SPatrick Venture     return nullptr;
352*262276f4SPatrick Venture }
353*262276f4SPatrick Venture 
354*262276f4SPatrick Venture // Follow Association properties for Sensor back to the Board dbus object to
355*262276f4SPatrick Venture // check for an EntityId and EntityInstance property.
356*262276f4SPatrick Venture static inline void updateIpmiFromAssociation(const std::string& path,
357*262276f4SPatrick Venture                                              const SensorMap& sensorMap,
358*262276f4SPatrick Venture                                              uint8_t& entityId,
359*262276f4SPatrick Venture                                              uint8_t& entityInstance)
360*262276f4SPatrick Venture {
361*262276f4SPatrick Venture     namespace fs = std::filesystem;
362*262276f4SPatrick Venture 
363*262276f4SPatrick Venture     auto sensorAssociationObject =
364*262276f4SPatrick Venture         sensorMap.find("xyz.openbmc_project.Association.Definitions");
365*262276f4SPatrick Venture     if (sensorAssociationObject == sensorMap.end())
366*262276f4SPatrick Venture     {
367*262276f4SPatrick Venture         if constexpr (debug)
368*262276f4SPatrick Venture         {
369*262276f4SPatrick Venture             std::fprintf(stderr, "path=%s, no association interface found\n",
370*262276f4SPatrick Venture                          path.c_str());
371*262276f4SPatrick Venture         }
372*262276f4SPatrick Venture 
373*262276f4SPatrick Venture         return;
374*262276f4SPatrick Venture     }
375*262276f4SPatrick Venture 
376*262276f4SPatrick Venture     auto associationObject =
377*262276f4SPatrick Venture         sensorAssociationObject->second.find("Associations");
378*262276f4SPatrick Venture     if (associationObject == sensorAssociationObject->second.end())
379*262276f4SPatrick Venture     {
380*262276f4SPatrick Venture         if constexpr (debug)
381*262276f4SPatrick Venture         {
382*262276f4SPatrick Venture             std::fprintf(stderr, "path=%s, no association records found\n",
383*262276f4SPatrick Venture                          path.c_str());
384*262276f4SPatrick Venture         }
385*262276f4SPatrick Venture 
386*262276f4SPatrick Venture         return;
387*262276f4SPatrick Venture     }
388*262276f4SPatrick Venture 
389*262276f4SPatrick Venture     std::vector<Association> associationValues =
390*262276f4SPatrick Venture         std::get<std::vector<Association>>(associationObject->second);
391*262276f4SPatrick Venture 
392*262276f4SPatrick Venture     // loop through the Associations looking for the right one:
393*262276f4SPatrick Venture     for (const auto& entry : associationValues)
394*262276f4SPatrick Venture     {
395*262276f4SPatrick Venture         // forward, reverse, endpoint
396*262276f4SPatrick Venture         const std::string& forward = std::get<0>(entry);
397*262276f4SPatrick Venture         const std::string& reverse = std::get<1>(entry);
398*262276f4SPatrick Venture         const std::string& endpoint = std::get<2>(entry);
399*262276f4SPatrick Venture 
400*262276f4SPatrick Venture         // We only currently concern ourselves with chassis+all_sensors.
401*262276f4SPatrick Venture         if (!(forward == "chassis" && reverse == "all_sensors"))
402*262276f4SPatrick Venture         {
403*262276f4SPatrick Venture             continue;
404*262276f4SPatrick Venture         }
405*262276f4SPatrick Venture 
406*262276f4SPatrick Venture         // the endpoint is the board entry provided by
407*262276f4SPatrick Venture         // Entity-Manager. so let's grab its properties if it has
408*262276f4SPatrick Venture         // the right interface.
409*262276f4SPatrick Venture 
410*262276f4SPatrick Venture         // just try grabbing the properties first.
411*262276f4SPatrick Venture         std::map<std::string, DbusVariant> ipmiProperties =
412*262276f4SPatrick Venture             getEntityManagerProperties(
413*262276f4SPatrick Venture                 endpoint.c_str(),
414*262276f4SPatrick Venture                 "xyz.openbmc_project.Inventory.Decorator.Ipmi");
415*262276f4SPatrick Venture 
416*262276f4SPatrick Venture         auto entityIdProp = ipmiProperties.find("EntityId");
417*262276f4SPatrick Venture         auto entityInstanceProp = ipmiProperties.find("EntityInstance");
418*262276f4SPatrick Venture         if (entityIdProp != ipmiProperties.end())
419*262276f4SPatrick Venture         {
420*262276f4SPatrick Venture             entityId =
421*262276f4SPatrick Venture                 static_cast<uint8_t>(std::get<uint64_t>(entityIdProp->second));
422*262276f4SPatrick Venture         }
423*262276f4SPatrick Venture         if (entityInstanceProp != ipmiProperties.end())
424*262276f4SPatrick Venture         {
425*262276f4SPatrick Venture             entityInstance = static_cast<uint8_t>(
426*262276f4SPatrick Venture                 std::get<uint64_t>(entityInstanceProp->second));
427*262276f4SPatrick Venture         }
428*262276f4SPatrick Venture 
429*262276f4SPatrick Venture         // Now check the entity-manager entry for this sensor to see
430*262276f4SPatrick Venture         // if it has its own value and use that instead.
431*262276f4SPatrick Venture         //
432*262276f4SPatrick Venture         // In theory, checking this first saves us from checking
433*262276f4SPatrick Venture         // both, except in most use-cases identified, there won't be
434*262276f4SPatrick Venture         // a per sensor override, so we need to always check both.
435*262276f4SPatrick Venture         std::string sensorNameFromPath = fs::path(path).filename();
436*262276f4SPatrick Venture 
437*262276f4SPatrick Venture         std::string sensorConfigPath = endpoint + "/" + sensorNameFromPath;
438*262276f4SPatrick Venture 
439*262276f4SPatrick Venture         // Download the interfaces for the sensor from
440*262276f4SPatrick Venture         // Entity-Manager to find the name of the configuration
441*262276f4SPatrick Venture         // interface.
442*262276f4SPatrick Venture         std::map<std::string, std::vector<std::string>>
443*262276f4SPatrick Venture             sensorInterfacesResponse =
444*262276f4SPatrick Venture                 getObjectInterfaces(sensorConfigPath.c_str());
445*262276f4SPatrick Venture 
446*262276f4SPatrick Venture         const std::string* configurationInterface =
447*262276f4SPatrick Venture             getSensorConfigurationInterface(sensorInterfacesResponse);
448*262276f4SPatrick Venture 
449*262276f4SPatrick Venture         // We didnt' find a configuration interface for this sensor, but we
450*262276f4SPatrick Venture         // followed the Association property to get here, so we're done
451*262276f4SPatrick Venture         // searching.
452*262276f4SPatrick Venture         if (!configurationInterface)
453*262276f4SPatrick Venture         {
454*262276f4SPatrick Venture             break;
455*262276f4SPatrick Venture         }
456*262276f4SPatrick Venture 
457*262276f4SPatrick Venture         // We found a configuration interface.
458*262276f4SPatrick Venture         std::map<std::string, DbusVariant> configurationProperties =
459*262276f4SPatrick Venture             getEntityManagerProperties(sensorConfigPath.c_str(),
460*262276f4SPatrick Venture                                        configurationInterface->c_str());
461*262276f4SPatrick Venture 
462*262276f4SPatrick Venture         entityIdProp = configurationProperties.find("EntityId");
463*262276f4SPatrick Venture         entityInstanceProp = configurationProperties.find("EntityInstance");
464*262276f4SPatrick Venture         if (entityIdProp != configurationProperties.end())
465*262276f4SPatrick Venture         {
466*262276f4SPatrick Venture             entityId =
467*262276f4SPatrick Venture                 static_cast<uint8_t>(std::get<uint64_t>(entityIdProp->second));
468*262276f4SPatrick Venture         }
469*262276f4SPatrick Venture         if (entityInstanceProp != configurationProperties.end())
470*262276f4SPatrick Venture         {
471*262276f4SPatrick Venture             entityInstance = static_cast<uint8_t>(
472*262276f4SPatrick Venture                 std::get<uint64_t>(entityInstanceProp->second));
473*262276f4SPatrick Venture         }
474*262276f4SPatrick Venture 
475*262276f4SPatrick Venture         // stop searching Association records.
476*262276f4SPatrick Venture         break;
477*262276f4SPatrick Venture     } // end for Association vectors.
478*262276f4SPatrick Venture 
479*262276f4SPatrick Venture     if constexpr (debug)
480*262276f4SPatrick Venture     {
481*262276f4SPatrick Venture         std::fprintf(stderr, "path=%s, entityId=%d, entityInstance=%d\n",
482*262276f4SPatrick Venture                      path.c_str(), entityId, entityInstance);
483*262276f4SPatrick Venture     }
484*262276f4SPatrick Venture }
485*262276f4SPatrick Venture 
486*262276f4SPatrick Venture } // namespace ipmi
487