zone: Add debug thermal/power interface

- Add xyz.openbmc_project.Debug.Pid.ThermalPower interface to
  fanctrl/zoneX/pid dbus to record some datas in thermal/power
  PID loop.

Tested:
```
busctl introspect xyz.openbmc_project.State.FanCtrl /xyz/openbmc_project/settings/fanctrl/zone0/CPU0_PID xyz.openbmc_project.Debug.Pid.ThermalPower
NAME                                       TYPE      SIGNATURE RESULT/VALUE  FLAGS
.ClassType                                 property  s         "Temperature" emits-change
.Input                                     property  d         36.594        emits-change
.Leader                                    property  s         "Die_CPU0"    emits-change
.Output                                    property  d         4200          emits-change
.Setpoint                                  property  d         70            emits-change
```

Signed-off-by: Harvey Wu <Harvey.Wu@quantatw.com>
Change-Id: I6846c3878c2ca5eaeeb6eaf48aaf0f604a2beccf
diff --git a/pid/builder.cpp b/pid/builder.cpp
index 830c2fb..8525073 100644
--- a/pid/builder.cpp
+++ b/pid/builder.cpp
@@ -115,9 +115,9 @@
                     getThermalType(info.type));
 
                 zone->addThermalPID(std::move(pid));
-                zone->addPidControlProcess(name, modeControlBus,
-                                           getPidControlPath(zoneId, name),
-                                           deferSignals);
+                zone->addPidControlProcess(
+                    name, info.type, info.setpoint, modeControlBus,
+                    getPidControlPath(zoneId, name), deferSignals);
                 zone->addPidFailSafePercent(name, info.failSafePercent);
             }
             else if (info.type == "stepwise")
@@ -130,9 +130,9 @@
                 auto stepwise = StepwiseController::createStepwiseController(
                     zone.get(), name, inputs, info.stepwiseInfo);
                 zone->addThermalPID(std::move(stepwise));
-                zone->addPidControlProcess(name, modeControlBus,
-                                           getPidControlPath(zoneId, name),
-                                           deferSignals);
+                zone->addPidControlProcess(
+                    name, info.type, info.setpoint, modeControlBus,
+                    getPidControlPath(zoneId, name), deferSignals);
                 zone->addPidFailSafePercent(name, info.failSafePercent);
             }
 
diff --git a/pid/thermalcontroller.cpp b/pid/thermalcontroller.cpp
index db4763f..357437b 100644
--- a/pid/thermalcontroller.cpp
+++ b/pid/thermalcontroller.cpp
@@ -101,6 +101,8 @@
         throw ControllerBuildException("Unrecognized ThermalType");
     }
 
+    std::string leaderName = *(_inputs.begin());
+
     bool acceptable = false;
     for (const auto& in : _inputs)
     {
@@ -112,6 +114,8 @@
             continue;
         }
 
+        double oldValue = value;
+
         if (doSummation)
         {
             value += cachedValue;
@@ -121,6 +125,12 @@
             value = compare(value, cachedValue);
         }
 
+        if (oldValue != value)
+        {
+            leaderName = in;
+            _owner->updateThermalPowerDebugInterface(_id, leaderName, value, 0);
+        }
+
         acceptable = true;
     }
 
@@ -133,7 +143,7 @@
     if (debugEnabled)
     {
         std::cerr << getID() << " choose the temperature value: " << value
-                  << "\n";
+                  << " " << leaderName << "\n";
     }
 
     return value;
