psu-ng: Add code to set ON_OFF_CONFIG

Add code that sends the appropriate ON_OFF_CONFIG mask for the power
supply power on operation.

Tested:
    Ran gtest using x86sdk
    Used simulator to change ON_OFF_CONFIG value, restarted service,
    verified ON_OFF_CONFIG changed.
    Used i2cget on hardware to change ON_OFF_CONFIG, restarted service,
    verified ON_OFF_CONFIG changed.

Signed-off-by: Brandon Wyman <bjwyman@gmail.com>
Change-Id: Ifd9d63fcd2e86a62b7358e08958b5e2dbd21db9f
diff --git a/phosphor-power-supply/power_supply.cpp b/phosphor-power-supply/power_supply.cpp
index 37e5666..8c80ef3 100644
--- a/phosphor-power-supply/power_supply.cpp
+++ b/phosphor-power-supply/power_supply.cpp
@@ -93,6 +93,30 @@
     }
 }
 
+void PowerSupply::onOffConfig(uint8_t data)
+{
+    using namespace phosphor::pmbus;
+
+    if (present)
+    {
+        log<level::INFO>("ON_OFF_CONFIG write", entry("DATA=0x%02X", data));
+        try
+        {
+            std::vector<uint8_t> configData{data};
+            pmbusIntf->writeBinary(ON_OFF_CONFIG, configData,
+                                   Type::HwmonDeviceDebug);
+        }
+        catch (...)
+        {
+            // The underlying code in writeBinary will log a message to the
+            // journal if the write fails. If the ON_OFF_CONFIG is not setup as
+            // desired, later fault detection and analysis code should catch any
+            // of the fall out. We should not need to terminate the application
+            // if this write fails.
+        }
+    }
+}
+
 void PowerSupply::clearFaults()
 {
     faultFound = false;
@@ -133,6 +157,7 @@
         if (std::get<bool>(valPropMap->second))
         {
             present = true;
+            onOffConfig(phosphor::pmbus::ON_OFF_CONFIG_CONTROL_PIN_ONLY);
             clearFaults();
         }
         else
diff --git a/phosphor-power-supply/power_supply.hpp b/phosphor-power-supply/power_supply.hpp
index 707a745..487fa53 100644
--- a/phosphor-power-supply/power_supply.hpp
+++ b/phosphor-power-supply/power_supply.hpp
@@ -65,6 +65,16 @@
     void analyze();
 
     /**
+     * Write PMBus ON_OFF_CONFIG
+     *
+     * This function will be called to cause the PMBus device driver to send the
+     * ON_OFF_CONFIG command. Takes one byte of data.
+     *
+     * @param[in] data - The ON_OFF_CONFIG data byte mask.
+     */
+    void onOffConfig(uint8_t data);
+
+    /**
      * Write PMBus CLEAR_FAULTS
      *
      * This function will be called in various situations in order to clear
diff --git a/phosphor-power-supply/psu_manager.hpp b/phosphor-power-supply/psu_manager.hpp
index a3bcae0..a9a0bd5 100644
--- a/phosphor-power-supply/psu_manager.hpp
+++ b/phosphor-power-supply/psu_manager.hpp
@@ -87,6 +87,7 @@
             powerOn = false;
         }
 
+        onOffConfig(phosphor::pmbus::ON_OFF_CONFIG_CONTROL_PIN_ONLY);
         clearFaults();
         updateInventory();
     }
@@ -100,6 +101,20 @@
     }
 
     /**
+     * Write PMBus ON_OFF_CONFIG
+     *
+     * This function will be called to cause the PMBus device driver to send the
+     * ON_OFF_CONFIG command. Takes one byte of data.
+     */
+    void onOffConfig(const uint8_t data)
+    {
+        for (auto& psu : psus)
+        {
+            psu->onOffConfig(data);
+        }
+    }
+
+    /**
      * This function will be called in various situations in order to clear
      * any fault status bits that may have been set, in order to start over
      * with a clean state. Presence changes and power state changes will want
diff --git a/phosphor-power-supply/test/mock.hpp b/phosphor-power-supply/test/mock.hpp
index 0c64e00..c4c2c9d 100644
--- a/phosphor-power-supply/test/mock.hpp
+++ b/phosphor-power-supply/test/mock.hpp
@@ -17,6 +17,9 @@
 
     MOCK_METHOD(uint64_t, read, (const std::string& name, Type type),
                 (override));
+    MOCK_METHOD(void, writeBinary,
+                (const std::string& name, std::vector<uint8_t> data, Type type),
+                (override));
 };
 } // namespace pmbus
 
diff --git a/phosphor-power-supply/test/power_supply_tests.cpp b/phosphor-power-supply/test/power_supply_tests.cpp
index c6d4814..5eb4b3e 100644
--- a/phosphor-power-supply/test/power_supply_tests.cpp
+++ b/phosphor-power-supply/test/power_supply_tests.cpp
@@ -11,8 +11,11 @@
 using namespace phosphor::pmbus;
 
 using ::testing::_;
+using ::testing::Args;
 using ::testing::Assign;
 using ::testing::DoAll;
+using ::testing::ElementsAre;
+using ::testing::NotNull;
 using ::testing::Return;
 using ::testing::StrEq;
 
@@ -148,6 +151,46 @@
     // TODO: ReadFailure
 }
 
+TEST_F(PowerSupplyTests, OnOffConfig)
+{
+    auto bus = sdbusplus::bus::new_default();
+    uint8_t data = 0x15;
+
+    // Test where PSU is NOT present
+    try
+    {
+        EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath)))
+            .Times(1)
+            .WillOnce(Return(false));
+        PowerSupply psu{bus, PSUInventoryPath, 4, "0069"};
+        MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
+        // If it is not present, I should not be trying to write to it.
+        EXPECT_CALL(mockPMBus, writeBinary(_, _, _)).Times(0);
+        psu.onOffConfig(data);
+    }
+    catch (...)
+    {
+    }
+
+    // Test where PSU is present
+    try
+    {
+        EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath)))
+            .Times(1)
+            .WillOnce(Return(true)); // present
+        PowerSupply psu{bus, PSUInventoryPath, 5, "006a"};
+        MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
+        // TODO: ???should I check the filename?
+        EXPECT_CALL(mockPMBus,
+                    writeBinary(_, ElementsAre(0x15), Type::HwmonDeviceDebug))
+            .Times(1);
+        psu.onOffConfig(data);
+    }
+    catch (...)
+    {
+    }
+}
+
 TEST_F(PowerSupplyTests, ClearFaults)
 {
     auto bus = sdbusplus::bus::new_default();