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