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