Add hwmon support to PMBus class

Add support to allow the class to handle accessing
hwmon files even though the device path passed to
the constructor wasn't a hwmon path.

This is useful because the users of this class have
to access files in both locations.

For example:
  PMBus p(basePath);

  p.write("myfile", 1, Type::Base)
    -> writes to basePath/myfile

  p.write("myfile", 1, Type::Hwmon)
    -> writes to basePath/hwmon/hwmonN/myfile
       where hwmonN is the hwmon dir for the device

Change-Id: Ic66835dace2a9958310c9f4ee8cbcaae3669dd0f
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
diff --git a/pmbus.cpp b/pmbus.cpp
index 85e7c43..bd9e697 100644
--- a/pmbus.cpp
+++ b/pmbus.cpp
@@ -48,18 +48,25 @@
     return name;
 }
 
-bool PMBus::readBitInPage(const std::string& name, size_t page)
+bool PMBus::readBitInPage(const std::string& name,
+                          size_t page,
+                          Type type)
 {
     auto pagedBit = insertPageNum(name, page);
-    return readBit(pagedBit);
+    return readBit(pagedBit, type);
 }
 
-bool PMBus::readBit(const std::string& name)
+bool PMBus::readBit(const std::string& name, Type type)
 {
     unsigned long int value = 0;
     std::ifstream file;
     fs::path path{basePath};
 
+    if (type == Type::Hwmon)
+    {
+        path /= hwmonRelPath;
+    }
+
     path /= name;
 
     file.exceptions(std::ifstream::failbit |
@@ -103,11 +110,16 @@
     return value != 0;
 }
 
-void PMBus::write(const std::string& name, int value)
+void PMBus::write(const std::string& name, int value, Type type)
 {
     std::ofstream file;
     fs::path path{basePath};
 
+    if (type == Type::Hwmon)
+    {
+        path /= hwmonRelPath;
+    }
+
     path /= name;
 
     file.exceptions(std::ofstream::failbit |
@@ -134,5 +146,34 @@
     }
 }
 
+void PMBus::findHwmonRelativePath()
+{
+    fs::path path{basePath};
+    path /= "hwmon";
+
+    //look for <basePath>/hwmon/hwmonN/
+    for (auto& f : fs::directory_iterator(path))
+    {
+        if ((f.path().filename().string().find("hwmon") !=
+            std::string::npos) &&
+            (fs::is_directory(f.path())))
+        {
+            hwmonRelPath = "hwmon";
+            hwmonRelPath /= f.path().filename();
+            break;
+        }
+    }
+
+    //Don't really want to crash here, just log it
+    //and let accesses fail later
+    if (hwmonRelPath.empty())
+    {
+        log<level::ERR>("Unable to find hwmon directory "
+                        "in device base path",
+                        entry("DEVICE_PATH=%s", basePath.c_str()));
+    }
+
+}
+
 }
 }
diff --git a/pmbus.hpp b/pmbus.hpp
index fc269ac..d384279 100644
--- a/pmbus.hpp
+++ b/pmbus.hpp
@@ -10,10 +10,24 @@
 {
 
 /**
+ * If the access should be done in the base
+ * device directory or the hwmon directory.
+ */
+enum class Type
+{
+    Base,
+    Hwmon
+};
+
+/**
  * @class PMBus
  *
  * This class is an interface to communicating with PMBus devices
  * by reading and writing sysfs files.
+ *
+ * Based on the Type parameter, the accesses can either be done
+ * in the base device directory (the one passed into the constructor),
+ * or in the hwmon directory for the device.
  */
 class PMBus
 {
@@ -34,6 +48,7 @@
         PMBus(const std::string& path) :
             basePath(path)
         {
+            findHwmonRelativePath();
         }
 
         /**
@@ -42,10 +57,11 @@
          *
          * @param[in] name - path concatenated to
          *                   basePath to read
+         * @param[in] type - either Base or Hwmon
          *
          * @return bool - false if result was 0, else true
          */
-        bool readBit(const std::string& name);
+        bool readBit(const std::string& name, Type type);
 
         /**
          * Reads a file in sysfs that represents a single bit,
@@ -55,11 +71,13 @@
          * @param[in] name - path concatenated to
          *                   basePath to read
          * @param[in] page - page number
+         * @param[in] type - either Base or Hwmon
          *
          * @return bool - false if result was 0, else true
          */
         bool readBitInPage(const std::string& name,
-                           size_t page);
+                           size_t page,
+                           Type type);
 
         /**
          * Writes an integer value to the file, therefore doing
@@ -68,8 +86,9 @@
          * @param[in] name - path concatenated to
          *                   basePath to write
          * @param[in] value - the value to write
+         * @param[in] type - either Base or Hwmon
          */
-        void write(const std::string& name, int value);
+        void write(const std::string& name, int value, Type type);
 
         /**
          * Returns the sysfs base path of this device
@@ -95,6 +114,12 @@
         static std::string insertPageNum(const std::string& templateName,
                                          size_t page);
 
+        /**
+         * Finds the path relative to basePath to the hwmon directory
+         * for the device and stores it in hwmonRelPath.
+         */
+         void findHwmonRelativePath();
+
     private:
 
         /**
@@ -102,6 +127,11 @@
          */
         std::experimental::filesystem::path basePath;
 
+        /**
+         * The relative (to basePath) path to the hwmon directory
+         */
+        std::experimental::filesystem::path hwmonRelPath;
+
 };
 
 }