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 = 46 _bus.new_method_call("xyz.openbmc_project.ObjectMapper", 47 "/xyz/openbmc_project/object_mapper", 48 "xyz.openbmc_project.ObjectMapper", "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::SdBusError& 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, 78 struct SensorProperties* prop) 79 { 80 auto pimMsg = _bus.new_method_call(service.c_str(), path.c_str(), 81 propertiesintf, "GetAll"); 82 83 pimMsg.append(sensorintf); 84 85 PropertyMap propMap; 86 87 try 88 { 89 auto valueResponseMsg = _bus.call(pimMsg); 90 valueResponseMsg.read(propMap); 91 } 92 catch (const sdbusplus::exception::SdBusError& ex) 93 { 94 log<level::ERR>("GetAll Properties Failed", 95 entry("WHAT=%s", ex.what())); 96 throw; 97 } 98 99 // The PropertyMap returned will look like this because it's always 100 // reading a Sensor.Value interface. 101 // a{sv} 3: 102 // "Value" x 24875 103 // "Unit" s "xyz.openbmc_project.Sensor.Value.Unit.DegreesC" 104 // "Scale" x -3 105 106 // If no error was set, the values should all be there. 107 auto findUnit = propMap.find("Unit"); 108 if (findUnit != propMap.end()) 109 { 110 prop->unit = std::get<std::string>(findUnit->second); 111 } 112 auto findScale = propMap.find("Scale"); 113 auto findMax = propMap.find("MaxValue"); 114 auto findMin = propMap.find("MinValue"); 115 116 prop->min = 0; 117 prop->max = 0; 118 prop->scale = 0; 119 if (findScale != propMap.end()) 120 { 121 prop->scale = std::get<int64_t>(findScale->second); 122 } 123 if (findMax != propMap.end()) 124 { 125 prop->max = std::visit(VariantToDoubleVisitor(), findMax->second); 126 } 127 if (findMin != propMap.end()) 128 { 129 prop->min = std::visit(VariantToDoubleVisitor(), findMin->second); 130 } 131 132 prop->value = std::visit(VariantToDoubleVisitor(), propMap["Value"]); 133 134 return; 135 } 136 137 bool DbusHelper::thresholdsAsserted(const std::string& service, 138 const std::string& path) 139 { 140 141 auto critical = _bus.new_method_call(service.c_str(), path.c_str(), 142 propertiesintf, "GetAll"); 143 critical.append(criticalThreshInf); 144 PropertyMap criticalMap; 145 146 try 147 { 148 auto msg = _bus.call(critical); 149 msg.read(criticalMap); 150 } 151 catch (sdbusplus::exception_t&) 152 { 153 // do nothing, sensors don't have to expose critical thresholds 154 return false; 155 } 156 157 auto findCriticalLow = criticalMap.find("CriticalAlarmLow"); 158 auto findCriticalHigh = criticalMap.find("CriticalAlarmHigh"); 159 160 bool asserted = false; 161 if (findCriticalLow != criticalMap.end()) 162 { 163 asserted = std::get<bool>(findCriticalLow->second); 164 } 165 166 // as we are catching properties changed, a sensor could theoretically jump 167 // from one threshold to the other in one event, so check both thresholds 168 if (!asserted && findCriticalHigh != criticalMap.end()) 169 { 170 asserted = std::get<bool>(findCriticalHigh->second); 171 } 172 return asserted; 173 } 174 175 } // namespace pid_control 176