@@ -162,6 +172,7 @@
 void ThermalController::outputProc(double value)
 {
     _owner->addSetPoint(value, _id);
+    _owner->updateThermalPowerDebugInterface(_id, "", 0, value);
 
     if (debugEnabled)
     {
diff --git a/pid/zone.cpp b/pid/zone.cpp
index 995b2aa..0b46841 100644
--- a/pid/zone.cpp
+++ b/pid/zone.cpp
@@ -470,7 +470,8 @@
     return getFailSafeMode();
 }
 
-void DbusPidZone::addPidControlProcess(std::string name, sdbusplus::bus_t& bus,
+void DbusPidZone::addPidControlProcess(std::string name, std::string type,
+                                       double setpoint, sdbusplus::bus_t& bus,
                                        std::string objPath, bool defer)
 {
     _pidsControlProcess[name] = std::make_unique<ProcessObject>(
@@ -479,6 +480,24 @@
               : ProcessObject::action::emit_object_added);
     // Default enable setting = true
     _pidsControlProcess[name]->enabled(true);
+    _pidsControlProcess[name]->setpoint(setpoint);
+
+    if (type == "temp")
+    {
+        _pidsControlProcess[name]->classType("Temperature");
+    }
+    else if (type == "margin")
+    {
+        _pidsControlProcess[name]->classType("Margin");
+    }
+    else if (type == "power")
+    {
+        _pidsControlProcess[name]->classType("Power");
+    }
+    else if (type == "powersum")
+    {
+        _pidsControlProcess[name]->classType("PowerSum");
+    }
 }
 
 bool DbusPidZone::isPidProcessEnabled(std::string name)
@@ -521,4 +540,19 @@
     return _maximumSetPointName;
 }
 
+void DbusPidZone::updateThermalPowerDebugInterface(std::string pidName,
+                                                   std::string leader,
+                                                   double input, double output)
+{
+    if (leader.empty())
+    {
+        _pidsControlProcess[pidName]->output(output);
+    }
+    else
+    {
+        _pidsControlProcess[pidName]->leader(leader);
+        _pidsControlProcess[pidName]->input(input);
+    }
+}
+
 } // namespace pid_control
diff --git a/pid/zone.hpp b/pid/zone.hpp
index 85a9064..2854997 100644
--- a/pid/zone.hpp
+++ b/pid/zone.hpp
@@ -11,6 +11,7 @@
 #include <sdbusplus/bus.hpp>
 #include <sdbusplus/server.hpp>
 #include <xyz/openbmc_project/Control/Mode/server.hpp>
+#include <xyz/openbmc_project/Debug/Pid/ThermalPower/server.hpp>
 #include <xyz/openbmc_project/Debug/Pid/Zone/server.hpp>
 #include <xyz/openbmc_project/Object/Enable/server.hpp>
 
@@ -30,7 +31,10 @@
 using ModeObject = ServerObject<ModeInterface, DebugZoneInterface>;
 using ProcessInterface =
     sdbusplus::xyz::openbmc_project::Object::server::Enable;
