xref: /openbmc/phosphor-hwmon/thresholds.hpp (revision 6f42e3568ffd1addcb409f9c7ad9bdc111cf5537)
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 {
16     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>
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>
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         static constexpr bool deferSignals = true;
133         auto& bus = *std::get<sdbusplus::bus::bus*>(info);
134 
135         iface = std::make_shared<T>(bus, objPath.c_str(), deferSignals);
136         auto lo = stod(tLo) * std::pow(10, scale);
137         auto hi = stod(tHi) * std::pow(10, scale);
138         (*iface.*Thresholds<T>::setLo)(lo);
139         (*iface.*Thresholds<T>::setHi)(hi);
140         auto alarmLowState = (*iface.*Thresholds<T>::getAlarmLow)();
141         auto alarmHighState = (*iface.*Thresholds<T>::getAlarmHigh)();
142         (*iface.*Thresholds<T>::alarmLo)(value <= lo);
143         (*iface.*Thresholds<T>::alarmHi)(value >= hi);
144         if (alarmLowState != (value <= lo))
145         {
146             if (value <= lo)
147             {
148                 (*iface.*Thresholds<T>::assertLowSignal)(value);
149             }
150             else
151             {
152                 (*iface.*Thresholds<T>::deassertLowSignal)(value);
153             }
154         }
155         if (alarmHighState != (value >= hi))
156         {
157             if (value >= hi)
158             {
159                 (*iface.*Thresholds<T>::assertHighSignal)(value);
160             }
161             else
162             {
163                 (*iface.*Thresholds<T>::deassertHighSignal)(value);
164             }
165         }
166         auto type = Thresholds<T>::type;
167         obj[type] = iface;
168     }
169 
170     return iface;
171 }
172 
173 // vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
174