| /** |
| * Copyright 2017 Google Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "pid/builder.hpp" |
| |
| #include "conf.hpp" |
| #include "pid/controller.hpp" |
| #include "pid/fancontroller.hpp" |
| #include "pid/stepwisecontroller.hpp" |
| #include "pid/thermalcontroller.hpp" |
| #include "pid/zone.hpp" |
| #include "pid/zone_interface.hpp" |
| #include "util.hpp" |
| |
| #include <sdbusplus/bus.hpp> |
| |
| #include <cstdint> |
| #include <iostream> |
| #include <memory> |
| #include <string> |
| #include <unordered_map> |
| #include <vector> |
| |
| namespace pid_control |
| { |
| |
| static constexpr bool deferSignals = true; |
| static constexpr auto objectPath = "/xyz/openbmc_project/settings/fanctrl/zone"; |
| |
| static std::string getControlPath(int64_t zone) |
| { |
| return std::string(objectPath) + std::to_string(zone); |
| } |
| |
| static std::string getPidControlPath(int64_t zone, std::string pidname) |
| { |
| return std::string(objectPath) + std::to_string(zone) + "/" + pidname; |
| } |
| |
| std::unordered_map<int64_t, std::shared_ptr<ZoneInterface>> |
| buildZones(const std::map<int64_t, conf::PIDConf>& zonePids, |
| std::map<int64_t, conf::ZoneConfig>& zoneConfigs, |
| SensorManager& mgr, sdbusplus::bus_t& modeControlBus) |
| { |
| std::unordered_map<int64_t, std::shared_ptr<ZoneInterface>> zones; |
| |
| for (const auto& [zoneId, pidConfig] : zonePids) |
| { |
| /* The above shouldn't be necessary but is, and I am having trouble |
| * locating my notes on why. If I recall correctly it was casting it |
| * down to a byte in at least some cases causing weird behaviors. |
| */ |
| auto zoneConf = zoneConfigs.find(zoneId); |
| if (zoneConf == zoneConfigs.end()) |
| { |
| /* The Zone doesn't have a configuration, bail. */ |
| static constexpr auto err = |
| "Bailing during load, missing Zone Configuration"; |
| std::cerr << err << std::endl; |
| throw std::runtime_error(err); |
| } |
| |
| auto zone = std::make_shared<DbusPidZone>( |
| zoneId, zoneConf->second.minThermalOutput, |
| zoneConf->second.failsafePercent, zoneConf->second.cycleTime, mgr, |
| modeControlBus, getControlPath(zoneId).c_str(), deferSignals); |
| |
| std::cerr << "Zone Id: " << zone->getZoneID() << "\n"; |
| |
| // For each PID create a Controller and a Sensor. |
| for (const auto& [name, info] : pidConfig) |
| { |
| std::vector<pid_control::conf::SensorInput> inputs; |
| std::cerr << "PID name: " << name << "\n"; |
| |
| /* |
| * TODO(venture): Need to check if input is known to the |
| * SensorManager. |
| */ |
| if (info.type == "fan") |
| { |
| for (const auto& i : info.inputs) |
| { |
| inputs.push_back(i); |
| zone->addFanInput(i.name, i.missingIsAcceptable); |
| } |
| |
| auto pid = FanController::createFanPid( |
| zone.get(), name, splitNames(inputs), info.pidInfo); |
| zone->addFanPID(std::move(pid)); |
| zone->addPidFailSafePercent(name, info.failSafePercent); |
| } |
| else if (isThermalType(info.type)) |
| { |
| for (const auto& i : info.inputs) |
| { |
| inputs.push_back(i); |
| zone->addThermalInput(i.name, i.missingIsAcceptable); |
| } |
| |
| auto pid = ThermalController::createThermalPid( |
| zone.get(), name, inputs, info.setpoint, info.pidInfo, |
| getThermalType(info.type)); |
| |
| zone->addThermalPID(std::move(pid)); |
| zone->addPidControlProcess( |
| name, info.type, info.setpoint, modeControlBus, |
| getPidControlPath(zoneId, name), deferSignals); |
| zone->addPidFailSafePercent(name, info.failSafePercent); |
| } |
| else if (info.type == "stepwise") |
| { |
| for (const auto& i : info.inputs) |
| { |
| inputs.push_back(i); |
| zone->addThermalInput(i.name, i.missingIsAcceptable); |
| } |
| auto stepwise = StepwiseController::createStepwiseController( |
| zone.get(), name, splitNames(inputs), info.stepwiseInfo); |
| zone->addThermalPID(std::move(stepwise)); |
| zone->addPidControlProcess( |
| name, info.type, info.setpoint, modeControlBus, |
| getPidControlPath(zoneId, name), deferSignals); |
| zone->addPidFailSafePercent(name, info.failSafePercent); |
| } |
| |
| std::cerr << "inputs: "; |
| for (const auto& i : inputs) |
| { |
| std::cerr << i.name; |
| if (i.convertTempToMargin) |
| { |
| std::cerr << "[" << i.convertMarginZero << "]"; |
| } |
| if (i.missingIsAcceptable) |
| { |
| std::cerr << "?"; |
| } |
| std::cerr << ", "; |
| } |
| std::cerr << "\n"; |
| } |
| |
| zone->emit_object_added(); |
| zones[zoneId] = std::move(zone); |
| } |
| |
| return zones; |
| } |
| |
| } // namespace pid_control |