1 /*
2 // Copyright (c) 2018 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16 
17 #include <boost/algorithm/string.hpp>
18 #include <boost/container/flat_map.hpp>
19 #include <cstring>
20 #include <phosphor-logging/log.hpp>
21 #include <storagecommands.hpp>
22 
23 #pragma once
24 
25 struct CmpStrVersion
26 {
27     bool operator()(std::string a, std::string b) const
28     {
29         return strverscmp(a.c_str(), b.c_str()) < 0;
30     }
31 };
32 
33 using SensorSubTree = boost::container::flat_map<
34     std::string,
35     boost::container::flat_map<std::string, std::vector<std::string>>,
36     CmpStrVersion>;
37 
38 inline static bool getSensorSubtree(SensorSubTree& subtree)
39 {
40     sd_bus* bus = NULL;
41     int ret = sd_bus_default_system(&bus);
42     if (ret < 0)
43     {
44         phosphor::logging::log<phosphor::logging::level::ERR>(
45             "Failed to connect to system bus",
46             phosphor::logging::entry("ERRNO=0x%X", -ret));
47         sd_bus_unref(bus);
48         return false;
49     }
50     sdbusplus::bus::bus dbus(bus);
51     auto mapperCall =
52         dbus.new_method_call("xyz.openbmc_project.ObjectMapper",
53                              "/xyz/openbmc_project/object_mapper",
54                              "xyz.openbmc_project.ObjectMapper", "GetSubTree");
55     static const auto depth = 2;
56     static constexpr std::array<const char*, 3> interfaces = {
57         "xyz.openbmc_project.Sensor.Value",
58         "xyz.openbmc_project.Sensor.Threshold.Warning",
59         "xyz.openbmc_project.Sensor.Threshold.Critical"};
60     mapperCall.append("/xyz/openbmc_project/sensors", depth, interfaces);
61 
62     try
63     {
64         auto mapperReply = dbus.call(mapperCall);
65         subtree.clear();
66         mapperReply.read(subtree);
67     }
68     catch (sdbusplus::exception_t&)
69     {
70         phosphor::logging::log<phosphor::logging::level::ERR>(
71             "getSensorSubtree: Error calling mapper");
72         return false;
73     }
74     return true;
75 }
76 
77 struct CmpStr
78 {
79     bool operator()(const char* a, const char* b) const
80     {
81         return std::strcmp(a, b) < 0;
82     }
83 };
84 
85 const static boost::container::flat_map<const char*, SensorTypeCodes, CmpStr>
86     sensorTypes{{{"temperature", SensorTypeCodes::temperature},
87                  {"voltage", SensorTypeCodes::voltage},
88                  {"current", SensorTypeCodes::current},
89                  {"fan_tach", SensorTypeCodes::fan},
90                  {"power", SensorTypeCodes::other}}};
91 
92 inline static std::string getSensorTypeStringFromPath(const std::string& path)
93 {
94     // get sensor type string from path, path is defined as
95     // /xyz/openbmc_project/sensors/<type>/label
96     size_t typeEnd = path.rfind("/");
97     size_t typeStart = path.rfind("/", typeEnd - 1);
98     if (typeEnd != std::string::npos && typeStart != std::string::npos)
99     {
100         return path.substr(typeStart + 1, typeEnd - typeStart);
101     }
102     return path;
103 }
104 
105 inline static uint8_t getSensorTypeFromPath(const std::string& path)
106 {
107     uint8_t sensorType = 0;
108     std::string type = getSensorTypeStringFromPath(path);
109     auto findSensor = sensorTypes.find(type.c_str());
110     if (findSensor != sensorTypes.end())
111     {
112         sensorType = static_cast<uint8_t>(findSensor->second);
113     } // else default 0x0 RESERVED
114 
115     return sensorType;
116 }
117 
118 inline static uint8_t getSensorNumberFromPath(const std::string& path)
119 {
120     SensorSubTree sensorTree;
121     if (!getSensorSubtree(sensorTree))
122         return 0xFF;
123     uint8_t sensorNum = 0xFF;
124 
125     for (const auto& sensor : sensorTree)
126     {
127         sensorNum++;
128         if (sensor.first == path)
129         {
130             break;
131         }
132     }
133     return sensorNum;
134 }
135 
136 inline static uint8_t getSensorEventTypeFromPath(const std::string& path)
137 {
138     // TODO: Add support for additional reading types as needed
139     return 0x1; // reading type = threshold
140 }
141 
142 inline static std::string getPathFromSensorNumber(uint8_t sensorNum)
143 {
144     SensorSubTree sensorTree;
145     std::string path;
146     if (!getSensorSubtree(sensorTree))
147         return path;
148 
149     if (sensorTree.size() < sensorNum)
150     {
151         return path;
152     }
153 
154     uint8_t sensorIndex = sensorNum;
155     for (const auto& sensor : sensorTree)
156     {
157         if (sensorIndex-- == 0)
158         {
159             path = sensor.first;
160             break;
161         }
162     }
163 
164     return path;
165 }
166