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