1 #pragma once 2 3 #include "conf.hpp" 4 #include "controller.hpp" 5 #include "failsafeloggers/failsafe_logger_utility.hpp" 6 #include "pidcontroller.hpp" 7 #include "sensors/manager.hpp" 8 #include "sensors/sensor.hpp" 9 #include "tuning.hpp" 10 #include "zone_interface.hpp" 11 12 #include <sdbusplus/bus.hpp> 13 #include <sdbusplus/server.hpp> 14 #include <xyz/openbmc_project/Control/Mode/server.hpp> 15 #include <xyz/openbmc_project/Debug/Pid/ThermalPower/server.hpp> 16 #include <xyz/openbmc_project/Debug/Pid/Zone/server.hpp> 17 #include <xyz/openbmc_project/Object/Enable/server.hpp> 18 19 #include <fstream> 20 #include <iostream> 21 #include <map> 22 #include <memory> 23 #include <set> 24 #include <string> 25 #include <vector> 26 27 template <typename... T> 28 using ServerObject = typename sdbusplus::server::object_t<T...>; 29 using ModeInterface = sdbusplus::xyz::openbmc_project::Control::server::Mode; 30 using DebugZoneInterface = 31 sdbusplus::xyz::openbmc_project::Debug::Pid::server::Zone; 32 using ModeObject = ServerObject<ModeInterface, DebugZoneInterface>; 33 using ProcessInterface = 34 sdbusplus::xyz::openbmc_project::Object::server::Enable; 35 using DebugThermalPowerInterface = 36 sdbusplus::xyz::openbmc_project::Debug::Pid::server::ThermalPower; 37 using ProcessObject = 38 ServerObject<ProcessInterface, DebugThermalPowerInterface>; 39 using FailSafeSensorsMap = 40 std::map<std::string, std::pair<std::string, double>>; 41 using FailSafeSensorPair = 42 std::pair<std::string, std::pair<std::string, double>>; 43 44 namespace pid_control 45 { 46 47 /* 48 * The DbusPidZone inherits from the Mode object so that it can listen for 49 * control mode changes. It primarily holds all PID loops and holds the sensor 50 * value cache that's used per iteration of the PID loops. 51 */ 52 class DbusPidZone : public ZoneInterface, public ModeObject 53 { 54 public: DbusPidZone(int64_t zone,double minThermalOutput,double failSafePercent,conf::CycleTime cycleTime,const SensorManager & mgr,sdbusplus::bus_t & bus,const char * objPath,bool defer,bool accumulateSetPoint)55 DbusPidZone(int64_t zone, double minThermalOutput, double failSafePercent, 56 conf::CycleTime cycleTime, const SensorManager& mgr, 57 sdbusplus::bus_t& bus, const char* objPath, bool defer, 58 bool accumulateSetPoint) : 59 ModeObject(bus, objPath, 60 defer ? ModeObject::action::defer_emit 61 : ModeObject::action::emit_object_added), 62 _zoneId(zone), _maximumSetPoint(), 63 _accumulateSetPoint(accumulateSetPoint), 64 _minThermalOutputSetPt(minThermalOutput), 65 _zoneFailSafePercent(failSafePercent), _cycleTime(cycleTime), _mgr(mgr) 66 { 67 if (loggingEnabled) 68 { 69 _log.open(loggingPath + "/zone_" + std::to_string(zone) + ".log"); 70 } 71 } 72 73 bool getManualMode(void) const override; 74 /* Could put lock around this since it's accessed from two threads, but 75 * only one reader/one writer. 76 */ 77 78 bool getRedundantWrite(void) const override; 79 void setManualMode(bool mode); 80 bool getFailSafeMode(void) const override; 81 void markSensorMissing(const std::string& name, 82 const std::string& failReason); 83 bool getAccSetPoint(void) const override; 84 85 int64_t getZoneID(void) const override; 86 void addSetPoint(double setPoint, const std::string& name) override; 87 double getMaxSetPointRequest(void) const override; 88 void addRPMCeiling(double ceiling) override; 89 void clearSetPoints(void) override; 90 void clearRPMCeilings(void) override; 91 double getFailSafePercent(void) override; 92 FailSafeSensorsMap getFailSafeSensors(void) const override; 93 double getMinThermalSetPoint(void) const; 94 uint64_t getCycleIntervalTime(void) const override; 95 uint64_t getUpdateThermalsCycle(void) const override; 96 97 Sensor* getSensor(const std::string& name) override; 98 std::vector<std::string> getSensorNames(void) override; 99 void determineMaxSetPointRequest(void) override; 100 void updateFanTelemetry(void) override; 101 void updateSensors(void) override; 102 void initializeCache(void) override; 103 void setOutputCache(std::string_view, const ValueCacheEntry&) override; 104 void dumpCache(void); 105 106 void processFans(void) override; 107 void processThermals(void) override; 108 109 void addFanPID(std::unique_ptr<Controller> pid); 110 void addThermalPID(std::unique_ptr<Controller> pid); 111 double getCachedValue(const std::string& name) override; 112 ValueCacheEntry getCachedValues(const std::string& name) override; 113 114 void addFanInput(const std::string& fan, bool missingAcceptable); 115 void addThermalInput(const std::string& therm, bool missingAcceptable); 116 117 void initializeLog(void) override; 118 void writeLog(const std::string& value) override; 119 120 /* Method for setting the manual mode over dbus */ 121 bool manual(bool value) override; 122 /* Method for reading whether in fail-safe mode over dbus */ 123 bool failSafe() const override; 124 /* Method for recording the maximum SetPoint PID config name */ 125 std::string leader() const override; 126 /* Method for control process for each loop at runtime */ 127 void addPidControlProcess(std::string name, std::string type, 128 double setpoint, sdbusplus::bus_t& bus, 129 std::string objPath, bool defer); 130 bool isPidProcessEnabled(std::string name); 131 132 void addPidFailSafePercent(std::vector<std::string> inputs, double percent); 133 134 void updateThermalPowerDebugInterface(std::string pidName, 135 std::string leader, double input, 136 double output) override; 137 138 private: 139 template <bool fanSensorLogging> processSensorInputs(const std::vector<std::string> & sensorInputs,std::chrono::high_resolution_clock::time_point now)140 void processSensorInputs(const std::vector<std::string>& sensorInputs, 141 std::chrono::high_resolution_clock::time_point now) 142 { 143 for (const auto& sensorInput : sensorInputs) 144 { 145 auto sensor = _mgr.getSensor(sensorInput); 146 ReadReturn r = sensor->read(); 147 _cachedValuesByName[sensorInput] = {r.value, r.unscaled}; 148 int64_t timeout = sensor->getTimeout(); 149 std::chrono::high_resolution_clock::time_point then = r.updated; 150 151 auto duration = 152 std::chrono::duration_cast<std::chrono::seconds>(now - then) 153 .count(); 154 auto period = std::chrono::seconds(timeout).count(); 155 /* 156 * TODO(venture): We should check when these were last read. 157 * However, these are the fans, so if I'm not getting updated values 158 * for them... what should I do? 159 */ 160 if constexpr (fanSensorLogging) 161 { 162 if (loggingEnabled) 163 { 164 const auto& v = _cachedValuesByName[sensorInput]; 165 _log << "," << v.scaled << "," << v.unscaled; 166 const auto& p = _cachedFanOutputs[sensorInput]; 167 _log << "," << p.scaled << "," << p.unscaled; 168 } 169 } 170 171 if (debugEnabled) 172 { 173 std::cerr << sensorInput << " sensor reading: " << r.value 174 << "\n"; 175 } 176 177 // check if fan fail. 178 if (sensor->getFailed()) 179 { 180 markSensorMissing(sensorInput, sensor->getFailReason()); 181 182 if (debugEnabled) 183 { 184 std::cerr << sensorInput << " sensor get failed\n"; 185 } 186 } 187 else if (timeout != 0 && duration >= period) 188 { 189 markSensorMissing(sensorInput, "Sensor timeout"); 190 191 if (debugEnabled) 192 { 193 std::cerr << sensorInput << " sensor timeout\n"; 194 } 195 outputFailsafeLogWithZone(_zoneId, this->getFailSafeMode(), 196 sensorInput, 197 "The sensor has timed out."); 198 } 199 else 200 { 201 // Check if it's in there: remove it. 202 auto kt = _failSafeSensors.find(sensorInput); 203 if (kt != _failSafeSensors.end()) 204 { 205 if (debugEnabled) 206 { 207 std::cerr << sensorInput 208 << " is erased from failsafe sensor set\n"; 209 } 210 211 _failSafeSensors.erase(kt); 212 outputFailsafeLogWithZone(_zoneId, this->getFailSafeMode(), 213 sensorInput, 214 "The sensor has recovered."); 215 } 216 } 217 } 218 } 219 220 std::ofstream _log; 221 222 const int64_t _zoneId; 223 double _maximumSetPoint = 0; 224 std::string _maximumSetPointName; 225 std::string _maximumSetPointNamePrev; 226 bool _manualMode = false; 227 bool _redundantWrite = false; 228 bool _accumulateSetPoint = false; 229 const double _minThermalOutputSetPt; 230 // Zone fail safe Percent setting by configuration. 231 const double _zoneFailSafePercent; 232 const conf::CycleTime _cycleTime; 233 234 /* 235 * <map key = sensor name, value = sensor fail reason and failsafe percent> 236 */ 237 FailSafeSensorsMap _failSafeSensors; 238 std::set<std::string> _missingAcceptable; 239 240 std::map<std::string, double> _SetPoints; 241 std::vector<double> _RPMCeilings; 242 std::vector<std::string> _fanInputs; 243 std::vector<std::string> _thermalInputs; 244 std::map<std::string, ValueCacheEntry> _cachedValuesByName; 245 std::map<std::string, ValueCacheEntry> _cachedFanOutputs; 246 const SensorManager& _mgr; 247 248 std::vector<std::unique_ptr<Controller>> _fans; 249 std::vector<std::unique_ptr<Controller>> _thermals; 250 251 std::map<std::string, std::unique_ptr<ProcessObject>> _pidsControlProcess; 252 /* 253 * <key = sensor name, value = sensor failsafe percent> 254 * sensor fail safe Percent setting by each pid controller configuration. 255 */ 256 std::map<std::string, double> _sensorFailSafePercent; 257 }; 258 259 } // namespace pid_control 260