xref: /openbmc/phosphor-pid-control/pid/builder.cpp (revision f8b6e55147148c3cfb42327ff267197a460b411c)
1 /**
2  * Copyright 2017 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "pid/builder.hpp"
18 
19 #include "conf.hpp"
20 #include "manager.hpp"
21 #include "pid/controller.hpp"
22 #include "pid/fancontroller.hpp"
23 #include "pid/stepwisecontroller.hpp"
24 #include "pid/thermalcontroller.hpp"
25 #include "pid/zone.hpp"
26 #include "pid/zone_interface.hpp"
27 #include "util.hpp"
28 
29 #include <sdbusplus/bus.hpp>
30 
31 #include <cstdint>
32 #include <iostream>
33 #include <map>
34 #include <memory>
35 #include <stdexcept>
36 #include <string>
37 #include <unordered_map>
38 #include <utility>
39 #include <vector>
40 
41 namespace pid_control
42 {
43 
44 static constexpr bool deferSignals = true;
45 static constexpr auto objectPath = "/xyz/openbmc_project/settings/fanctrl/zone";
46 
getControlPath(int64_t zone)47 static std::string getControlPath(int64_t zone)
48 {
49     return std::string(objectPath) + std::to_string(zone);
50 }
51 
getPidControlPath(int64_t zone,const std::string & pidname)52 static std::string getPidControlPath(int64_t zone, const std::string& pidname)
53 {
54     return std::string(objectPath) + std::to_string(zone) + "/" + pidname;
55 }
56 
buildZones(const std::map<int64_t,conf::PIDConf> & zonePids,std::map<int64_t,conf::ZoneConfig> & zoneConfigs,SensorManager & mgr,sdbusplus::bus_t & modeControlBus)57 std::unordered_map<int64_t, std::shared_ptr<ZoneInterface>> buildZones(
58     const std::map<int64_t, conf::PIDConf>& zonePids,
59     std::map<int64_t, conf::ZoneConfig>& zoneConfigs, SensorManager& mgr,
60     sdbusplus::bus_t& modeControlBus)
61 {
62     std::unordered_map<int64_t, std::shared_ptr<ZoneInterface>> zones;
63 
64     for (const auto& [zoneId, pidConfig] : zonePids)
65     {
66         /* The above shouldn't be necessary but is, and I am having trouble
67          * locating my notes on why.  If I recall correctly it was casting it
68          * down to a byte in at least some cases causing weird behaviors.
69          */
70         auto zoneConf = zoneConfigs.find(zoneId);
71         if (zoneConf == zoneConfigs.end())
72         {
73             /* The Zone doesn't have a configuration, bail. */
74             static constexpr auto err =
75                 "Bailing during load, missing Zone Configuration";
76             std::cerr << err << std::endl;
77             throw std::runtime_error(err);
78         }
79 
80         auto zone = std::make_shared<DbusPidZone>(
81             zoneId, zoneConf->second.minThermalOutput,
82             zoneConf->second.failsafePercent, zoneConf->second.cycleTime, mgr,
83             modeControlBus, getControlPath(zoneId).c_str(), deferSignals,
84             zoneConf->second.accumulateSetPoint);
85 
86         std::cerr << "Zone Id: " << zone->getZoneID() << "\n";
87 
88         // For each PID create a Controller and a Sensor.
89         for (const auto& [name, info] : pidConfig)
90         {
91             std::vector<pid_control::conf::SensorInput> inputs;
92             std::cerr << "PID name: " << name << "\n";
93 
94             /*
95              * TODO(venture): Need to check if input is known to the
96              * SensorManager.
97              */
98             if (info.type == "fan")
99             {
100                 for (const auto& i : info.inputs)
101                 {
102                     inputs.push_back(i);
103                     zone->addFanInput(i.name, i.missingIsAcceptable);
104                 }
105 
106                 auto pid = FanController::createFanPid(
107                     zone.get(), name, splitNames(inputs), info.pidInfo);
108                 zone->addFanPID(std::move(pid));
109                 zone->addPidFailSafePercent(splitNames(inputs),
110                                             info.failSafePercent);
111             }
112             else if (isThermalType(info.type))
113             {
114                 for (const auto& i : info.inputs)
115                 {
116                     inputs.push_back(i);
117                     zone->addThermalInput(i.name, i.missingIsAcceptable);
118                 }
119 
120                 auto pid = ThermalController::createThermalPid(
121                     zone.get(), name, inputs, info.setpoint, info.pidInfo,
122                     getThermalType(info.type));
123 
124                 zone->addThermalPID(std::move(pid));
125                 zone->addPidControlProcess(
126                     name, info.type, info.setpoint, modeControlBus,
127                     getPidControlPath(zoneId, name), deferSignals);
128                 zone->addPidFailSafePercent(splitNames(inputs),
129                                             info.failSafePercent);
130             }
131             else if (info.type == "stepwise")
132             {
133                 for (const auto& i : info.inputs)
134                 {
135                     inputs.push_back(i);
136                     zone->addThermalInput(i.name, i.missingIsAcceptable);
137                 }
138                 auto stepwise = StepwiseController::createStepwiseController(
139                     zone.get(), name, splitNames(inputs), info.stepwiseInfo);
140                 zone->addThermalPID(std::move(stepwise));
141                 zone->addPidControlProcess(
142                     name, info.type, info.setpoint, modeControlBus,
143                     getPidControlPath(zoneId, name), deferSignals);
144                 zone->addPidFailSafePercent(splitNames(inputs),
145                                             info.failSafePercent);
146             }
147 
148             std::cerr << "inputs: ";
149             for (const auto& i : inputs)
150             {
151                 std::cerr << i.name;
152                 if (i.convertTempToMargin)
153                 {
154                     std::cerr << "[" << i.convertMarginZero << "]";
155                 }
156                 if (i.missingIsAcceptable)
157                 {
158                     std::cerr << "?";
159                 }
160                 std::cerr << ", ";
161             }
162             std::cerr << "\n";
163         }
164 
165         zone->emit_object_added();
166         zones[zoneId] = std::move(zone);
167     }
168 
169     return zones;
170 }
171 
172 } // namespace pid_control
173