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 "thermalcontroller.hpp" 18 19 #include "errors/exception.hpp" 20 #include "tuning.hpp" 21 #include "util.hpp" 22 #include "zone.hpp" 23 24 #include <algorithm> 25 #include <cmath> 26 #include <iostream> 27 28 namespace pid_control 29 { 30 31 ThermalType getThermalType(const std::string& typeString) 32 { 33 /* Currently it only supports the two types. */ 34 return (typeString == "temp") ? ThermalType::absolute : ThermalType::margin; 35 } 36 37 bool isThermalType(const std::string& typeString) 38 { 39 static const std::vector<std::string> thermalTypes = {"temp", "margin"}; 40 return std::count(thermalTypes.begin(), thermalTypes.end(), typeString); 41 } 42 43 std::unique_ptr<PIDController> ThermalController::createThermalPid( 44 ZoneInterface* owner, const std::string& id, 45 const std::vector<std::string>& inputs, double setpoint, 46 const ec::pidinfo& initial, const ThermalType& type) 47 { 48 // ThermalController requires at least 1 input 49 if (inputs.empty()) 50 { 51 throw ControllerBuildException("Thermal controller missing inputs"); 52 return nullptr; 53 } 54 55 auto thermal = std::make_unique<ThermalController>(id, inputs, type, owner); 56 57 ec::pid_info_t* info = thermal->getPIDInfo(); 58 thermal->setSetpoint(setpoint); 59 60 initializePIDStruct(info, initial); 61 62 return thermal; 63 } 64 65 // bmc_host_sensor_value_double 66 double ThermalController::inputProc(void) 67 { 68 double value; 69 const double& (*compare)(const double&, const double&); 70 if (type == ThermalType::margin) 71 { 72 value = std::numeric_limits<double>::max(); 73 compare = std::min<double>; 74 } 75 else 76 { 77 value = std::numeric_limits<double>::lowest(); 78 compare = std::max<double>; 79 } 80 81 bool acceptable = false; 82 for (const auto& in : _inputs) 83 { 84 double cachedValue = _owner->getCachedValue(in); 85 86 // Less than 0 is perfectly OK for temperature, but must not be NAN 87 if (!(std::isfinite(cachedValue))) 88 { 89 continue; 90 } 91 92 value = compare(value, cachedValue); 93 acceptable = true; 94 } 95 96 if (!acceptable) 97 { 98 // While not optimal, zero is better than garbage 99 value = 0; 100 } 101 102 if (debugEnabled) 103 { 104 std::cerr << getID() << " choose the temperature value: " << value 105 << "\n"; 106 } 107 108 return value; 109 } 110 111 // bmc_get_setpt 112 double ThermalController::setptProc(void) 113 { 114 double setpoint = getSetpoint(); 115 116 /* TODO(venture): Thermal setpoint invalid? */ 117 #if 0 118 if (-1 == setpoint) 119 { 120 return 0.0f; 121 } 122 else 123 { 124 return setpoint; 125 } 126 #endif 127 return setpoint; 128 } 129 130 // bmc_set_pid_output 131 void ThermalController::outputProc(double value) 132 { 133 _owner->addSetPoint(value, _id); 134 135 if (debugEnabled) 136 { 137 std::cerr << getID() << " pid output pwm: " << value << "\n"; 138 } 139 140 return; 141 } 142 143 } // namespace pid_control 144