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