xref: /openbmc/phosphor-pid-control/util.hpp (revision 83a2c3b2)
1 #pragma once
2 
3 #include "pid/ec/pid.hpp"
4 
5 #include <limits>
6 #include <phosphor-logging/log.hpp>
7 #include <sdbusplus/bus.hpp>
8 #include <string>
9 
10 /* This program assumes sensors use the Sensor.Value interface
11  * and for sensor->write() I only implemented sysfs as a type,
12  * but -- how would it know whether to use Control.FanSpeed or Control.FanPwm?
13  *
14  * One could get the interface list for the object and search for Control.*
15  * but, it needs to know the maximum, minimum.  The only sensors it wants to
16  * write in this code base are Fans...
17  */
18 enum class IOInterfaceType
19 {
20     NONE, // There is no interface.
21     EXTERNAL,
22     DBUSPASSIVE,
23     DBUSACTIVE, // This means for write that it needs to look up the interface.
24     SYSFS,
25     UNKNOWN
26 };
27 
28 /* WriteInterfaceType is different because Dbusactive/passive. how to know... */
29 IOInterfaceType getWriteInterfaceType(const std::string& path);
30 
31 IOInterfaceType getReadInterfaceType(const std::string& path);
32 
33 void tryRestartControlLoops(void);
34 
35 /*
36  * Given a configuration structure, fill out the information we use within the
37  * PID loop.
38  */
39 void initializePIDStruct(ec::pid_info_t* info, const ec::pidinfo& initial);
40 
41 void dumpPIDStruct(ec::pid_info_t* info);
42 
43 struct SensorProperties
44 {
45     int64_t scale;
46     double value;
47     double min;
48     double max;
49     std::string unit;
50 };
51 
52 struct SensorThresholds
53 {
54     double lowerThreshold = std::numeric_limits<double>::quiet_NaN();
55     double upperThreshold = std::numeric_limits<double>::quiet_NaN();
56 };
57 
58 const std::string sensorintf = "xyz.openbmc_project.Sensor.Value";
59 const std::string criticalThreshInf =
60     "xyz.openbmc_project.Sensor.Threshold.Critical";
61 const std::string propertiesintf = "org.freedesktop.DBus.Properties";
62 
63 class DbusHelperInterface
64 {
65   public:
66     virtual ~DbusHelperInterface() = default;
67 
68     /** @brief Get the service providing the interface for the path.
69      *
70      * @warning Throws exception on dbus failure.
71      */
72     virtual std::string getService(sdbusplus::bus::bus& bus,
73                                    const std::string& intf,
74                                    const std::string& path) = 0;
75 
76     /** @brief Get all Sensor.Value properties for a service and path.
77      *
78      * @param[in] bus - A bus to use for the call.
79      * @param[in] service - The service providing the interface.
80      * @param[in] path - The dbus path.
81      * @param[out] prop - A pointer to a properties struct to fill out.
82      *
83      * @warning Throws exception on dbus failure.
84      */
85     virtual void getProperties(sdbusplus::bus::bus& bus,
86                                const std::string& service,
87                                const std::string& path,
88                                struct SensorProperties* prop) = 0;
89 
90     /** @brief Get Critical Threshold current assert status
91      *
92      * @param[in] bus - A bus to use for the call.
93      * @param[in] service - The service providing the interface.
94      * @param[in] path - The dbus path.
95      */
96     virtual bool thresholdsAsserted(sdbusplus::bus::bus& bus,
97                                     const std::string& service,
98                                     const std::string& path) = 0;
99 };
100 
101 class DbusHelper : public DbusHelperInterface
102 {
103   public:
104     DbusHelper() = default;
105     ~DbusHelper() = default;
106     DbusHelper(const DbusHelper&) = default;
107     DbusHelper& operator=(const DbusHelper&) = default;
108     DbusHelper(DbusHelper&&) = default;
109     DbusHelper& operator=(DbusHelper&&) = default;
110 
111     std::string getService(sdbusplus::bus::bus& bus, const std::string& intf,
112                            const std::string& path) override;
113 
114     void getProperties(sdbusplus::bus::bus& bus, const std::string& service,
115                        const std::string& path,
116                        struct SensorProperties* prop) override;
117 
118     bool thresholdsAsserted(sdbusplus::bus::bus& bus,
119                             const std::string& service,
120                             const std::string& path) override;
121 
122     template <typename T>
123     void getProperty(sdbusplus::bus::bus& bus, const std::string& service,
124                      const std::string& path, const std::string& interface,
125                      const std::string& propertyName, T& prop)
126     {
127         namespace log = phosphor::logging;
128 
129         auto msg = bus.new_method_call(service.c_str(), path.c_str(),
130                                        propertiesintf.c_str(), "Get");
131 
132         msg.append(interface, propertyName);
133 
134         std::variant<T> result;
135         try
136         {
137             auto valueResponseMsg = bus.call(msg);
138             valueResponseMsg.read(result);
139         }
140         catch (const sdbusplus::exception::SdBusError& ex)
141         {
142             log::log<log::level::ERR>("Get Property Failed",
143                                       log::entry("WHAT=%s", ex.what()));
144             throw;
145         }
146 
147         prop = std::get<T>(result);
148     }
149 };
150 
151 std::string getSensorPath(const std::string& type, const std::string& id);
152 std::string getMatch(const std::string& type, const std::string& id);
153 void scaleSensorReading(const double min, const double max, double& value);
154 bool validType(const std::string& type);
155 
156 struct VariantToDoubleVisitor
157 {
158     template <typename T>
159     std::enable_if_t<std::is_arithmetic<T>::value, double>
160         operator()(const T& t) const
161     {
162         return static_cast<double>(t);
163     }
164 
165     template <typename T>
166     std::enable_if_t<!std::is_arithmetic<T>::value, double>
167         operator()(const T& t) const
168     {
169         throw std::invalid_argument("Cannot translate type to double");
170     }
171 };
172 
173 /*
174  * Given a path that optionally has a glob portion, fill it out.
175  */
176 std::string FixupPath(std::string original);
177