Use hwmonio for attribute IO

Moves disparate error handling scenarios from the method doing the
IO to the call point.

Resolves openbmc/openbmc#2166

Change-Id: I3b6d2e175433dd8b2946ae60381901f2d7ca1798
Signed-off-by: Brad Bishop <bradleyb@fuzziesquirrel.com>
diff --git a/mainloop.cpp b/mainloop.cpp
index 11f03a5..7399df4 100644
--- a/mainloop.cpp
+++ b/mainloop.cpp
@@ -146,8 +146,8 @@
 }
 
 auto addValue(const SensorSet::key_type& sensor,
-              const std::string& hwmonRoot,
-              const std::string& instance,
+              const std::string& devPath,
+              sysfs::hwmonio::HwmonIO& ioAccess,
               ObjectInfo& info)
 {
     static constexpr bool deferSignals = true;
@@ -157,38 +157,59 @@
     auto& obj = std::get<Object>(info);
     auto& objPath = std::get<std::string>(info);
 
-    int val = 0;
-    bool retry = true;
-    size_t count = 10;
-
-
-    //Retry for up to a second if device is busy
-
-    while (retry)
+    auto readWithRetry = [&ioAccess](
+            const auto& type,
+            const auto& id,
+            const auto& sensor,
+            auto retries,
+            const auto& delay)
     {
-        try
-        {
-            val = sysfs::readSysfsWithCallout(hwmonRoot,
-                    instance,
-                    sensor.first,
-                    sensor.second,
-                    hwmon::entry::input,
-                    count > 0); //throw DeviceBusy until last attempt
-        }
-        catch (sysfs::DeviceBusyException& e)
-        {
-            count--;
-            std::this_thread::sleep_for(std::chrono::milliseconds{100});
-            continue;
-        }
-        catch(const std::exception& ioe)
-        {
-            using namespace sdbusplus::xyz::openbmc_project::Sensor::Device::Error;
-            commit<ReadFailure>();
+        auto value = 0;
 
-            return static_cast<std::shared_ptr<ValueObject>>(nullptr);
+        while(true)
+        {
+            try
+            {
+                value = ioAccess.read(type, id, sensor);
+            }
+            catch (const std::system_error& e)
+            {
+                if (e.code().value() != EAGAIN || !retries)
+                {
+                    throw;
+                }
+
+                --retries;
+                std::this_thread::sleep_for(delay);
+                continue;
+            }
+            break;
         }
-        retry = false;
+        return value;
+    };
+
+    static constexpr auto retries = 10;
+    auto val = 0;
+    try
+    {
+        // Retry for up to a second if device is busy
+        val = readWithRetry(
+                sensor.first,
+                sensor.second,
+                hwmon::entry::input,
+                retries,
+                std::chrono::milliseconds{100});
+    }
+    catch (const std::system_error& e)
+    {
+        using namespace sdbusplus::xyz::openbmc_project::Sensor::Device::Error;
+        report<ReadFailure>(
+            xyz::openbmc_project::Sensor::Device::
+                ReadFailure::CALLOUT_ERRNO(e.code().value()),
+            xyz::openbmc_project::Sensor::Device::
+                ReadFailure::CALLOUT_DEVICE_PATH(devPath.c_str()));
+
+        return static_cast<std::shared_ptr<ValueObject>>(nullptr);
     }
 
     auto iface = std::make_shared<ValueObject>(bus, objPath.c_str(), deferSignals);
@@ -219,7 +240,8 @@
       _devPath(devPath),
       _prefix(prefix),
       _root(root),
-      state()
+      state(),
+      ioAccess(path)
 {
     std::string p = path;
     while (!p.empty() && p.back() == '/')
@@ -293,7 +315,7 @@
         objectPath.append(label);
 
         ObjectInfo info(&_bus, std::move(objectPath), Object());
-        auto valueInterface = addValue(i.first, _hwmonRoot, _instance, info);
+        auto valueInterface = addValue(i.first, _devPath, ioAccess, info);
         if (!valueInterface)
         {
 #ifdef REMOVE_ON_FAIL
@@ -308,7 +330,7 @@
         //TODO openbmc/openbmc#1347
         //     Handle application restarts to set/refresh fan speed values
         auto target = addTarget<hwmon::FanSpeed>(
-                i.first, _hwmonRoot, _instance, info);
+                i.first, ioAccess.path(), _devPath, info);
 
         if (target)
         {
@@ -367,21 +389,10 @@
                 int value;
                 try
                 {
-                    try
-                    {
-                        value = sysfs::readSysfsWithCallout(_hwmonRoot,
-                                _instance,
-                                i.first.first,
-                                i.first.second,
-                                hwmon::entry::input);
-                    }
-                    catch (sysfs::DeviceBusyException& e)
-                    {
-                        //Just go with the current values and try again later.
-                        //TODO: openbmc/openbmc#2048 could keep an eye on
-                        //how long the device is actually busy.
-                        continue;
-                    }
+                    value = ioAccess.read(
+                            i.first.first,
+                            i.first.second,
+                            hwmon::entry::input);
 
                     auto& objInfo = std::get<ObjectInfo>(i.second);
                     auto& obj = std::get<Object>(objInfo);
@@ -410,10 +421,24 @@
                         }
                     }
                 }
-                catch (const std::exception& e)
+                catch (const std::system_error& e)
                 {
-                    using namespace sdbusplus::xyz::openbmc_project::Sensor::Device::Error;
-                    commit<ReadFailure>();
+                    if (e.code().value() == EAGAIN)
+                    {
+                        //Just go with the current values and try again later.
+                        //TODO: openbmc/openbmc#2048 could keep an eye on
+                        //how long the device is actually busy.
+                        continue;
+                    }
+
+                    using namespace sdbusplus::xyz::openbmc_project::
+                        Sensor::Device::Error;
+                    report<ReadFailure>(
+                            xyz::openbmc_project::Sensor::Device::
+                                ReadFailure::CALLOUT_ERRNO(e.code().value()),
+                            xyz::openbmc_project::Sensor::Device::
+                                ReadFailure::CALLOUT_DEVICE_PATH(
+                                    _devPath.c_str()));
 
 #ifdef REMOVE_ON_FAIL
                     destroy.push_back(i.first);