Fix ExitAirTempSensor calculation

When calculating maxRPM, variables tachMaxPercent and tachMinPercent
are in percentage. Both tachMaxReading and tachMinReading are already
specified as percentage in configuration file.

When cfm is less than 50% of QMin, exit air temp formula does not
work correctly. Make exit air temp not available.

Use steady_clock to ensure time elapsed is non-negative.

Increase the error print count to 5 during exit air temp computation.
This change allows power reading related error messages to be logged
in addition to fan sensor reading errors during same computation cycle.

This patch also includes minor clean up that moves powerReading
to private member.

Tested:
Before the change, exit air temp reports critical event occasionally on power up.
Examples:
Exit_Air_Temp sensor crossed a critical high threshold going high. Reading=13938.000000 Threshold=85.000000
Exit_Air_Temp sensor crossed a critical low threshold going low. Reading=-119240.000000 Threshold=0.000000

Same AC cycle test was run with the change, the issue is resolved.

Signed-off-by: Zhikui Ren <zhikui.ren@intel.com>
Change-Id: Idf9c2aa916ac741ff047c5baea51a664c101c33d
diff --git a/include/ExitAirTempSensor.hpp b/include/ExitAirTempSensor.hpp
index 191f95f..55da203 100644
--- a/include/ExitAirTempSensor.hpp
+++ b/include/ExitAirTempSensor.hpp
@@ -59,9 +59,6 @@
     double alphaF;
     double pOffset = 0;
 
-    // todo: make this private once we don't have to hack in a reading
-    boost::container::flat_map<std::string, double> powerReadings;
-
     ExitAirTempSensor(std::shared_ptr<sdbusplus::asio::connection>& conn,
                       const std::string& name,
                       const std::string& sensorConfiguration,
@@ -78,9 +75,10 @@
 
     std::vector<sdbusplus::bus::match::match> matches;
     double inletTemp = std::numeric_limits<double>::quiet_NaN();
+    boost::container::flat_map<std::string, double> powerReadings;
 
     sdbusplus::asio::object_server& objServer;
-    std::chrono::time_point<std::chrono::system_clock> lastTime;
+    std::chrono::time_point<std::chrono::steady_clock> lastTime;
     double getTotalCFM(void);
     bool calculate(double& val);
 };
diff --git a/src/ExitAirTempSensor.cpp b/src/ExitAirTempSensor.cpp
index 445a952..82b75eb 100644
--- a/src/ExitAirTempSensor.cpp
+++ b/src/ExitAirTempSensor.cpp
@@ -688,7 +688,7 @@
 
 bool ExitAirTempSensor::calculate(double& val)
 {
-    constexpr size_t maxErrorPrint = 1;
+    constexpr size_t maxErrorPrint = 5;
     static bool firstRead = false;
     static size_t errorPrint = maxErrorPrint;
 
@@ -699,6 +699,23 @@
         return false;
     }
 
+    // Though cfm is not expected to be less than qMin normally,
+    // it is not a hard limit for exit air temp calculation.
+    // 50% qMin is chosen as a generic limit between providing
+    // a valid derived exit air temp and reporting exit air temp not available.
+    constexpr const double cfmLimitFactor = 0.5;
+    if (cfm < (qMin * cfmLimitFactor))
+    {
+        if (errorPrint > 0)
+        {
+            errorPrint--;
+            std::cerr << "cfm " << cfm << " is too low, expected qMin " << qMin
+                      << "\n";
+        }
+        val = 0;
+        return false;
+    }
+
     // if there is an error getting inlet temp, return error
     if (std::isnan(inletTemp))
     {
@@ -795,7 +812,7 @@
         alpha = alphaS + ((alphaF - alphaS) * (cfm - qMin) / (qMax - qMin));
     }
 
-    auto time = std::chrono::system_clock::now();
+    auto time = std::chrono::steady_clock::now();
     if (!firstRead)
     {
         firstRead = true;
@@ -923,13 +940,9 @@
                         sensor->c2 =
                             loadVariant<double>(entry.second, "C2") / 100;
                         sensor->tachMinPercent =
-                            loadVariant<double>(entry.second,
-                                                "TachMinPercent") /
-                            100;
+                            loadVariant<double>(entry.second, "TachMinPercent");
                         sensor->tachMaxPercent =
-                            loadVariant<double>(entry.second,
-                                                "TachMaxPercent") /
-                            100;
+                            loadVariant<double>(entry.second, "TachMaxPercent");
                         sensor->createMaxCFMIface();
                         sensor->setupMatches();