Support averaging power values

Support new env variables 'AVERAGE_power* = "true"' in hwmon config file.
When this env variable is set, power value is the calculated average value.
Otherwise, power value is from power*_input by default.
The new average of power is calculated since the last time the sensor's
values were changed and read.

average =
(cur_average*cur_average_interval - pre_average*pre_average_interval) /
(cur_average_interval - pre_average_interval)

hwmon config example:
AVERAGE_power2 = "true"
AVERAGE_power3 = "true"
AVERAGE_power4 = "true"

Tested: Set AVERAGE_power* in p0 OCC hwmon conf but not in p1 OCC hwmon conf,
then get power sensor info with restapi to check the values.
1. The values of p0*power are all average values.
2. The values of p1*power are all input values.

Note:
Delete $(CODE_COVERAGE_CPPFLAGS) in AM_CPPFLAGS in test/Makefile.am.
This option will define NDEBUG during configuration, then assert in
code doesn't work.

Resolves: openbmc/openbmc#3187
Signed-off-by: Carol Wang <wangkair@cn.ibm.com>
Change-Id: I8d97a7b2905c79cd4f2c276b32e7f5590ffc0483
diff --git a/mainloop.cpp b/mainloop.cpp
index 05ac623..4abfc02 100644
--- a/mainloop.cpp
+++ b/mainloop.cpp
@@ -27,6 +27,7 @@
 #include "sysfs.hpp"
 #include "targets.hpp"
 #include "thresholds.hpp"
+#include "util.hpp"
 
 #include <cassert>
 #include <cstdlib>
@@ -351,6 +352,13 @@
 
             _state[std::move(i.first)] = std::move(value);
         }
+
+        // Initialize _averageMap of sensor. e.g. <<power, 1>, <0, 0>>
+        if ((i.first.first == hwmon::type::power) &&
+            (phosphor::utility::isAverageEnvSet(i.first)))
+        {
+            _average.setAverageValue(i.first, std::make_pair(0, 0));
+        }
     }
 
     /* If there are no sensors specified by labels, exit. */
@@ -394,11 +402,18 @@
         }
 
         // Read value from sensor.
-        std::string input = hwmon::entry::cinput;
-        if (sensorSysfsType == "pwm")
+        std::string input = hwmon::entry::input;
+        if (sensorSysfsType == hwmon::type::pwm)
         {
             input = "";
         }
+        // If type is power and AVERAGE_power* is true in env, use average
+        // instead of input
+        else if ((sensorSysfsType == hwmon::type::power) &&
+                 (phosphor::utility::isAverageEnvSet(sensorSetKey)))
+        {
+            input = hwmon::entry::average;
+        }
 
         int64_t value;
         auto& obj = std::get<InterfaceMap>(objInfo);
@@ -437,6 +452,41 @@
                 statusIface->functional(true);
 
                 value = sensor->adjustValue(value);
+
+                if (input == hwmon::entry::average)
+                {
+                    // Calculate the values of averageMap based on current
+                    // average value, current average_interval value, previous
+                    // average value, previous average_interval value
+                    int64_t interval =
+                        _ioAccess->read(sensorSysfsType, sensorSysfsNum,
+                                        hwmon::entry::caverage_interval,
+                                        hwmonio::retries, hwmonio::delay);
+                    auto ret = _average.getAverageValue(sensorSetKey);
+                    assert(ret);
+
+                    const auto& [preAverage, preInterval] = *ret;
+
+                    auto calValue = Average::calcAverage(
+                        preAverage, preInterval, value, interval);
+                    if (calValue)
+                    {
+                        // Update previous values in averageMap before the
+                        // variable value is changed next
+                        _average.setAverageValue(
+                            sensorSetKey, std::make_pair(value, interval));
+                        // Update value to be calculated average
+                        value = calValue.value();
+                    }
+                    else
+                    {
+                        // the value of
+                        // power*_average_interval is not changed yet, use the
+                        // previous calculated average instead. So skip dbus
+                        // update.
+                        continue;
+                    }
+                }
             }
 
             updateSensorInterfaces(obj, value);
@@ -450,9 +500,8 @@
             // as the code may exit before reaching it.
             statusIface->functional(false);
 #endif
-            auto file =
-                sysfs::make_sysfs_path(_ioAccess->path(), sensorSysfsType,
-                                       sensorSysfsNum, hwmon::entry::cinput);
+            auto file = sysfs::make_sysfs_path(
+                _ioAccess->path(), sensorSysfsType, sensorSysfsNum, input);
 
             // Check sensorAdjusts for sensor removal RCs
             auto& sAdjusts = _sensorObjects[sensorSetKey]->getAdjusts();
@@ -534,10 +583,18 @@
 
                 _state[std::move(ssValueType.first)] = std::move(value);
 
+                std::string input = hwmon::entry::input;
+                // If type is power and AVERAGE_power* is true in env, use
+                // average instead of input
+                if ((it->first.first == hwmon::type::power) &&
+                    (phosphor::utility::isAverageEnvSet(it->first)))
+                {
+                    input = hwmon::entry::average;
+                }
                 // Sensor object added, erase entry from removal list
-                auto file = sysfs::make_sysfs_path(
-                    _ioAccess->path(), it->first.first, it->first.second,
-                    hwmon::entry::cinput);
+                auto file =
+                    sysfs::make_sysfs_path(_ioAccess->path(), it->first.first,
+                                           it->first.second, input);
 
                 log<level::INFO>("Added sensor to dbus after successful read",
                                  entry("FILE=%s", file.c_str()));