Add status interface to sensors

When a fault sysfs file is present for a sensor, the OperationalStatus
interface is attached to the sensor object. The functional property is
initially set to the corresponding value read from the fault sysfs file
when the sensor object is created. A follow-up commit will address
updating the functional property based on reading the fault sysfs file
during the polling interval.

Tested:
    OperationalStatus interface created for sensors with fault files
    Interface not created for sensors without fault file
    Functional property set to correct value from sensor's fault file

Change-Id: Id75b3711d048d4667d2173a3255512cf5482ab67
Signed-off-by: Matthew Barth <msbarth@us.ibm.com>
diff --git a/sensor.cpp b/sensor.cpp
new file mode 100644
index 0000000..cbcbfeb
--- /dev/null
+++ b/sensor.cpp
@@ -0,0 +1,83 @@
+#include <experimental/filesystem>
+
+#include <phosphor-logging/elog-errors.hpp>
+#include <xyz/openbmc_project/Sensor/Device/error.hpp>
+
+#include "sensor.hpp"
+#include "sensorset.hpp"
+#include "hwmon.hpp"
+#include "sysfs.hpp"
+
+namespace sensor
+{
+
+std::shared_ptr<StatusObject> addStatus(
+        const SensorSet::key_type& sensor,
+        const hwmonio::HwmonIO& ioAccess,
+        const std::string& devPath,
+        ObjectInfo& info)
+{
+    namespace fs = std::experimental::filesystem;
+
+    std::shared_ptr<StatusObject> iface = nullptr;
+    static constexpr bool deferSignals = true;
+    auto& bus = *std::get<sdbusplus::bus::bus*>(info);
+    auto& objPath = std::get<std::string>(info);
+    auto& obj = std::get<Object>(info);
+
+    // Check if fault sysfs file exists
+    std::string faultName = sensor.first;
+    std::string faultID = sensor.second;
+    std::string entry = hwmon::entry::fault;
+
+    auto sysfsFullPath = sysfs::make_sysfs_path(ioAccess.path(),
+                                                faultName,
+                                                faultID,
+                                                entry);
+    if (fs::exists(sysfsFullPath))
+    {
+        bool functional = true;
+        uint32_t fault = 0;
+        try
+        {
+            fault = ioAccess.read(faultName,
+                                  faultID,
+                                  entry,
+                                  hwmonio::retries,
+                                  hwmonio::delay);
+            if (fault != 0)
+            {
+                functional = false;
+            }
+        }
+        catch (const std::system_error& e)
+        {
+            using namespace phosphor::logging;
+            using namespace sdbusplus::xyz::openbmc_project::
+                Sensor::Device::Error;
+            using metadata = xyz::openbmc_project::Sensor::
+                Device::ReadFailure;
+
+            report<ReadFailure>(
+                    metadata::CALLOUT_ERRNO(e.code().value()),
+                    metadata::CALLOUT_DEVICE_PATH(devPath.c_str()));
+
+            log<level::INFO>("Logging failing sysfs file",
+                    phosphor::logging::entry(
+                            "FILE=%s", sysfsFullPath.c_str()));
+        }
+
+        iface = std::make_shared<StatusObject>(
+                bus,
+                objPath.c_str(),
+                deferSignals);
+        // Set functional property
+        iface->functional(functional);
+
+        obj[InterfaceType::STATUS] = iface;
+    }
+
+    return iface;
+}
+
+} // namespace sensor