Add I2C interface to Device class

Add an I2C interface to the phosphor-regulators C++ Device class.

Use the I2CInterface class from the tools/i2c directory of this
repository.

Also add the other required properties of the JSON "device" object to
the C++ Device class.

The JSON "device" object is in the phosphor-regulators config file.  For
more information, see phosphor-regulators/docs/config_file/device.md.

Signed-off-by: Shawn McCarney <shawnmm@us.ibm.com>
Change-Id: Idc780b1a11372d6597762cfb6540fa44f1cfb64e
diff --git a/phosphor-regulators/src/device.hpp b/phosphor-regulators/src/device.hpp
index ba4c067..b4c2af6 100644
--- a/phosphor-regulators/src/device.hpp
+++ b/phosphor-regulators/src/device.hpp
@@ -15,7 +15,11 @@
  */
 #pragma once
 
+#include "i2c_interface.hpp"
+
+#include <memory>
 #include <string>
+#include <utility>
 
 namespace phosphor::power::regulators
 {
@@ -40,8 +44,16 @@
      * Constructor.
      *
      * @param id unique device ID
+     * @param isRegulator indicates whether this device is a voltage regulator
+     * @param fru Field-Replaceable Unit (FRU) for this device
+     * @param i2cInterface I2C interface to this device
      */
-    explicit Device(const std::string& id) : id{id}
+    explicit Device(const std::string& id, bool isRegulator,
+                    const std::string& fru,
+                    std::unique_ptr<i2c::I2CInterface> i2cInterface) :
+        id{id},
+        isRegulatorDevice{isRegulator}, fru{fru}, i2cInterface{
+                                                      std::move(i2cInterface)}
     {
     }
 
@@ -55,11 +67,62 @@
         return id;
     }
 
+    /**
+     * Returns whether this device is a voltage regulator.
+     *
+     * @return true if device is a voltage regulator, false otherwise
+     */
+    bool isRegulator() const
+    {
+        return isRegulatorDevice;
+    }
+
+    /**
+     * Returns the Field-Replaceable Unit (FRU) for this device.
+     *
+     * Returns the D-Bus inventory path of the FRU.  If the device itself is not
+     * a FRU, returns the FRU that contains the device.
+     *
+     * @return FRU for this device
+     */
+    const std::string& getFRU() const
+    {
+        return fru;
+    }
+
+    /**
+     * Gets the I2C interface to this device.
+     *
+     * @return I2C interface to device
+     */
+    i2c::I2CInterface& getI2CInterface()
+    {
+        return *i2cInterface;
+    }
+
   private:
     /**
      * Unique ID of this device.
      */
     const std::string id{};
+
+    /**
+     * Indicates whether this device is a voltage regulator.
+     */
+    const bool isRegulatorDevice{false};
+
+    /**
+     * Field-Replaceable Unit (FRU) for this device.
+     *
+     * Set to the D-Bus inventory path of the FRU.  If the device itself is not
+     * a FRU, set to the FRU that contains the device.
+     */
+    const std::string fru{};
+
+    /**
+     * I2C interface to this device.
+     */
+    std::unique_ptr<i2c::I2CInterface> i2cInterface{};
 };
 
 } // namespace phosphor::power::regulators
diff --git a/phosphor-regulators/src/meson.build b/phosphor-regulators/src/meson.build
index 4337095..121bf45 100644
--- a/phosphor-regulators/src/meson.build
+++ b/phosphor-regulators/src/meson.build
@@ -13,7 +13,10 @@
     'phosphor-regulators',
     phosphor_regulators_library_source_files,
     implicit_include_directories: false,
