/** * Copyright 2017 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "config.h" #include "dbushelper.hpp" #include "dbushelper_interface.hpp" #include "dbusutil.hpp" #include #include #include #include #include #include namespace pid_control { using Property = std::string; using Value = std::variant; using PropertyMap = std::map; using namespace phosphor::logging; /* TODO(venture): Basically all phosphor apps need this, maybe it should be a * part of sdbusplus. There is an old version in libmapper. */ std::string DbusHelper::getService(const std::string& intf, const std::string& path) { auto mapper = _bus.new_method_call("xyz.openbmc_project.ObjectMapper", "/xyz/openbmc_project/object_mapper", "xyz.openbmc_project.ObjectMapper", "GetObject"); mapper.append(path); mapper.append(std::vector({intf})); std::map> response; try { auto responseMsg = _bus.call(mapper); responseMsg.read(response); } catch (const sdbusplus::exception_t& ex) { log("ObjectMapper call failure", entry("WHAT=%s", ex.what())); throw; } if (response.begin() == response.end()) { throw std::runtime_error("Unable to find Object: " + path); } return response.begin()->first; } void DbusHelper::getProperties(const std::string& service, const std::string& path, SensorProperties* prop) { auto pimMsg = _bus.new_method_call(service.c_str(), path.c_str(), propertiesintf, "GetAll"); pimMsg.append(sensorintf); PropertyMap propMap; try { auto valueResponseMsg = _bus.call(pimMsg); valueResponseMsg.read(propMap); } catch (const sdbusplus::exception_t& ex) { log("GetAll Properties Failed", entry("WHAT=%s", ex.what())); throw; } // The PropertyMap returned will look like this because it's always // reading a Sensor.Value interface. // a{sv} 3: // "Value" x 24875 // "Unit" s "xyz.openbmc_project.Sensor.Value.Unit.DegreesC" // "Scale" x -3 // If no error was set, the values should all be there. auto findUnit = propMap.find("Unit"); if (findUnit != propMap.end()) { prop->unit = std::get(findUnit->second); } auto findScale = propMap.find("Scale"); auto findMax = propMap.find("MaxValue"); auto findMin = propMap.find("MinValue"); prop->min = 0; prop->max = 0; prop->scale = 0; if (findScale != propMap.end()) { prop->scale = std::get(findScale->second); } if (findMax != propMap.end()) { prop->max = std::visit(VariantToDoubleVisitor(), findMax->second); } if (findMin != propMap.end()) { prop->min = std::visit(VariantToDoubleVisitor(), findMin->second); } prop->value = std::visit(VariantToDoubleVisitor(), propMap["Value"]); bool available = true; try { getProperty(service, path, availabilityIntf, "Available", available); } catch (const sdbusplus::exception_t& ex) { // unsupported Available property, leaving reading at 'True' } prop->available = available; return; } bool DbusHelper::thresholdsAsserted(const std::string& service, const std::string& path) { auto critical = _bus.new_method_call(service.c_str(), path.c_str(), propertiesintf, "GetAll"); critical.append(criticalThreshInf); PropertyMap criticalMap; try { auto msg = _bus.call(critical); msg.read(criticalMap); } catch (const sdbusplus::exception_t&) { // do nothing, sensors don't have to expose critical thresholds #ifndef UNC_FAILSAFE return false; #endif } auto findCriticalLow = criticalMap.find("CriticalAlarmLow"); auto findCriticalHigh = criticalMap.find("CriticalAlarmHigh"); bool asserted = false; if (findCriticalLow != criticalMap.end()) { asserted = std::get(findCriticalLow->second); } // as we are catching properties changed, a sensor could theoretically jump // from one threshold to the other in one event, so check both thresholds if (!asserted && findCriticalHigh != criticalMap.end()) { asserted = std::get(findCriticalHigh->second); } #ifdef UNC_FAILSAFE if (!asserted) { auto warning = _bus.new_method_call(service.c_str(), path.c_str(), propertiesintf, "GetAll"); warning.append(warningThreshInf); PropertyMap warningMap; try { auto msg = _bus.call(warning); msg.read(warningMap); } catch (const sdbusplus::exception_t&) { // sensors don't have to expose non-critical thresholds return false; } auto findWarningHigh = warningMap.find("WarningAlarmHigh"); if (findWarningHigh != warningMap.end()) { asserted = std::get(findWarningHigh->second); } } #endif return asserted; } } // namespace pid_control