blob: db4763f764e6702d25d062eab82b0a4849ccd71f [file] [log] [blame]
/**
* 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 "thermalcontroller.hpp"
#include "errors/exception.hpp"
#include "tuning.hpp"
#include "util.hpp"
#include "zone.hpp"
#include <algorithm>
#include <cmath>
#include <iostream>
namespace pid_control
{
ThermalType getThermalType(const std::string& typeString)
{
if (typeString == "margin")
{
return ThermalType::margin;
}
if ((typeString == "temp") || (typeString == "power"))
{
return ThermalType::absolute;
}
if (typeString == "powersum")
{
return ThermalType::summation;
}
throw ControllerBuildException("Unrecognized PID Type/Class string");
}
bool isThermalType(const std::string& typeString)
{
static const std::vector<std::string> thermalTypes = {"temp", "margin",
"power", "powersum"};
return std::count(thermalTypes.begin(), thermalTypes.end(), typeString);
}
std::unique_ptr<PIDController> ThermalController::createThermalPid(
ZoneInterface* owner, const std::string& id,
const std::vector<std::string>& inputs, double setpoint,
const ec::pidinfo& initial, const ThermalType& type)
{
// ThermalController requires at least 1 input
if (inputs.empty())
{
throw ControllerBuildException("Thermal controller missing inputs");
}
auto thermal = std::make_unique<ThermalController>(id, inputs, type, owner);
ec::pid_info_t* info = thermal->getPIDInfo();
thermal->setSetpoint(setpoint);
initializePIDStruct(info, initial);
return thermal;
}
// bmc_host_sensor_value_double
double ThermalController::inputProc(void)
{
double value;
const double& (*compare)(const double&, const double&);
bool doSummation = false;
if (type == ThermalType::margin)
{
value = std::numeric_limits<double>::max();
compare = std::min<double>;
}
else if (type == ThermalType::absolute)
{
value = std::numeric_limits<double>::lowest();
compare = std::max<double>;
}
else if (type == ThermalType::summation)
{
doSummation = true;
value = 0.0;
}
else
{
throw ControllerBuildException("Unrecognized ThermalType");
}
bool acceptable = false;
for (const auto& in : _inputs)
{
double cachedValue = _owner->getCachedValue(in);
// Less than 0 is perfectly OK for temperature, but must not be NAN
if (!(std::isfinite(cachedValue)))
{
continue;
}
if (doSummation)
{
value += cachedValue;
}
else
{
value = compare(value, cachedValue);
}
acceptable = true;
}
if (!acceptable)
{
// While not optimal, zero is better than garbage
value = 0;
}
if (debugEnabled)
{
std::cerr << getID() << " choose the temperature value: " << value
<< "\n";
}
return value;
}
// bmc_get_setpt
double ThermalController::setptProc(void)
{
double setpoint = getSetpoint();
/* TODO(venture): Thermal setpoint invalid? */
#if 0
if (-1 == setpoint)
{
return 0.0f;
}
else
{
return setpoint;
}
#endif
return setpoint;
}
// bmc_set_pid_output
void ThermalController::outputProc(double value)
{
_owner->addSetPoint(value, _id);
if (debugEnabled)
{
std::cerr << getID() << " pid output pwm: " << value << "\n";
}
return;
}
} // namespace pid_control