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