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 #include "dbuspassive.hpp" 17 18 #include "dbuspassiveredundancy.hpp" 19 #include "util.hpp" 20 21 #include <sdbusplus/bus.hpp> 22 23 #include <chrono> 24 #include <cmath> 25 #include <memory> 26 #include <mutex> 27 #include <string> 28 #include <variant> 29 30 std::unique_ptr<ReadInterface> DbusPassive::createDbusPassive( 31 sdbusplus::bus::bus& bus, const std::string& type, const std::string& id, 32 DbusHelperInterface* helper, const conf::SensorConfig* info, 33 const std::shared_ptr<DbusPassiveRedundancy>& redundancy) 34 { 35 if (helper == nullptr) 36 { 37 return nullptr; 38 } 39 if (!validType(type)) 40 { 41 return nullptr; 42 } 43 44 /* Need to get the scale and initial value */ 45 auto tempBus = sdbusplus::bus::new_system(); 46 47 /* service == busname */ 48 std::string path = getSensorPath(type, id); 49 50 struct SensorProperties settings; 51 bool failed; 52 53 try 54 { 55 std::string service = helper->getService(tempBus, sensorintf, path); 56 57 helper->getProperties(tempBus, service, path, &settings); 58 failed = helper->thresholdsAsserted(tempBus, service, path); 59 } 60 catch (const std::exception& e) 61 { 62 return nullptr; 63 } 64 65 /* if these values are zero, they're ignored. */ 66 if (info->ignoreDbusMinMax) 67 { 68 settings.min = 0; 69 settings.max = 0; 70 } 71 72 return std::make_unique<DbusPassive>(bus, type, id, helper, settings, 73 failed, path, redundancy); 74 } 75 76 DbusPassive::DbusPassive( 77 sdbusplus::bus::bus& bus, const std::string& type, const std::string& id, 78 DbusHelperInterface* helper, const struct SensorProperties& settings, 79 bool failed, const std::string& path, 80 const std::shared_ptr<DbusPassiveRedundancy>& redundancy) : 81 ReadInterface(), 82 _bus(bus), _signal(bus, getMatch(type, id).c_str(), dbusHandleSignal, this), 83 _id(id), _helper(helper), _failed(failed), path(path), 84 redundancy(redundancy) 85 86 { 87 _scale = settings.scale; 88 _value = settings.value * pow(10, _scale); 89 _min = settings.min * pow(10, _scale); 90 _max = settings.max * pow(10, _scale); 91 _updated = std::chrono::high_resolution_clock::now(); 92 } 93 94 ReadReturn DbusPassive::read(void) 95 { 96 std::lock_guard<std::mutex> guard(_lock); 97 98 struct ReadReturn r = {_value, _updated}; 99 100 return r; 101 } 102 103 void DbusPassive::setValue(double value) 104 { 105 std::lock_guard<std::mutex> guard(_lock); 106 107 _value = value; 108 _updated = std::chrono::high_resolution_clock::now(); 109 } 110 111 bool DbusPassive::getFailed(void) const 112 { 113 if (redundancy) 114 { 115 const std::set<std::string>& failures = redundancy->getFailed(); 116 if (failures.find(path) != failures.end()) 117 { 118 return true; 119 } 120 } 121 122 return _failed || !_functional; 123 } 124 125 void DbusPassive::setFailed(bool value) 126 { 127 _failed = value; 128 } 129 130 void DbusPassive::setFunctional(bool value) 131 { 132 _functional = value; 133 } 134 135 int64_t DbusPassive::getScale(void) 136 { 137 return _scale; 138 } 139 140 std::string DbusPassive::getID(void) 141 { 142 return _id; 143 } 144 145 double DbusPassive::getMax(void) 146 { 147 return _max; 148 } 149 150 double DbusPassive::getMin(void) 151 { 152 return _min; 153 } 154 155 int handleSensorValue(sdbusplus::message::message& msg, DbusPassive* owner) 156 { 157 std::string msgSensor; 158 std::map<std::string, std::variant<int64_t, double, bool>> msgData; 159 160 msg.read(msgSensor, msgData); 161 162 if (msgSensor == "xyz.openbmc_project.Sensor.Value") 163 { 164 auto valPropMap = msgData.find("Value"); 165 if (valPropMap != msgData.end()) 166 { 167 double value = 168 std::visit(VariantToDoubleVisitor(), valPropMap->second); 169 170 value *= std::pow(10, owner->getScale()); 171 172 scaleSensorReading(owner->getMin(), owner->getMax(), value); 173 174 owner->setValue(value); 175 } 176 } 177 else if (msgSensor == "xyz.openbmc_project.Sensor.Threshold.Critical") 178 { 179 auto criticalAlarmLow = msgData.find("CriticalAlarmLow"); 180 auto criticalAlarmHigh = msgData.find("CriticalAlarmHigh"); 181 if (criticalAlarmHigh == msgData.end() && 182 criticalAlarmLow == msgData.end()) 183 { 184 return 0; 185 } 186 187 bool asserted = false; 188 if (criticalAlarmLow != msgData.end()) 189 { 190 asserted = std::get<bool>(criticalAlarmLow->second); 191 } 192 193 // checking both as in theory you could de-assert one threshold and 194 // assert the other at the same moment 195 if (!asserted && criticalAlarmHigh != msgData.end()) 196 { 197 asserted = std::get<bool>(criticalAlarmHigh->second); 198 } 199 owner->setFailed(asserted); 200 } 201 else if (msgSensor == 202 "xyz.openbmc_project.State.Decorator.OperationalStatus") 203 { 204 auto functional = msgData.find("Functional"); 205 if (functional == msgData.end()) 206 { 207 return 0; 208 } 209 bool asserted = std::get<bool>(functional->second); 210 owner->setFunctional(asserted); 211 } 212 213 return 0; 214 } 215 216 int dbusHandleSignal(sd_bus_message* msg, void* usrData, sd_bus_error* err) 217 { 218 auto sdbpMsg = sdbusplus::message::message(msg); 219 DbusPassive* obj = static_cast<DbusPassive*>(usrData); 220 221 return handleSensorValue(sdbpMsg, obj); 222 } 223