-    include_directories: phosphor_regulators_include_directories
+    include_directories: [
+        phosphor_regulators_include_directories,
+        libi2c_inc
+    ]
 )
 
 phosphor_regulators = executable(
diff --git a/phosphor-regulators/test/actions/action_environment_tests.cpp b/phosphor-regulators/test/actions/action_environment_tests.cpp
index d861a25..5561705 100644
--- a/phosphor-regulators/test/actions/action_environment_tests.cpp
+++ b/phosphor-regulators/test/actions/action_environment_tests.cpp
@@ -15,13 +15,16 @@
  */
 #include "action_environment.hpp"
 #include "device.hpp"
+#include "i2c_interface.hpp"
 #include "id_map.hpp"
+#include "mocked_i2c_interface.hpp"
 #include "rule.hpp"
 
 #include <cstddef> // for size_t
 #include <exception>
 #include <memory>
 #include <stdexcept>
+#include <utility>
 #include <vector>
 
 #include <gtest/gtest.h>
@@ -32,7 +35,12 @@
 {
     // Create IDMap
     IDMap idMap{};
-    Device reg1{"regulator1"};
+
+    // Create Device and add to IDMap
+    std::unique_ptr<i2c::I2CInterface> i2cInterface =
+        i2c::create(1, 0x70, i2c::I2CInterface::InitialState::CLOSED);
+    Device reg1{"regulator1", true, "/system/chassis/motherboard/reg1",
+                std::move(i2cInterface)};
     idMap.addDevice(reg1);
 
     // Verify object state after constructor
@@ -71,7 +79,12 @@
 {
     // Create IDMap
     IDMap idMap{};
-    Device reg1{"regulator1"};
+
+    // Create Device and add to IDMap
+    std::unique_ptr<i2c::I2CInterface> i2cInterface =
+        i2c::create(1, 0x70, i2c::I2CInterface::InitialState::CLOSED);
+    Device reg1{"regulator1", true, "/system/chassis/motherboard/reg1",
+                std::move(i2cInterface)};
     idMap.addDevice(reg1);
 
     ActionEnvironment env{idMap, "regulator1"};
@@ -250,10 +263,7 @@
 TEST(ActionEnvironmentTests, SetDeviceID)
 {
     IDMap idMap{};
-    Device reg1{"regulator1"};
-    idMap.addDevice(reg1);
     ActionEnvironment env{idMap, "regulator1"};
-
     EXPECT_EQ(env.getDeviceID(), "regulator1");
     env.setDeviceID("regulator2");
     EXPECT_EQ(env.getDeviceID(), "regulator2");
diff --git a/phosphor-regulators/test/actions/set_device_action_tests.cpp b/phosphor-regulators/test/actions/set_device_action_tests.cpp
index 6164a46..1aa6cfc 100644
--- a/phosphor-regulators/test/actions/set_device_action_tests.cpp
+++ b/phosphor-regulators/test/actions/set_device_action_tests.cpp
@@ -15,10 +15,14 @@
  */
 #include "action_environment.hpp"
 #include "device.hpp"
+#include "i2c_interface.hpp"
 #include "id_map.hpp"
+#include "mocked_i2c_interface.hpp"
 #include "set_device_action.hpp"
 
 #include <exception>
+#include <memory>
+#include <utility>
 
 #include <gtest/gtest.h>
 
@@ -34,9 +38,19 @@
 {
     // Create IDMap
     IDMap idMap{};
-    Device reg1{"regulator1"};
+
+    // Create Device regulator1 and add to IDMap
+    std::unique_ptr<i2c::I2CInterface> i2cInterface =
+        i2c::create(1, 0x70, i2c::I2CInterface::InitialState::CLOSED);
+    Device reg1{"regulator1", true, "/system/chassis/motherboard/reg1",
+                std::move(i2cInterface)};
     idMap.addDevice(reg1);
-    Device reg2{"regulator2"};
+
+    // Create Device regulator2 and add to IDMap
+    i2cInterface =
+        i2c::create(1, 0x72, i2c::I2CInterface::InitialState::CLOSED);
+    Device reg2{"regulator2", true, "/system/chassis/motherboard/reg2",
+                std::move(i2cInterface)};
     idMap.addDevice(reg2);
 
     // Create ActionEnvironment
diff --git a/phosphor-regulators/test/device_tests.cpp b/phosphor-regulators/test/device_tests.cpp
index 1d979b0..fb92fd7 100644
--- a/phosphor-regulators/test/device_tests.cpp
+++ b/phosphor-regulators/test/device_tests.cpp
@@ -14,19 +14,66 @@
  * limitations under the License.
  */
 #include "device.hpp"
+#include "i2c_interface.hpp"
+#include "mocked_i2c_interface.hpp"
+
+#include <memory>
+#include <utility>
 
 #include <gtest/gtest.h>
 
 using namespace phosphor::power::regulators;
 
+/**
+ * Create an I2CInterface object with hard-coded bus and address values.
+ *
+ * @return I2CInterface object wrapped in a unique_ptr
+ */
+std::unique_ptr<i2c::I2CInterface> createI2CInterface()
+{
+    std::unique_ptr<i2c::I2CInterface> i2cInterface =
+        i2c::create(1, 0x70, i2c::I2CInterface::InitialState::CLOSED);
+    return i2cInterface;
+}
+
 TEST(DeviceTests, Constructor)
 {
-    Device device("vdd_vrm2");
-    EXPECT_EQ(device.getID(), "vdd_vrm2");
+    std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
+    i2c::I2CInterface* i2cInterfacePtr = i2cInterface.get();
+    Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2",
+                  std::move(i2cInterface)};
+    EXPECT_EQ(device.getID(), "vdd_reg");
+    EXPECT_EQ(device.isRegulator(), true);
+    EXPECT_EQ(device.getFRU(), "/system/chassis/motherboard/reg2");
+    EXPECT_EQ(&(device.getI2CInterface()), i2cInterfacePtr);
 }
 
 TEST(DeviceTests, GetID)
 {
-    Device device("vio_vrm");
-    EXPECT_EQ(device.getID(), "vio_vrm");
+    Device device{"vdd_reg", false, "/system/chassis/motherboard/reg2",
+                  std::move(createI2CInterface())};
+    EXPECT_EQ(device.getID(), "vdd_reg");
+}
+
+TEST(DeviceTests, IsRegulator)
+{
+    Device device{"vdd_reg", false, "/system/chassis/motherboard/reg2",
+                  std::move(createI2CInterface())};
+    EXPECT_EQ(device.isRegulator(), false);
+}
+
+TEST(DeviceTests, GetFRU)
+{
+    Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2",
+                  std::move(createI2CInterface())};
+    EXPECT_EQ(device.getFRU(), "/system/chassis/motherboard/reg2");
+}
+
+TEST(DeviceTests, GetI2CInterface)
+{
+    std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
+    i2c::I2CInterface* i2cInterfacePtr = i2cInterface.get();
+    Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2",
+                  std::move(i2cInterface)};
+    EXPECT_EQ(&(device.getI2CInterface()), i2cInterfacePtr);
 }
diff --git a/phosphor-regulators/test/id_map_tests.cpp b/phosphor-regulators/test/id_map_tests.cpp
index ffa6c15..d3053d7 100644
--- a/phosphor-regulators/test/id_map_tests.cpp
+++ b/phosphor-regulators/test/id_map_tests.cpp
@@ -14,7 +14,9 @@
  * limitations under the License.
  */
 #include "device.hpp"
+#include "i2c_interface.hpp"
 #include "id_map.hpp"
+#include "mocked_i2c_interface.hpp"
 #include "rail.hpp"
 #include "rule.hpp"
 
@@ -22,6 +24,7 @@
 #include <memory>
 #include <stdexcept>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include <gtest/gtest.h>
@@ -33,8 +36,11 @@
     IDMap idMap{};
 
     // Create device
+    std::unique_ptr<i2c::I2CInterface> i2cInterface =
+        i2c::create(1, 0x70, i2c::I2CInterface::InitialState::CLOSED);
     std::string id{"vio_reg"};
-    Device device{id};
+    Device device{id, true, "/system/chassis/motherboard/vio_reg",
+                  std::move(i2cInterface)};
 
     // Verify device is not initially in map
     EXPECT_THROW(idMap.getDevice(id), std::invalid_argument);
@@ -123,9 +129,14 @@
 {
     IDMap idMap{};
 
-    // Add a device to the map
+    // Create device
+    std::unique_ptr<i2c::I2CInterface> i2cInterface =
+        i2c::create(1, 0x70, i2c::I2CInterface::InitialState::CLOSED);
     std::string id{"vio_reg"};
-    Device device{id};
+    Device device{id, true, "/system/chassis/motherboard/vio_reg",
+                  std::move(i2cInterface)};
+
+    // Add a device to the map
     idMap.addDevice(device);
 
     // Test where ID found in map
diff --git a/phosphor-regulators/test/meson.build b/phosphor-regulators/test/meson.build
index 1d261f7..6db6b88 100644
--- a/phosphor-regulators/test/meson.build
+++ b/phosphor-regulators/test/meson.build
@@ -26,11 +26,16 @@
                     gmock,
                     gtest,
                 ],
-                link_with: phosphor_regulators_library,
+                link_with: [
+                    phosphor_regulators_library,
+                    libi2c_dev_mock
+                ],
                 implicit_include_directories: false,
                 include_directories: [
                     phosphor_regulators_include_directories,
-                    phosphor_regulators_tests_include_directories
+                    phosphor_regulators_tests_include_directories,
+                    libi2c_inc,
+                    libi2c_dev_mock_inc
                 ]
      )
 )