1 // SPDX-License-Identifier: Apache-2.0 2 // SPDX-FileCopyrightText: Copyright 2017 Google Inc 3 4 #include "config.h" 5 6 #include "dbushelper.hpp" 7 8 #include "dbushelper_interface.hpp" 9 #include "dbusutil.hpp" 10 11 #include <phosphor-logging/log.hpp> 12 #include <sdbusplus/bus.hpp> 13 #include <sdbusplus/exception.hpp> 14 15 #include <cstdint> 16 #include <map> 17 #include <stdexcept> 18 #include <string> 19 #include <variant> 20 #include <vector> 21 22 namespace pid_control 23 { 24 25 using Property = std::string; 26 using Value = std::variant<int64_t, double, std::string, bool>; 27 using PropertyMap = std::map<Property, Value>; 28 29 using namespace phosphor::logging; 30 31 /* TODO(venture): Basically all phosphor apps need this, maybe it should be a 32 * part of sdbusplus. There is an old version in libmapper. 33 */ 34 std::string DbusHelper::getService(const std::string& intf, 35 const std::string& path) 36 { 37 auto mapper = 38 _bus.new_method_call("xyz.openbmc_project.ObjectMapper", 39 "/xyz/openbmc_project/object_mapper", 40 "xyz.openbmc_project.ObjectMapper", "GetObject"); 41 42 mapper.append(path); 43 mapper.append(std::vector<std::string>({intf})); 44 45 std::map<std::string, std::vector<std::string>> response; 46 47 try 48 { 49 auto responseMsg = _bus.call(mapper); 50 51 responseMsg.read(response); 52 } 53 catch (const sdbusplus::exception_t& ex) 54 { 55 log<level::ERR>("ObjectMapper call failure", 56 entry("WHAT=%s", ex.what())); 57 throw; 58 } 59 60 if (response.begin() == response.end()) 61 { 62 throw std::runtime_error("Unable to find Object: " + path); 63 } 64 65 return response.begin()->first; 66 } 67 68 void DbusHelper::getProperties(const std::string& service, 69 const std::string& path, SensorProperties* prop) 70 { 71 auto pimMsg = _bus.new_method_call(service.c_str(), path.c_str(), 72 propertiesintf, "GetAll"); 73 74 pimMsg.append(sensorintf); 75 76 PropertyMap propMap; 77 78 try 79 { 80 auto valueResponseMsg = _bus.call(pimMsg); 81 valueResponseMsg.read(propMap); 82 } 83 catch (const sdbusplus::exception_t& ex) 84 { 85 log<level::ERR>("GetAll Properties Failed", 86 entry("WHAT=%s", ex.what())); 87 throw; 88 } 89 90 // The PropertyMap returned will look like this because it's always 91 // reading a Sensor.Value interface. 92 // a{sv} 3: 93 // "Value" x 24875 94 // "Unit" s "xyz.openbmc_project.Sensor.Value.Unit.DegreesC" 95 // "Scale" x -3 96 97 // If no error was set, the values should all be there. 98 auto findUnit = propMap.find("Unit"); 99 if (findUnit != propMap.end()) 100 { 101 prop->unit = std::get<std::string>(findUnit->second); 102 } 103 auto findScale = propMap.find("Scale"); 104 auto findMax = propMap.find("MaxValue"); 105 auto findMin = propMap.find("MinValue"); 106 107 prop->min = 0; 108 prop->max = 0; 109 prop->scale = 0; 110 if (findScale != propMap.end()) 111 { 112 prop->scale = std::get<int64_t>(findScale->second); 113 } 114 if (findMax != propMap.end()) 115 { 116 prop->max = std::visit(VariantToDoubleVisitor(), findMax->second); 117 } 118 if (findMin != propMap.end()) 119 { 120 prop->min = std::visit(VariantToDoubleVisitor(), findMin->second); 121 } 122 123 prop->value = std::visit(VariantToDoubleVisitor(), propMap["Value"]); 124 125 bool available = true; 126 try 127 { 128 getProperty(service, path, availabilityIntf, "Available", available); 129 } 130 catch (const sdbusplus::exception_t& ex) 131 { 132 // unsupported Available property, leaving reading at 'True' 133 } 134 prop->available = available; 135 136 return; 137 } 138 139 bool DbusHelper::thresholdsAsserted(const std::string& service, 140 const std::string& path) 141 { 142 auto critical = _bus.new_method_call(service.c_str(), path.c_str(), 143 propertiesintf, "GetAll"); 144 critical.append(criticalThreshInf); 145 PropertyMap criticalMap; 146 147 try 148 { 149 auto msg = _bus.call(critical); 150 msg.read(criticalMap); 151 } 152 catch (const sdbusplus::exception_t&) 153 { 154 // do nothing, sensors don't have to expose critical thresholds 155 #ifndef UNC_FAILSAFE 156 return false; 157 #endif 158 } 159 160 auto findCriticalLow = criticalMap.find("CriticalAlarmLow"); 161 auto findCriticalHigh = criticalMap.find("CriticalAlarmHigh"); 162 163 bool asserted = false; 164 if (findCriticalLow != criticalMap.end()) 165 { 166 asserted = std::get<bool>(findCriticalLow->second); 167 } 168 169 // as we are catching properties changed, a sensor could theoretically jump 170 // from one threshold to the other in one event, so check both thresholds 171 if (!asserted && findCriticalHigh != criticalMap.end()) 172 { 173 asserted = std::get<bool>(findCriticalHigh->second); 174 } 175 #ifdef UNC_FAILSAFE 176 if (!asserted) 177 { 178 auto warning = _bus.new_method_call(service.c_str(), path.c_str(), 179 propertiesintf, "GetAll"); 180 warning.append(warningThreshInf); 181 PropertyMap warningMap; 182 183 try 184 { 185 auto msg = _bus.call(warning); 186 msg.read(warningMap); 187 } 188 catch (const sdbusplus::exception_t&) 189 { 190 // sensors don't have to expose non-critical thresholds 191 return false; 192 } 193 auto findWarningHigh = warningMap.find("WarningAlarmHigh"); 194 195 if (findWarningHigh != warningMap.end()) 196 { 197 asserted = std::get<bool>(findWarningHigh->second); 198 } 199 } 200 #endif 201 return asserted; 202 } 203 204 } // namespace pid_control 205