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