blob: 21878f340c384ab08c417e0594034c89d14e9cdf [file] [log] [blame]
James Feist8fd8a582018-11-16 11:10:46 -08001#pragma once
2
Patrick Ventureca44b2f2019-10-31 11:02:26 -07003#include "Thresholds.hpp"
4
James Feist38fb5982020-05-28 10:09:54 -07005#include <sdbusplus/asio/object_server.hpp>
6
Patrick Venturefd6ba732019-10-31 14:27:39 -07007#include <limits>
8#include <memory>
Patrick Venturefd6ba732019-10-31 14:27:39 -07009#include <string>
10#include <vector>
James Feist8fd8a582018-11-16 11:10:46 -080011
James Feist1169eb42018-10-31 10:08:47 -070012constexpr size_t sensorFailedPollTimeMs = 5000;
James Feista5e58722019-04-22 14:43:11 -070013
14constexpr const char* sensorValueInterface = "xyz.openbmc_project.Sensor.Value";
James Feist67601bd2020-06-16 17:14:44 -070015constexpr const char* availableInterfaceName =
16 "xyz.openbmc_project.State.Decorator.Availability";
James Feist8fd8a582018-11-16 11:10:46 -080017struct Sensor
18{
James Feist930fcde2019-05-28 12:58:43 -070019 Sensor(const std::string& name,
James Feistd8705872019-02-08 13:26:09 -080020 std::vector<thresholds::Threshold>&& thresholdData,
21 const std::string& configurationPath, const std::string& objectType,
James Feistce3fca42018-11-21 12:58:24 -080022 const double max, const double min) :
AppaRao Puli54ffb272020-06-02 19:09:38 +053023 name(std::regex_replace(name, std::regex("[^a-zA-Z0-9_/]+"), "_")),
James Feist930fcde2019-05-28 12:58:43 -070024 configurationPath(configurationPath), objectType(objectType),
Brad Bishopfbb44ad2019-11-08 09:42:37 -050025 maxValue(max), minValue(min), thresholds(std::move(thresholdData)),
Josh Lehan883fb3a2020-02-27 14:41:39 -080026 hysteresisTrigger((max - min) * 0.01),
27 hysteresisPublish((max - min) * 0.0001)
James Feist38fb5982020-05-28 10:09:54 -070028 {}
James Feist8fd8a582018-11-16 11:10:46 -080029 virtual ~Sensor() = default;
James Feistce3fca42018-11-21 12:58:24 -080030 virtual void checkThresholds(void) = 0;
James Feistdc6c55f2018-10-31 12:53:20 -070031 std::string name;
James Feistce3fca42018-11-21 12:58:24 -080032 std::string configurationPath;
33 std::string objectType;
34 double maxValue;
35 double minValue;
James Feist8fd8a582018-11-16 11:10:46 -080036 std::vector<thresholds::Threshold> thresholds;
37 std::shared_ptr<sdbusplus::asio::dbus_interface> sensorInterface;
38 std::shared_ptr<sdbusplus::asio::dbus_interface> thresholdInterfaceWarning;
39 std::shared_ptr<sdbusplus::asio::dbus_interface> thresholdInterfaceCritical;
James Feist078f2322019-03-08 11:09:05 -080040 std::shared_ptr<sdbusplus::asio::dbus_interface> association;
James Feist67601bd2020-06-16 17:14:44 -070041 std::shared_ptr<sdbusplus::asio::dbus_interface> availableInterface;
James Feist8fd8a582018-11-16 11:10:46 -080042 double value = std::numeric_limits<double>::quiet_NaN();
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +053043 bool overriddenState = false;
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +053044 bool internalSet = false;
James Feist67601bd2020-06-16 17:14:44 -070045 bool available = true;
Josh Lehan883fb3a2020-02-27 14:41:39 -080046 double hysteresisTrigger;
47 double hysteresisPublish;
James Feistce3fca42018-11-21 12:58:24 -080048
James Feistd8705872019-02-08 13:26:09 -080049 int setSensorValue(const double& newValue, double& oldValue)
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +053050 {
Richard Marian Thomaiyaraf6b87c2019-04-03 23:54:28 +053051 if (!internalSet)
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +053052 {
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +053053 oldValue = newValue;
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +053054 overriddenState = true;
55 // check thresholds for external set
56 value = newValue;
57 checkThresholds();
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +053058 }
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +053059 else if (!overriddenState)
Richard Marian Thomaiyaraf6b87c2019-04-03 23:54:28 +053060 {
61 oldValue = newValue;
62 }
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +053063 return 1;
64 }
James Feistce3fca42018-11-21 12:58:24 -080065
66 void
Cheng C Yang6b1247a2020-03-09 23:48:39 +080067 setInitialProperties(std::shared_ptr<sdbusplus::asio::connection>& conn,
68 const std::string label = std::string(),
69 size_t thresholdSize = 0)
James Feistce3fca42018-11-21 12:58:24 -080070 {
James Feist82bac4c2019-03-11 11:16:53 -070071 createAssociation(association, configurationPath);
AppaRao Pulic82213c2020-02-27 01:24:58 +053072
James Feistce3fca42018-11-21 12:58:24 -080073 sensorInterface->register_property("MaxValue", maxValue);
74 sensorInterface->register_property("MinValue", minValue);
75 sensorInterface->register_property(
James Feistd8705872019-02-08 13:26:09 -080076 "Value", value, [&](const double& newValue, double& oldValue) {
James Feistce3fca42018-11-21 12:58:24 -080077 return setSensorValue(newValue, oldValue);
78 });
James Feistd8705872019-02-08 13:26:09 -080079 for (auto& threshold : thresholds)
James Feistce3fca42018-11-21 12:58:24 -080080 {
81 std::shared_ptr<sdbusplus::asio::dbus_interface> iface;
82 std::string level;
83 std::string alarm;
84 if (threshold.level == thresholds::Level::CRITICAL)
85 {
86 iface = thresholdInterfaceCritical;
87 if (threshold.direction == thresholds::Direction::HIGH)
88 {
89 level = "CriticalHigh";
90 alarm = "CriticalAlarmHigh";
91 }
92 else
93 {
94 level = "CriticalLow";
95 alarm = "CriticalAlarmLow";
96 }
97 }
98 else if (threshold.level == thresholds::Level::WARNING)
99 {
100 iface = thresholdInterfaceWarning;
101 if (threshold.direction == thresholds::Direction::HIGH)
102 {
103 level = "WarningHigh";
104 alarm = "WarningAlarmHigh";
105 }
106 else
107 {
108 level = "WarningLow";
109 alarm = "WarningAlarmLow";
110 }
111 }
112 else
113 {
114 std::cerr << "Unknown threshold level" << threshold.level
115 << "\n";
116 continue;
117 }
118 if (!iface)
119 {
120 std::cout << "trying to set uninitialized interface\n";
121 continue;
122 }
Cheng C Yang6b1247a2020-03-09 23:48:39 +0800123
124 size_t thresSize =
125 label.empty() ? thresholds.size() : thresholdSize;
James Feistce3fca42018-11-21 12:58:24 -0800126 iface->register_property(
127 level, threshold.value,
Cheng C Yang6b1247a2020-03-09 23:48:39 +0800128 [&, label, thresSize](const double& request, double& oldValue) {
James Feistce3fca42018-11-21 12:58:24 -0800129 oldValue = request; // todo, just let the config do this?
130 threshold.value = request;
131 thresholds::persistThreshold(configurationPath, objectType,
Cheng C Yang6b1247a2020-03-09 23:48:39 +0800132 threshold, conn, thresSize,
133 label);
Josh Lehan883fb3a2020-02-27 14:41:39 -0800134 // Invalidate previously remembered value,
135 // so new thresholds will be checked during next update,
136 // even if sensor reading remains unchanged.
137 value = std::numeric_limits<double>::quiet_NaN();
138
139 // Although tempting, don't call checkThresholds() from here
140 // directly. Let the regular sensor monitor call the same
141 // using updateValue(), which can check conditions like
142 // poweron, etc., before raising any event.
James Feistce3fca42018-11-21 12:58:24 -0800143 return 1;
144 });
145 iface->register_property(alarm, false);
146 }
147 if (!sensorInterface->initialize())
148 {
149 std::cerr << "error initializing value interface\n";
150 }
151 if (thresholdInterfaceWarning &&
Yong Lif902c052020-05-07 17:13:53 +0800152 !thresholdInterfaceWarning->initialize(true))
James Feistce3fca42018-11-21 12:58:24 -0800153 {
154 std::cerr << "error initializing warning threshold interface\n";
155 }
156
157 if (thresholdInterfaceCritical &&
Yong Lif902c052020-05-07 17:13:53 +0800158 !thresholdInterfaceCritical->initialize(true))
James Feistce3fca42018-11-21 12:58:24 -0800159 {
160 std::cerr << "error initializing critical threshold interface\n";
161 }
James Feist67601bd2020-06-16 17:14:44 -0700162
163 if (!availableInterface)
164 {
165 availableInterface =
166 std::make_shared<sdbusplus::asio::dbus_interface>(
167 conn, sensorInterface->get_object_path(),
168 availableInterfaceName);
169 availableInterface->register_property(
170 "Available", true, [this](const bool propIn, bool& old) {
171 if (propIn == old)
172 {
173 return 1;
174 }
175 if (!propIn)
176 {
177 updateValue(std::numeric_limits<double>::quiet_NaN());
178 }
179 old = propIn;
180 available = propIn;
181 return 1;
182 });
183 availableInterface->initialize();
184 }
James Feistce3fca42018-11-21 12:58:24 -0800185 }
186
James Feistd8705872019-02-08 13:26:09 -0800187 void updateValue(const double& newValue)
James Feistce3fca42018-11-21 12:58:24 -0800188 {
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530189 // Ignore if overriding is enabled
James Feist67601bd2020-06-16 17:14:44 -0700190 if (overriddenState || !available)
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530191 {
Josh Lehan883fb3a2020-02-27 14:41:39 -0800192 return;
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530193 }
Josh Lehan883fb3a2020-02-27 14:41:39 -0800194
Josh Lehan883fb3a2020-02-27 14:41:39 -0800195 // Indicate that it is internal set call
196 internalSet = true;
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200197 updateProperty(sensorInterface, value, newValue, "Value");
Josh Lehan883fb3a2020-02-27 14:41:39 -0800198 internalSet = false;
199
200 // Always check thresholds after changing the value,
201 // as the test against hysteresisTrigger now takes place in
202 // the thresholds::checkThresholds() method,
203 // which is called by checkThresholds() below,
204 // in all current implementations of sensors that have thresholds.
205 checkThresholds();
James Feistce3fca42018-11-21 12:58:24 -0800206 }
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200207
208 void updateProperty(
209 std::shared_ptr<sdbusplus::asio::dbus_interface>& interface,
210 double& oldValue, const double& newValue, const char* dbusPropertyName)
211 {
212 if (requiresUpdate(oldValue, newValue))
213 {
214 oldValue = newValue;
215 if (!(interface->set_property(dbusPropertyName, newValue)))
216 {
217 std::cerr << "error setting property " << dbusPropertyName
218 << " to " << newValue << "\n";
219 }
220 }
221 }
222
223 bool requiresUpdate(const double& lVal, const double& rVal)
224 {
225 if (std::isnan(lVal) || std::isnan(rVal))
226 {
227 return true;
228 }
229 double diff = std::abs(lVal - rVal);
230 if (diff > hysteresisPublish)
231 {
232 return true;
233 }
234 return false;
235 }
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530236};