pid/zone: Adding unscaled to cache and logging

The "ReadReturn" structure, and the cache within DbusPidZone, have
been widened, to hold both the scaled and the original unscaled values
at the same time. This allows logging to show both at once, and also
clears up confusion/bugs resulting from storing one or the other and
losing track of which was which.

Compatibility setValue() and getCachedValue() functions still
retained, so this will not break other sensors. These functions still
only take a single argument/return, which will be used for both value
and unscaled, indicating scaling is unknown or irrelevant to this
sensor.

Also, the PWM output of the PID loop appears in the log file,
conveniently right alongside the RPM input of the PID loop.

An output cache has been added to the zone interface, and, unlike the
input cache, use of it is optional. It is only to help populate the
logging, so subclasses are free to ignore it if they want.

Tested: In the logging files, I can see both PWM and RPM, and they are
consistent, showing how the PID loop is trying to update the PWM to
target the desired RPM.

Example: Here's /tmp/zone_0.log on my system
epoch_ms,setpt,fan0_tach,fan0_tach_raw,fan0_tach_pwm,fan0_tach_pwm_raw,bmcmargin_zone0,bmcmargin_zone0_raw,thermal_zone0,thermal_zone0_raw,failsafe
3097918,3818.42,0.748267,11224,0,0,0.724753,56.812,0.745098,62,0
3098022,3818.42,0.748267,11224,0.266666,67,0.724753,56.812,0.745098,62,0
3098132,3818.42,0.748267,11224,0.266666,67,0.724753,56.812,0.745098,62,0

Here's what we can now learn:
The desired setpoint is 3818 RPM.
The fan is at 74.8% of scale, which is 11224 RPM.
The written PWM, after the first PID loop pass, is a raw value of 67,
which is 26.6% of scale.
The first margin temperature is 56.8 degrees of margin, which is 72.4%
of scale.
The second margin temperature is 62 degrees of margin, which is 74.5%
of scale.
This zone is not in failsafe mode.
As you can see, this will be rather useful for PID loop tuning.

Signed-off-by: Josh Lehan <krellan@google.com>
Change-Id: I972a4e4a3b787255f0dcafa10d4498ee58b682f0
diff --git a/pid/zone.cpp b/pid/zone.cpp
index 1eda992..585cbeb 100644
--- a/pid/zone.cpp
+++ b/pid/zone.cpp
@@ -153,9 +153,20 @@
 
 double DbusPidZone::getCachedValue(const std::string& name)
 {
+    return _cachedValuesByName.at(name).scaled;
+}
+
+ValueCacheEntry DbusPidZone::getCachedValues(const std::string& name)
+{
     return _cachedValuesByName.at(name);
 }
 
+void DbusPidZone::setOutputCache(std::string_view name,
+                                 const ValueCacheEntry& values)
+{
+    _cachedFanOutputs[std::string{name}] = values;
+}
+
 void DbusPidZone::addFanInput(const std::string& fan)
 {
     _fanInputs.push_back(fan);
@@ -284,29 +295,28 @@
 void DbusPidZone::initializeLog(void)
 {
     /* Print header for log file:
-     * epoch_ms,setpt,fan1,fan2,fanN,sensor1,sensor2,sensorN,failsafe
+     * epoch_ms,setpt,fan1,fan1_raw,fan1_pwm,fan1_pwm_raw,fan2,fan2_raw,fan2_pwm,fan2_pwm_raw,fanN,fanN_raw,fanN_pwm,fanN_pwm_raw,sensor1,sensor1_raw,sensor2,sensor2_raw,sensorN,sensorN_raw,failsafe
      */
 
     _log << "epoch_ms,setpt,requester";
 
     for (const auto& f : _fanInputs)
     {
-        _log << "," << f;
+        _log << "," << f << "," << f << "_raw";
+        _log << "," << f << "_pwm," << f << "_pwm_raw";
     }
     for (const auto& t : _thermalInputs)
     {
-        _log << "," << t;
+        _log << "," << t << "," << t << "_raw";
     }
+
     _log << ",failsafe";
     _log << std::endl;
-
-    return;
 }
 
 void DbusPidZone::writeLog(const std::string& value)
 {
     _log << value;
-    return;
 }
 
 /*
@@ -342,7 +352,7 @@
     {
         auto sensor = _mgr.getSensor(f);
         ReadReturn r = sensor->read();
-        _cachedValuesByName[f] = r.value;
+        _cachedValuesByName[f] = {r.value, r.unscaled};
         int64_t timeout = sensor->getTimeout();
         tstamp then = r.updated;
 
@@ -357,7 +367,10 @@
          */
         if (loggingEnabled)
         {
-            _log << "," << r.value;
+            const auto& v = _cachedValuesByName[f];
+            _log << "," << v.scaled << "," << v.unscaled;
+            const auto& p = _cachedFanOutputs[f];
+            _log << "," << p.scaled << "," << p.unscaled;
         }
 
         // check if fan fail.
@@ -384,7 +397,8 @@
     {
         for (const auto& t : _thermalInputs)
         {
-            _log << "," << _cachedValuesByName[t];
+            const auto& v = _cachedValuesByName[t];
+            _log << "," << v.scaled << "," << v.unscaled;
         }
     }
 
@@ -403,7 +417,7 @@
         ReadReturn r = sensor->read();
         int64_t timeout = sensor->getTimeout();
 
-        _cachedValuesByName[t] = r.value;
+        _cachedValuesByName[t] = {r.value, r.unscaled};
         tstamp then = r.updated;
 
         auto duration = duration_cast<std::chrono::seconds>(now - then).count();
@@ -434,9 +448,12 @@
 
 void DbusPidZone::initializeCache(void)
 {
+    auto nan = std::numeric_limits<double>::quiet_NaN();
+
     for (const auto& f : _fanInputs)
     {
-        _cachedValuesByName[f] = 0;
+        _cachedValuesByName[f] = {nan, nan};
+        _cachedFanOutputs[f] = {nan, nan};
 
         // Start all fans in fail-safe mode.
         _failSafeSensors.insert(f);
@@ -444,7 +461,7 @@
 
     for (const auto& t : _thermalInputs)
     {
-        _cachedValuesByName[t] = 0;
+        _cachedValuesByName[t] = {nan, nan};
 
         // Start all sensors in fail-safe mode.
         _failSafeSensors.insert(t);
@@ -456,7 +473,15 @@
     std::cerr << "Cache values now: \n";
     for (const auto& [name, value] : _cachedValuesByName)
     {
-        std::cerr << name << ": " << value << "\n";
+        std::cerr << name << ": " << value.scaled << " " << value.unscaled
+                  << "\n";
+    }
+
+    std::cerr << "Fan outputs now: \n";
+    for (const auto& [name, value] : _cachedFanOutputs)
+    {
+        std::cerr << name << ": " << value.scaled << " " << value.unscaled
+                  << "\n";
     }
 }