xref: /openbmc/phosphor-hwmon/thresholds.hpp (revision ad6043f6)
1 #pragma once
2 
3 #include "env.hpp"
4 #include "interface.hpp"
5 
6 #include <cmath>
7 
8 /** @class Thresholds
9  *  @brief Threshold type traits.
10  *
11  *  @tparam T - The threshold type.
12  */
13 template <typename T>
14 struct Thresholds
15 {
failThresholds16     static void fail()
17     {
18         static_assert(sizeof(Thresholds) == -1, "Unsupported Threshold type");
19     }
20 };
21 
22 /**@brief Thresholds specialization for warning thresholds. */
23 template <>
24 struct Thresholds<WarningObject>
25 {
26     static constexpr InterfaceType type = InterfaceType::WARN;
27     static constexpr const char* envLo = "WARNLO";
28     static constexpr const char* envHi = "WARNHI";
29     static SensorValueType (WarningObject::*const setLo)(SensorValueType);
30     static SensorValueType (WarningObject::*const setHi)(SensorValueType);
31     static SensorValueType (WarningObject::*const getLo)() const;
32     static SensorValueType (WarningObject::*const getHi)() const;
33     static bool (WarningObject::*const alarmLo)(bool);
34     static bool (WarningObject::*const alarmHi)(bool);
35     static bool (WarningObject::*const getAlarmLow)() const;
36     static bool (WarningObject::*const getAlarmHigh)() const;
37     static void (WarningObject::*const assertLowSignal)(SensorValueType);
38     static void (WarningObject::*const assertHighSignal)(SensorValueType);
39     static void (WarningObject::*const deassertLowSignal)(SensorValueType);
40     static void (WarningObject::*const deassertHighSignal)(SensorValueType);
41 };
42 
43 /**@brief Thresholds specialization for critical thresholds. */
44 template <>
45 struct Thresholds<CriticalObject>
46 {
47     static constexpr InterfaceType type = InterfaceType::CRIT;
48     static constexpr const char* envLo = "CRITLO";
49     static constexpr const char* envHi = "CRITHI";
50     static SensorValueType (CriticalObject::*const setLo)(SensorValueType);
51     static SensorValueType (CriticalObject::*const setHi)(SensorValueType);
52     static SensorValueType (CriticalObject::*const getLo)() const;
53     static SensorValueType (CriticalObject::*const getHi)() const;
54     static bool (CriticalObject::*const alarmLo)(bool);
55     static bool (CriticalObject::*const alarmHi)(bool);
56     static bool (CriticalObject::*const getAlarmLow)() const;
57     static bool (CriticalObject::*const getAlarmHigh)() const;
58     static void (CriticalObject::*const assertLowSignal)(SensorValueType);
59     static void (CriticalObject::*const assertHighSignal)(SensorValueType);
60     static void (CriticalObject::*const deassertLowSignal)(SensorValueType);
61     static void (CriticalObject::*const deassertHighSignal)(SensorValueType);
62 };
63 
64 /** @brief checkThresholds
65  *
66  *  Compare a sensor reading to threshold values and set the
67  *  appropriate alarm property if bounds are exceeded.
68  *
69  *  @tparam T - The threshold type.
70  *
71  *  @param[in] iface - An sdbusplus server threshold instance.
72  *  @param[in] value - The sensor reading to compare to thresholds.
73  */
74 template <typename T>
checkThresholds(std::any & iface,SensorValueType value)75 void checkThresholds(std::any& iface, SensorValueType value)
76 {
77     auto realIface = std::any_cast<std::shared_ptr<T>>(iface);
78     auto lo = (*realIface.*Thresholds<T>::getLo)();
79     auto hi = (*realIface.*Thresholds<T>::getHi)();
80     auto alarmLowState = (*realIface.*Thresholds<T>::getAlarmLow)();
81     auto alarmHighState = (*realIface.*Thresholds<T>::getAlarmHigh)();
82     (*realIface.*Thresholds<T>::alarmLo)(value <= lo);
83     (*realIface.*Thresholds<T>::alarmHi)(value >= hi);
84     if (alarmLowState != (value <= lo))
85     {
86         if (value <= lo)
87         {
88             (*realIface.*Thresholds<T>::assertLowSignal)(value);
89         }
90         else
91         {
92             (*realIface.*Thresholds<T>::deassertLowSignal)(value);
93         }
94     }
95     if (alarmHighState != (value >= hi))
96     {
97         if (value >= hi)
98         {
99             (*realIface.*Thresholds<T>::assertHighSignal)(value);
100         }
101         else
102         {
103             (*realIface.*Thresholds<T>::deassertHighSignal)(value);
104         }
105     }
106 }
107 
108 /** @brief addThreshold
109  *
110  *  Look for a configured threshold value in the environment and
111  *  create an sdbusplus server threshold if found.
112  *
113  *  @tparam T - The threshold type.
114  *
115  *  @param[in] sensorType - sensor type, like 'temp'
116  *  @param[in] sensorID - sensor ID, like '5'
117  *  @param[in] value - The sensor reading.
118  *  @param[in] info - The sdbusplus server connection and interfaces.
119  */
120 template <typename T>
addThreshold(const std::string & sensorType,const std::string & sensorID,SensorValueType value,ObjectInfo & info,int64_t scale)121 auto addThreshold(const std::string& sensorType, const std::string& sensorID,
122                   SensorValueType value, ObjectInfo& info, int64_t scale)
123 {
124     auto& objPath = std::get<std::string>(info);
125     auto& obj = std::get<InterfaceMap>(info);
126     std::shared_ptr<T> iface;
127 
128     auto tLo = env::getEnv(Thresholds<T>::envLo, sensorType, sensorID);
129     auto tHi = env::getEnv(Thresholds<T>::envHi, sensorType, sensorID);
130     if (!tLo.empty() || !tHi.empty())
131     {
132         auto& bus = *std::get<sdbusplus::bus_t*>(info);
133 
134         iface = std::make_shared<T>(bus, objPath.c_str(),
135                                     T::action::emit_no_signals);
136         if (!tLo.empty())
137         {
138             auto lo = stod(tLo) * std::pow(10, scale);
139             (*iface.*Thresholds<T>::setLo)(lo);
140             auto alarmLowState = (*iface.*Thresholds<T>::getAlarmLow)();
141             (*iface.*Thresholds<T>::alarmLo)(value <= lo);
142             if (alarmLowState != (value <= lo))
143             {
144                 if (value <= lo)
145                 {
146                     (*iface.*Thresholds<T>::assertLowSignal)(value);
147                 }
148                 else
149                 {
150                     (*iface.*Thresholds<T>::deassertLowSignal)(value);
151                 }
152             }
153         }
154         if (!tHi.empty())
155         {
156             auto hi = stod(tHi) * std::pow(10, scale);
157             (*iface.*Thresholds<T>::setHi)(hi);
158             auto alarmHighState = (*iface.*Thresholds<T>::getAlarmHigh)();
159             (*iface.*Thresholds<T>::alarmHi)(value >= hi);
160             if (alarmHighState != (value >= hi))
161             {
162                 if (value >= hi)
163                 {
164                     (*iface.*Thresholds<T>::assertHighSignal)(value);
165                 }
166                 else
167                 {
168                     (*iface.*Thresholds<T>::deassertHighSignal)(value);
169                 }
170             }
171         }
172         auto type = Thresholds<T>::type;
173         obj[type] = iface;
174     }
175 
176     return iface;
177 }
178 
179 // vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
180