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/mainloop.cpp b/mainloop.cpp
index be9b680..595432d 100644
--- a/mainloop.cpp
+++ b/mainloop.cpp
@@ -17,7 +17,6 @@
 #include <iostream>
 #include <memory>
 #include <cstdlib>
-#include <cstring>
 #include <string>
 #include <unordered_set>
 #include <sstream>
@@ -79,137 +78,6 @@
 // Store the valueAdjust for sensors
 std::map<SensorSet::key_type, valueAdjust> sensorAdjusts;
 
-void addRemoveRCs(const SensorSet::key_type& sensor,
-                  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[sensor].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 adjustValue(const SensorSet::key_type& sensor, 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
-
-    const auto& it = sensorAdjusts.find(sensor);
-    if (it != sensorAdjusts.end())
-    {
-        // Adjust based on gain and offset
-        value = static_cast<decltype(value)>(
-                    static_cast<double>(value) * it->second.gain
-                        + it->second.offset);
-    }
-    return value;
-}
-
-auto addValue(const SensorSet::key_type& sensor,
-              const RetryIO& retryIO,
-              hwmonio::HwmonIO& ioAccess,
-              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);
-
-    auto senRmRCs = env::getEnv("REMOVERCS", sensor);
-    // Add sensor removal return codes defined per sensor
-    addRemoveRCs(sensor, senRmRCs);
-
-    auto gain = env::getEnv("GAIN", sensor);
-    if (!gain.empty())
-    {
-        sensorAdjusts[sensor].gain = std::stod(gain);
-    }
-
-    auto offset = env::getEnv("OFFSET", sensor);
-    if (!offset.empty())
-    {
-        sensorAdjusts[sensor].offset = std::stoi(offset);
-    }
-
-    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(sensor, 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::string MainLoop::getID(SensorSet::container_t::const_reference sensor)
 {
     std::string id;
@@ -295,7 +163,7 @@
     // Get list of return codes for removing sensors on device
     auto devRmRCs = env::getEnv("REMOVERCS");
     // Add sensor removal return codes defined at the device level
-    addRemoveRCs(sensor.first, devRmRCs);
+    sensorObj->addRemoveRCs(devRmRCs);
 
     std::string objectPath{_root};
     objectPath.append(1, '/');
@@ -317,7 +185,7 @@
     {
         // Add status interface based on _fault file being present
         sensorObj->addStatus(info);
-        valueInterface = addValue(sensor.first, retryIO, ioAccess, info);
+        valueInterface = sensorObj->addValue(retryIO, info);
     }
     catch (const std::system_error& e)
     {
@@ -566,7 +434,7 @@
                         hwmonio::retries,
                         hwmonio::delay);
 
-                value = adjustValue(i.first, value);
+                value = sensorObjects[i.first]->adjustValue(value);
 
                 for (auto& iface : obj)
                 {
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;
diff --git a/sensor.hpp b/sensor.hpp
index 978467b..565fd01 100644
--- a/sensor.hpp
+++ b/sensor.hpp
@@ -1,5 +1,6 @@
 #pragma once
 
+#include <unordered_set>
 #include "types.hpp"
 #include "sensorset.hpp"
 #include "hwmonio.hpp"
@@ -7,6 +8,13 @@
 namespace sensor
 {
 
+struct valueAdjust
+{
+    double gain = 1.0;
+    int offset = 0;
+    std::unordered_set<int> rmRCs;
+};
+
 /** @class Sensor
  *  @brief Sensor object based on a SensorSet container's key type
  *  @details Sensor object to create and modify an associated device's sensor
@@ -35,6 +43,42 @@
                         const std::string& devPath);
 
         /**
+         * @brief Adds any sensor removal return codes for the sensor
+         * @details Add all return codes defined within a device's config file
+         * for the entire device or for the specific sensor.
+         *
+         * @param[in] rcList - List of return codes found for the sensor
+         */
+        void addRemoveRCs(const std::string& rcList);
+
+        /**
+         * @brief Adjusts a sensor value
+         * @details Adjusts the value given by any gain and/or offset defined
+         * for this sensor object and returns that adjusted value.
+         *
+         * @param[in] value - Value to be adjusted
+         *
+         * @return - Adjusted sensor value
+         */
+        int64_t adjustValue(int64_t value);
+
+        /**
+         * @brief Add value interface and value property for sensor
+         * @details When a sensor has an associated input file, the Sensor.Value
+         * interface is added along with setting the Value property to the
+         * corresponding value found in the input file.
+         *
+         * @param[in] retryIO - Hwmon sysfs file retry constraints
+         *                      (number of and delay between)
+         * @param[in] info - Sensor object information
+         *
+         * @return - Shared pointer to the value object
+         */
+        std::shared_ptr<ValueObject> addValue(
+                const RetryIO& retryIO,
+                ObjectInfo& info);
+
+        /**
          * @brief Add status interface and functional property for sensor
          * @details When a sensor has an associated fault file, the
          * OperationalStatus interface is added along with setting the
@@ -57,6 +101,9 @@
 
         /** @brief Physical device sysfs path. */
         const std::string& devPath;
+
+        /** @brief Structure for storing sensor adjustments */
+        valueAdjust sensorAdjusts;
 };
 
 } // namespace sensor