xref: /openbmc/phosphor-pid-control/dbus/dbuspassive.cpp (revision f8cb464498833cc2730b1abf67e2c8006739b45d)
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 "dbus/util.hpp"
19  
20  #include <chrono>
21  #include <cmath>
22  #include <memory>
23  #include <mutex>
24  #include <sdbusplus/bus.hpp>
25  #include <string>
26  
27  std::unique_ptr<ReadInterface> DbusPassive::createDbusPassive(
28      sdbusplus::bus::bus& bus, const std::string& type, const std::string& id,
29      DbusHelperInterface* helper)
30  {
31      if (helper == nullptr)
32      {
33          return nullptr;
34      }
35      if (!validType(type))
36      {
37          return nullptr;
38      }
39  
40      /* Need to get the scale and initial value */
41      auto tempBus = sdbusplus::bus::new_default();
42  
43      /* service == busname */
44      std::string path = getSensorPath(type, id);
45  
46      struct SensorProperties settings;
47      bool failed;
48  
49      try
50      {
51          std::string service = helper->getService(tempBus, sensorintf, path);
52  
53          helper->getProperties(tempBus, service, path, &settings);
54          failed = helper->thresholdsAsserted(tempBus, service, path);
55      }
56      catch (const std::exception& e)
57      {
58          return nullptr;
59      }
60  
61      return std::make_unique<DbusPassive>(bus, type, id, helper, settings,
62                                           failed);
63  }
64  
65  DbusPassive::DbusPassive(sdbusplus::bus::bus& bus, const std::string& type,
66                           const std::string& id, DbusHelperInterface* helper,
67                           const struct SensorProperties& settings, bool failed) :
68      ReadInterface(),
69      _bus(bus), _signal(bus, getMatch(type, id).c_str(), dbusHandleSignal, this),
70      _id(id), _helper(helper), _failed(failed)
71  {
72      _scale = settings.scale;
73      _value = settings.value * pow(10, _scale);
74      _updated = std::chrono::high_resolution_clock::now();
75  }
76  
77  ReadReturn DbusPassive::read(void)
78  {
79      std::lock_guard<std::mutex> guard(_lock);
80  
81      struct ReadReturn r = {_value, _updated};
82  
83      return r;
84  }
85  
86  void DbusPassive::setValue(double value)
87  {
88      std::lock_guard<std::mutex> guard(_lock);
89  
90      _value = value;
91      _updated = std::chrono::high_resolution_clock::now();
92  }
93  
94  bool DbusPassive::getFailed(void) const
95  {
96      return _failed;
97  }
98  
99  void DbusPassive::setFailed(bool value)
100  {
101      _failed = value;
102  }
103  
104  int64_t DbusPassive::getScale(void)
105  {
106      return _scale;
107  }
108  
109  std::string DbusPassive::getID(void)
110  {
111      return _id;
112  }
113  
114  int handleSensorValue(sdbusplus::message::message& msg, DbusPassive* owner)
115  {
116      std::string msgSensor;
117      std::map<std::string, sdbusplus::message::variant<int64_t, double, bool>>
118          msgData;
119  
120      msg.read(msgSensor, msgData);
121  
122      if (msgSensor == "xyz.openbmc_project.Sensor.Value")
123      {
124          auto valPropMap = msgData.find("Value");
125          if (valPropMap != msgData.end())
126          {
127              double value = sdbusplus::message::variant_ns::apply_visitor(
128                  VariantToDoubleVisitor(), valPropMap->second);
129  
130              value *= std::pow(10, owner->getScale());
131  
132              owner->setValue(value);
133          }
134      }
135      else if (msgSensor == "xyz.openbmc_project.Sensor.Threshold.Critical")
136      {
137          auto criticalAlarmLow = msgData.find("CriticalAlarmLow");
138          auto criticalAlarmHigh = msgData.find("CriticalAlarmHigh");
139          if (criticalAlarmHigh == msgData.end() &&
140              criticalAlarmLow == msgData.end())
141          {
142              return 0;
143          }
144  
145          bool asserted = false;
146          if (criticalAlarmLow != msgData.end())
147          {
148              asserted = sdbusplus::message::variant_ns::get<bool>(
149                  criticalAlarmLow->second);
150          }
151  
152          // checking both as in theory you could de-assert one threshold and
153          // assert the other at the same moment
154          if (!asserted && criticalAlarmHigh != msgData.end())
155          {
156              asserted = sdbusplus::message::variant_ns::get<bool>(
157                  criticalAlarmHigh->second);
158          }
159          owner->setFailed(asserted);
160      }
161  
162      return 0;
163  }
164  
165  int dbusHandleSignal(sd_bus_message* msg, void* usrData, sd_bus_error* err)
166  {
167      auto sdbpMsg = sdbusplus::message::message(msg);
168      DbusPassive* obj = static_cast<DbusPassive*>(usrData);
169  
170      return handleSensorValue(sdbpMsg, obj);
171  }
172