-using ProcessObject = ServerObject<ProcessInterface>;
+using DebugThermalPowerInterface =
+    sdbusplus::xyz::openbmc_project::Debug::Pid::server::ThermalPower;
+using ProcessObject =
+    ServerObject<ProcessInterface, DebugThermalPowerInterface>;
 
 namespace pid_control
 {
@@ -108,13 +112,18 @@
     /* Method for recording the maximum SetPoint PID config name */
     std::string leader() const override;
     /* Method for control process for each loop at runtime */
-    void addPidControlProcess(std::string name, sdbusplus::bus_t& bus,
+    void addPidControlProcess(std::string name, std::string type,
+                              double setpoint, sdbusplus::bus_t& bus,
                               std::string objPath, bool defer);
     bool isPidProcessEnabled(std::string name);
 
     void initPidFailSafePercent(void);
     void addPidFailSafePercent(std::string name, double percent);
 
+    void updateThermalPowerDebugInterface(std::string pidName,
+                                          std::string leader, double input,
+                                          double output) override;
+
   private:
     template <bool fanSensorLogging>
     void processSensorInputs(const std::vector<std::string>& sensorInputs,
diff --git a/pid/zone_interface.hpp b/pid/zone_interface.hpp
index 179c856..7797740 100644
--- a/pid/zone_interface.hpp
+++ b/pid/zone_interface.hpp
@@ -108,6 +108,12 @@
     virtual void processFans(void) = 0;
     /** For each thermal pid, do processing. */
     virtual void processThermals(void) = 0;
+
+    /** Update thermal/power debug dbus properties */
+    virtual void updateThermalPowerDebugInterface(std::string pidName,
+                                                  std::string leader,
+                                                  double input,
+                                                  double output) = 0;
 };
 
 } // namespace pid_control
diff --git a/test/pid_zone_unittest.cpp b/test/pid_zone_unittest.cpp
index 391d026..3a51d88 100644
--- a/test/pid_zone_unittest.cpp
+++ b/test/pid_zone_unittest.cpp
@@ -28,6 +28,8 @@
 static std::string modeInterface = "xyz.openbmc_project.Control.Mode";
 static std::string debugZoneInterface = "xyz.openbmc_project.Debug.Pid.Zone";
 static std::string enableInterface = "xyz.openbmc_project.Object.Enable";
+static std::string debugThermalPowerInterface =
+    "xyz.openbmc_project.Debug.Pid.ThermalPower";
 
 namespace
 {
@@ -73,6 +75,13 @@
     SetupDbusObject(&sdbus_mock_enable, defer, pidsensorpath.c_str(),
                     enableInterface, propertiesenable, &de);
 
+    EXPECT_CALL(sdbus_mock_enable,
+                sd_bus_add_object_vtable(
+                    IsNull(), NotNull(), StrEq(pidsensorpath.c_str()),
+                    StrEq(debugThermalPowerInterface), NotNull(), NotNull()))
+        .Times(::testing::AnyNumber())
+        .WillOnce(Return(0));
+
     DbusPidZone p(zone, minThermalOutput, failSafePercent, cycleTime, m,
                   bus_mock_mode, objPath, defer);
     // Success.
@@ -109,6 +118,13 @@
         SetupDbusObject(&sdbus_mock_enable, defer, pidsensorpath.c_str(),
                         enableInterface, propertiesenable,
                         &propertyenable_index);
+        EXPECT_CALL(sdbus_mock_enable,
+                    sd_bus_add_object_vtable(IsNull(), NotNull(),
+                                             StrEq(pidsensorpath.c_str()),
+                                             StrEq(debugThermalPowerInterface),
+                                             NotNull(), NotNull()))
+            .Times(::testing::AnyNumber())
+            .WillOnce(Return(0));
 
         zone = std::make_unique<DbusPidZone>(zoneId, minThermalOutput,
                                              failSafePercent, cycleTime, mgr,
@@ -128,12 +144,14 @@
     int64_t zoneId = 1;
     double minThermalOutput = 1000.0;
     double failSafePercent = 0;
+    double setpoint = 50.0;
     bool defer = true;
     const char* objPath = "/path/";
     SensorManager mgr;
     conf::CycleTime cycleTime;
 
     std::string sensorname = "temp1";
+    std::string sensorType = "temp";
     std::string pidsensorpath = "/xyz/openbmc_project/settings/fanctrl/zone1/" +
                                 sensorname;
 
@@ -174,8 +192,8 @@
         return 0;
         }));
 
-    zone->addPidControlProcess(sensorname, bus_mock_enable,
-                               pidsensorpath.c_str(), defer);
+    zone->addPidControlProcess(sensorname, sensorType, setpoint,
+                               bus_mock_enable, pidsensorpath.c_str(), defer);
     EXPECT_TRUE(zone->isPidProcessEnabled(sensorname));
 }
 
@@ -232,8 +250,8 @@
         return 0;
         }));
 
-    zone->addPidControlProcess(sensorname, bus_mock_enable,
-                               pidsensorpath.c_str(), defer);
+    zone->addPidControlProcess(sensorname, sensorType, setpoint,
+                               bus_mock_enable, pidsensorpath.c_str(), defer);
 
     // At least one value must be above the minimum thermal setpoint used in
     // the constructor otherwise it'll choose that value
@@ -276,8 +294,8 @@
         return 0;
         }));
 
-    zone->addPidControlProcess(sensorname, bus_mock_enable,
-                               pidsensorpath.c_str(), defer);
+    zone->addPidControlProcess(sensorname, sensorType, setpoint,
+                               bus_mock_enable, pidsensorpath.c_str(), defer);
 
     std::vector<double> values = {100, 200, 300, 400, 500};
 
diff --git a/test/zone_mock.hpp b/test/zone_mock.hpp
index ba167f4..8ba9c85 100644
--- a/test/zone_mock.hpp
+++ b/test/zone_mock.hpp
@@ -51,6 +51,10 @@
 
     MOCK_METHOD0(initializeLog, void());
     MOCK_METHOD1(writeLog, void(const std::string&));
+
+    MOCK_METHOD4(updateThermalPowerDebugInterface,
+                 void(std::string pidName, std::string leader, double input,
+                      double output));
 };
 
 } // namespace pid_control