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