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