Move value iface creation into sensor object

Create the Sensor.Value interface for a sensor within the sensor object.
Each sensor must have an input sysfs file to get a Value property on the
Sensor.Value interface and be included by hwmon.

Tested:
    No change in value interface creation for sensors

Change-Id: I09b1c79142ba2a34424f5ec29f41d19a987c84e7
Signed-off-by: Matthew Barth <msbarth@us.ibm.com>
diff --git a/sensor.cpp b/sensor.cpp
index 3a1ed73..155b8bd 100644
--- a/sensor.cpp
+++ b/sensor.cpp
@@ -1,16 +1,21 @@
+#include <cstring>
 #include <experimental/filesystem>
 
 #include <phosphor-logging/elog-errors.hpp>
 #include <xyz/openbmc_project/Sensor/Device/error.hpp>
 
+#include "config.h"
 #include "sensor.hpp"
 #include "sensorset.hpp"
 #include "hwmon.hpp"
+#include "env.hpp"
 #include "sysfs.hpp"
 
 namespace sensor
 {
 
+using namespace phosphor::logging;
+
 Sensor::Sensor(const SensorSet::key_type& sensor,
                const hwmonio::HwmonIO& ioAccess,
                const std::string& devPath) :
@@ -20,6 +25,116 @@
 {
 }
 
+void Sensor::addRemoveRCs(const std::string& rcList)
+{
+    if (rcList.empty())
+    {
+        return;
+    }
+
+    // Convert to a char* for strtok
+    std::vector<char> rmRCs(rcList.c_str(),
+                            rcList.c_str() + rcList.size() + 1);
+    auto rmRC = std::strtok(&rmRCs[0], ", ");
+    while (rmRC != nullptr)
+    {
+        try
+        {
+            sensorAdjusts.rmRCs.insert(std::stoi(rmRC));
+        }
+        catch (const std::logic_error& le)
+        {
+            // Unable to convert to int, continue to next token
+            std::string name = sensor.first + "_" + sensor.second;
+            log<level::INFO>("Unable to convert sensor removal return code",
+                             entry("SENSOR=%s", name.c_str()),
+                             entry("RC=%s", rmRC),
+                             entry("EXCEPTION=%s", le.what()));
+        }
+        rmRC = std::strtok(nullptr, ", ");
+    }
+}
+
+int64_t Sensor::adjustValue(int64_t value)
+{
+// Because read doesn't have an out pointer to store errors.
+// let's assume negative values are errors if they have this
+// set.
+#ifdef NEGATIVE_ERRNO_ON_FAIL
+    if (value < 0)
+    {
+        return value;
+    }
+#endif
+
+    // Adjust based on gain and offset
+    value = static_cast<decltype(value)>(
+                static_cast<double>(value) * sensorAdjusts.gain
+                    + sensorAdjusts.offset);
+
+    return value;
+}
+
+std::shared_ptr<ValueObject> Sensor::addValue(
+        const RetryIO& retryIO,
+        ObjectInfo& info)
+{
+    static constexpr bool deferSignals = true;
+
+    // Get the initial value for the value interface.
+    auto& bus = *std::get<sdbusplus::bus::bus*>(info);
+    auto& obj = std::get<Object>(info);
+    auto& objPath = std::get<std::string>(info);
+
+    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));
+        val = adjustValue(val);
+    }
+
+    auto iface = std::make_shared<ValueObject>(bus, objPath.c_str(), deferSignals);
+    iface->value(val);
+
+    hwmon::Attributes attrs;
+    if (hwmon::getAttributes(sensor.first, attrs))
+    {
+        iface->unit(hwmon::getUnit(attrs));
+        iface->scale(hwmon::getScale(attrs));
+    }
+
+    auto maxValue = env::getEnv("MAXVALUE", sensor);
+    if(!maxValue.empty())
+    {
+        iface->maxValue(std::stoll(maxValue));
+    }
+    auto minValue = env::getEnv("MINVALUE", sensor);
+    if(!minValue.empty())
+    {
+        iface->minValue(std::stoll(minValue));
+    }
+
+    obj[InterfaceType::VALUE] = iface;
+    return iface;
+}
+
 std::shared_ptr<StatusObject> Sensor::addStatus(ObjectInfo& info)
 {
     namespace fs = std::experimental::filesystem;