Fault status check before reading sensor value

Checking for the fault sysfs file should be done prior to reading the
input value when creating the sensor's dbus object. A sensor providing a
fault sysfs file will have a status interface functional property
created with its initial functional state. A sensor in a nonfunctional
state when the object is created, will have an initial value of 0.

The hwmon documentation states that when a sensor input channel presents
an associated fault file, the measurement value provided for that
channel should not be trusted when the fault boolean has a value of 1.
Using an initial value of 0 follows this specification and allows the
corresponding dbus object to be created.

Tested:
    Faulted sensor at hwmon start shows functional status of false.
    Faulted sensor at hwmon start contains a sensor value of 0.

Change-Id: I6388a3f84f638360b03e557aadc6de8331e67a69
Signed-off-by: Matthew Barth <msbarth@us.ibm.com>
diff --git a/mainloop.cpp b/mainloop.cpp
index a9898b7..ad73df7 100644
--- a/mainloop.cpp
+++ b/mainloop.cpp
@@ -149,16 +149,6 @@
     // Add sensor removal return codes defined per sensor
     addRemoveRCs(sensor, senRmRCs);
 
-    // Retry for up to a second if device is busy
-    // or has a transient error.
-    int64_t val = ioAccess.read(
-            sensor.first,
-            sensor.second,
-            hwmon::entry::cinput,
-            std::get<size_t>(retryIO),
-            std::get<std::chrono::milliseconds>(retryIO),
-            isOCC);
-
     auto gain = env::getEnv("GAIN", sensor);
     if (!gain.empty())
     {
@@ -171,7 +161,30 @@
         sensorAdjusts[sensor].offset = std::stoi(offset);
     }
 
-    val = adjustValue(sensor, val);
+    int64_t val = 0;
+    std::shared_ptr<StatusObject> statusIface = nullptr;
+    auto it = obj.find(InterfaceType::STATUS);
+    if (it != obj.end())
+    {
+        statusIface = std::experimental::any_cast<
+                std::shared_ptr<StatusObject>>(it->second);
+    }
+
+    // If there's no fault file or the sensor has a fault file and
+    // its status is functional, read the input value.
+    if (!statusIface || (statusIface && statusIface->functional()))
+    {
+        // Retry for up to a second if device is busy
+        // or has a transient error.
+        val = ioAccess.read(
+                sensor.first,
+                sensor.second,
+                hwmon::entry::cinput,
+                std::get<size_t>(retryIO),
+                std::get<std::chrono::milliseconds>(retryIO),
+                isOCC);
+        val = adjustValue(sensor, val);
+    }
 
     auto iface = std::make_shared<ValueObject>(bus, objPath.c_str(), deferSignals);
     iface->value(val);
@@ -292,6 +305,8 @@
             std::shared_ptr<ValueObject>>(nullptr);
     try
     {
+        // Add status interface based on _fault file being present
+        sensor::addStatus(sensor.first, ioAccess, _devPath, info);
         valueInterface = addValue(sensor.first, retryIO, ioAccess, info,
                 _isOCC);
     }
@@ -358,9 +373,6 @@
     }
     addTarget<hwmon::FanPwm>(sensor.first, ioAccess, _devPath, info);
 
-    // Add status interface based on _fault file being present
-    sensor::addStatus(sensor.first, ioAccess, _devPath, info);
-
     // All the interfaces have been created.  Go ahead
     // and emit InterfacesAdded.
     valueInterface->emit_object_added();