monitor: include previous targets and tachs in PEL

To discover the source of certain fan ramp-up failures, this change
outputs the previous 8 targets and tach readings. The strategy is to see
if hardware limitations prevent attaining the targets quickly enough.

Signed-off-by: Mike Capps <mikepcapps@gmail.com>
Change-Id: Ia38867986b8a8a651de5d01766393c07d413273c
diff --git a/monitor/fan.cpp b/monitor/fan.cpp
index 46a85da..fa8b392 100644
--- a/monitor/fan.cpp
+++ b/monitor/fan.cpp
@@ -1,5 +1,5 @@
 /**
- * Copyright © 2017 IBM Corporation
+ * Copyright © 2022 IBM Corporation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -25,8 +25,6 @@
 
 #include <phosphor-logging/log.hpp>
 
-#include <algorithm>
-
 namespace phosphor
 {
 namespace fan
diff --git a/monitor/system.cpp b/monitor/system.cpp
index 050913e..aff3bdc 100644
--- a/monitor/system.cpp
+++ b/monitor/system.cpp
@@ -1,5 +1,5 @@
 /**
- * Copyright © 2021 IBM Corporation
+ * Copyright © 2022 IBM Corporation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -483,11 +483,20 @@
             values["present"] = fan->present();
             values["functional"] = sensor->functional();
             values["tach"] = sensor->getInput();
+
             if (sensor->hasTarget())
             {
                 values["target"] = sensor->getTarget();
             }
 
+            // convert between string/json to remove newlines
+            values["prev_tachs"] = json(sensor->getPrevTach()).dump();
+
+            if (sensor->hasTarget())
+            {
+                values["prev_targets"] = json(sensor->getPrevTarget()).dump();
+            }
+
             data["sensors"][sensor->name()] = values;
         }
     }
diff --git a/monitor/tach_sensor.cpp b/monitor/tach_sensor.cpp
index 36b20b1..0ff1828 100644
--- a/monitor/tach_sensor.cpp
+++ b/monitor/tach_sensor.cpp
@@ -38,6 +38,8 @@
 
 constexpr auto FAN_TARGET_PROPERTY = "Target";
 constexpr auto FAN_VALUE_PROPERTY = "Value";
+constexpr auto MAX_PREV_TACHS = 8;
+constexpr auto MAX_PREV_TARGETS = 8;
 
 namespace fs = std::filesystem;
 using InternalFailure =
@@ -88,6 +90,13 @@
     // Query functional state from inventory
     // TODO - phosphor-fan-presence/issues/25
 
+    _prevTachs.resize(MAX_PREV_TACHS);
+
+    if (_hasTarget)
+    {
+        _prevTargets.resize(MAX_PREV_TARGETS);
+    }
+
     _functional = true;
 
     try
@@ -177,7 +186,20 @@
     if (_hasTarget)
     {
         readProperty(_interface, FAN_TARGET_PROPERTY, _name, _bus, _tachTarget);
+
+        // record previous target value
+        if (_prevTargets.front() != _tachTarget)
+        {
+            _prevTargets.push_front(_tachTarget);
+
+            _prevTargets.pop_back();
+        }
     }
+
+    // record previous tach value
+    _prevTachs.push_front(_tachInput);
+
+    _prevTachs.pop_back();
 }
 
 std::string TachSensor::getMatchString(const std::string& interface)
@@ -277,6 +299,14 @@
 
     // Check all tach sensors on the fan against the target
     _fan.tachChanged();
+
+    // record previous target value
+    if (_prevTargets.front() != _tachTarget)
+    {
+        _prevTargets.push_front(_tachTarget);
+
+        _prevTargets.pop_back();
+    }
 }
 
 void TachSensor::handleTachChange(sdbusplus::message::message& msg)
@@ -286,6 +316,11 @@
 
     // Check just this sensor against the target
     _fan.tachChanged(*this);
+
+    // record previous tach value
+    _prevTachs.push_front(_tachInput);
+
+    _prevTachs.pop_back();
 }
 
 void TachSensor::startTimer(TimerMode mode)
diff --git a/monitor/tach_sensor.hpp b/monitor/tach_sensor.hpp
index 87c69ac..5b214c4 100644
--- a/monitor/tach_sensor.hpp
+++ b/monitor/tach_sensor.hpp
@@ -10,6 +10,7 @@
 #include <sdeventplus/utility/timer.hpp>
 
 #include <chrono>
+#include <deque>
 #include <optional>
 #include <utility>
 
@@ -360,6 +361,22 @@
      */
     void updateTachAndTarget();
 
+    /**
+     * @brief return the previous tach values
+     */
+    const std::deque<uint64_t>& getPrevTach() const
+    {
+        return _prevTachs;
+    }
+
+    /**
+     * @brief return the previous target values
+     */
+    const std::deque<uint64_t>& getPrevTarget() const
+    {
+        return _prevTargets;
+    }
+
   private:
     /**
      * @brief Returns the match string to use for matching
@@ -537,6 +554,16 @@
     std::unique_ptr<
         sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>
         _countTimer;
+
+    /**
+     * @brief record of previous targets
+     */
+    std::deque<uint64_t> _prevTargets;
+
+    /**
+     * @brief record of previous tach readings
+     */
+    std::deque<uint64_t> _prevTachs;
 };
 
 } // namespace monitor