Allow multiple inputs to thermal and stepwise controllers

Use std::max to determine which input value to apply.
Also start throwing when inputs are empty as otherwise
there will be a nullptr dereference.

Tested-by: Added multiple inputs and application no longer
segfaults and verifed max was being used. Also added unit
tests.

Change-Id: I7c8eda45b99247b8e92e629f036c9a46c98d9fe2
Signed-off-by: James Feist <james.feist@linux.intel.com>
diff --git a/pid/thermalcontroller.cpp b/pid/thermalcontroller.cpp
index 485688a..ff2c7bc 100644
--- a/pid/thermalcontroller.cpp
+++ b/pid/thermalcontroller.cpp
@@ -16,21 +16,23 @@
 
 #include "thermalcontroller.hpp"
 
+#include "errors/exception.hpp"
 #include "util.hpp"
 #include "zone.hpp"
 
 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 ec::pidinfo& initial, const ThermalType& type)
 {
-    // ThermalController currently only supports precisely one input.
-    if (inputs.size() != 1)
+    // ThermalController requires at least 1 input
+    if (inputs.empty())
     {
+        throw ControllerBuildException("Thermal controller missing inputs");
         return nullptr;
     }
 
-    auto thermal = std::make_unique<ThermalController>(id, inputs, owner);
+    auto thermal = std::make_unique<ThermalController>(id, inputs, type, owner);
 
     ec::pid_info_t* info = thermal->getPIDInfo();
     thermal->setSetpoint(setpoint);
@@ -43,11 +45,24 @@
 // bmc_host_sensor_value_double
 double ThermalController::inputProc(void)
 {
-    /*
-     * This only supports one thermal input because it doesn't yet know how to
-     * handle merging them, probably max?
-     */
-    double value = _owner->getCachedValue(_inputs.at(0));
+    double value;
+    const double& (*compare)(const double&, const double&);
+    if (type == ThermalType::margin)
+    {
+        value = std::numeric_limits<double>::max();
+        compare = std::min<double>;
+    }
+    else
+    {
+        value = std::numeric_limits<double>::lowest();
+        compare = std::max<double>;
+    }
+
+    for (const auto& in : _inputs)
+    {
+        value = compare(value, _owner->getCachedValue(in));
+    }
+
     return value;
 }