psu-ng: Clear faults when voltage back in range

If the last read voltage (via READ_VIN) was below the minimum and
now it is back in a valid range (100 or 200 volt range valid), clear all
the faults to allow for re-detection of faults and logging of new errors.

Trace if INPUT_FAULT_WARN or VIN_UV clear. We should not expect to see
that without sending a CLEAR_FAULTS command (or a power cycle).

Tested:
    Rainier 2S2U real hardware.
    ePDU outlet off/on allows re-detection of injected CML fault.
    - input fault, vin_uv fault, pgood/off fault.
    - repeat shows faults cleared, and new faults logged.
    Simulator pgood fault, then low voltage followed by good voltage.
    Verify simulator can re-detect faults after voltage back in range.
    Simulator fake input fault/warn on, then off and other fault on.
    - verified tracing input going off without clear faults sent.
    Simulator fake input fault/warn on, then no faults.
    - verified tracing input going off without clear faults sent.

Change-Id: Ic8022cf137978ff660680e9680f778853cbecf0d
Signed-off-by: Brandon Wyman <bjwyman@gmail.com>
diff --git a/phosphor-power-supply/test/power_supply_tests.cpp b/phosphor-power-supply/test/power_supply_tests.cpp
index 539f2fb..1eec2a0 100644
--- a/phosphor-power-supply/test/power_supply_tests.cpp
+++ b/phosphor-power-supply/test/power_supply_tests.cpp
@@ -103,9 +103,15 @@
     EXPECT_CALL(pmbus, writeBinary(ON_OFF_CONFIG, _, _));
     // Presence change from missing to present will trigger in1_input read
     // in an attempt to get CLEAR_FAULTS called.
-    EXPECT_CALL(pmbus, read(READ_VIN, _)).Times(1).WillOnce(Return(1));
+    // The voltage defaults to 0, the first call to analyze should update the
+    // voltage to the current reading, triggering another clearing of faults
+    // due to below minimum to within range voltage.
+    // This READ_VIN for CLEAR_FAULTS does not check the returned value.
+    EXPECT_CALL(pmbus, read(READ_VIN, _))
+        .Times(2)
+        .WillOnce(Return(1))
+        .WillOnce(Return(2));
     // Missing/present call will update Presence in inventory.
-    // EXPECT_CALL(mockedUtil, setPresence(_, _, true, _));
     EXPECT_CALL(util, setPresence(_, _, true, _));
 }
 
@@ -253,6 +259,10 @@
         // Set expectations for a no fault
         PMBusExpectations expectations;
         setPMBusExpectations(mockPMBus, expectations);
+        // After reading STATUS_WORD, etc., there will be a READ_VIN check.
+        EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+            .Times(1)
+            .WillOnce(Return("206000"));
         psu2.analyze();
         EXPECT_EQ(psu2.isPresent(), true);
         EXPECT_EQ(psu2.isFaulted(), false);
@@ -275,6 +285,9 @@
         expectations.statusWordValue = (status_word::INPUT_FAULT_WARN);
         expectations.statusInputValue = 0x38;
         setPMBusExpectations(mockPMBus, expectations);
+        EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+            .Times(1)
+            .WillOnce(Return("207000"));
         psu2.analyze();
         EXPECT_EQ(psu2.isPresent(), true);
         EXPECT_EQ(psu2.isFaulted(), true);
@@ -298,6 +311,9 @@
         // First need it to return good status, then the fault
         PMBusExpectations expectations;
         setPMBusExpectations(mockPMBus, expectations);
+        EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+            .Times(1)
+            .WillOnce(Return("208000"));
         psu2.analyze();
         // Now set fault bits in STATUS_WORD
         expectations.statusWordValue =
@@ -305,6 +321,10 @@
         // STATUS_INPUT fault bits ... on.
         expectations.statusInputValue = 0x38;
         setPMBusExpectations(mockPMBus, expectations);
+        // Input/UV fault, so voltage should read back low.
+        EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+            .Times(1)
+            .WillOnce(Return("19123"));
         psu2.analyze();
         EXPECT_EQ(psu2.isPresent(), true);
         EXPECT_EQ(psu2.isFaulted(), true);
@@ -321,6 +341,24 @@
         EXPECT_EQ(psu2.hasPSKillFault(), false);
         EXPECT_EQ(psu2.hasPS12VcsFault(), false);
         EXPECT_EQ(psu2.hasPSCS12VFault(), false);
+
+        // Turning VIN_UV fault off causes clearing of faults, causing read of
+        // in1_input as an attempt to get CLEAR_FAULTS called.
+        expectations.statusWordValue = 0;
+        setPMBusExpectations(mockPMBus, expectations);
+        // The call to read the voltage
+        EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+            .Times(1)
+            .WillOnce(Return("209000"));
+        // The call for CLEAR_FAULTS command
+        EXPECT_CALL(mockPMBus, read(READ_VIN, _)).Times(1).WillOnce(Return(3));
+        psu2.analyze();
+        // Should remain present, no longer be faulted, no input fault, no
+        // VIN_UV fault. Nothing else should change.
+        EXPECT_EQ(psu2.isPresent(), true);
+        EXPECT_EQ(psu2.isFaulted(), false);
+        EXPECT_EQ(psu2.hasInputFault(), false);
+        EXPECT_EQ(psu2.hasVINUVFault(), false);
     }
 
     // STATUS_WORD MFR fault.
@@ -328,12 +366,18 @@
         // First need it to return good status, then the fault
         PMBusExpectations expectations;
         setPMBusExpectations(mockPMBus, expectations);
+        EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+            .Times(1)
+            .WillOnce(Return("210000"));
         psu2.analyze();
         // Now STATUS_WORD with MFR fault bit on.
         expectations.statusWordValue = (status_word::MFR_SPECIFIC_FAULT);
         // STATUS_MFR bits on.
         expectations.statusMFRValue = 0xFF;
         setPMBusExpectations(mockPMBus, expectations);
+        EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+            .Times(1)
+            .WillOnce(Return("211000"));
         psu2.analyze();
         EXPECT_EQ(psu2.isPresent(), true);
         EXPECT_EQ(psu2.isFaulted(), true);
@@ -357,12 +401,18 @@
         // First STATUS_WORD with no bits set, then with temperature fault.
         PMBusExpectations expectations;
         setPMBusExpectations(mockPMBus, expectations);
+        EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+            .Times(1)
+            .WillOnce(Return("212000"));
         psu2.analyze();
         // STATUS_WORD with temperature fault bit on.
         expectations.statusWordValue = (status_word::TEMPERATURE_FAULT_WARN);
         // STATUS_TEMPERATURE with fault bit(s) on.
         expectations.statusTempValue = 0x10;
         setPMBusExpectations(mockPMBus, expectations);
+        EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+            .Times(1)
+            .WillOnce(Return("213000"));
         psu2.analyze();
         EXPECT_EQ(psu2.isPresent(), true);
         EXPECT_EQ(psu2.isFaulted(), true);
@@ -386,12 +436,18 @@
         // First STATUS_WORD wit no bits set, then with CML fault.
         PMBusExpectations expectations;
         setPMBusExpectations(mockPMBus, expectations);
+        EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+            .Times(1)
+            .WillOnce(Return("214000"));
         psu2.analyze();
         // STATUS_WORD with CML fault bit on.
         expectations.statusWordValue = (status_word::CML_FAULT);
         // Turn on STATUS_CML fault bit(s)
         expectations.statusCMLValue = 0xFF;
         setPMBusExpectations(mockPMBus, expectations);
+        EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+            .Times(1)
+            .WillOnce(Return("215000"));
         psu2.analyze();
         EXPECT_EQ(psu2.isPresent(), true);
         EXPECT_EQ(psu2.isFaulted(), true);
@@ -415,6 +471,9 @@
         // First STATUS_WORD with no bits set, then with VOUT/VOUT_OV fault.
         PMBusExpectations expectations;
         setPMBusExpectations(mockPMBus, expectations);
+        EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+            .Times(1)
+            .WillOnce(Return("216000"));
         psu2.analyze();
         // STATUS_WORD with VOUT/VOUT_OV fault.
         expectations.statusWordValue =
@@ -423,6 +482,9 @@
         expectations.statusVOUTValue = 0xA0;
         // STATUS_TEMPERATURE don't care (default)
         setPMBusExpectations(mockPMBus, expectations);
+        EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+            .Times(1)
+            .WillOnce(Return("217000"));
         psu2.analyze();
         EXPECT_EQ(psu2.isPresent(), true);
         EXPECT_EQ(psu2.isFaulted(), true);
@@ -446,12 +508,18 @@
         // First STATUS_WORD with no bits set, then with IOUT_OC fault.
         PMBusExpectations expectations;
         setPMBusExpectations(mockPMBus, expectations);
+        EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+            .Times(1)
+            .WillOnce(Return("218000"));
         psu2.analyze();
         // STATUS_WORD with IOUT_OC fault.
         expectations.statusWordValue = status_word::IOUT_OC_FAULT;
         // Turn on STATUS_IOUT fault bit(s)
         expectations.statusIOUTValue = 0x88;
         setPMBusExpectations(mockPMBus, expectations);
+        EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+            .Times(1)
+            .WillOnce(Return("219000"));
         psu2.analyze();
         EXPECT_EQ(psu2.isPresent(), true);
         EXPECT_EQ(psu2.isFaulted(), true);
@@ -475,12 +543,18 @@
         // First STATUS_WORD with no bits set, then with VOUT fault.
         PMBusExpectations expectations;
         setPMBusExpectations(mockPMBus, expectations);
+        EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+            .Times(1)
+            .WillOnce(Return("220000"));
         psu2.analyze();
         // Change STATUS_WORD to indicate VOUT fault.
         expectations.statusWordValue = (status_word::VOUT_FAULT);
         // Turn on STATUS_VOUT fault bit(s)
         expectations.statusVOUTValue = 0x30;
         setPMBusExpectations(mockPMBus, expectations);
+        EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+            .Times(1)
+            .WillOnce(Return("221000"));
         psu2.analyze();
         EXPECT_EQ(psu2.isPresent(), true);
         EXPECT_EQ(psu2.isFaulted(), true);
@@ -504,11 +578,17 @@
         // First STATUS_WORD with no bits set, then with fan fault.
         PMBusExpectations expectations;
         setPMBusExpectations(mockPMBus, expectations);
+        EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+            .Times(1)
+            .WillOnce(Return("222000"));
         psu2.analyze();
         expectations.statusWordValue = (status_word::FAN_FAULT);
         // STATUS_FANS_1_2 with fan 1 warning & fault bits on.
         expectations.statusFans12Value = 0xA0;
         setPMBusExpectations(mockPMBus, expectations);
+        EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+            .Times(1)
+            .WillOnce(Return("223000"));
         psu2.analyze();
         EXPECT_EQ(psu2.isPresent(), true);
         EXPECT_EQ(psu2.isFaulted(), true);
@@ -532,6 +612,9 @@
         // First STATUS_WORD with no bits set.
         PMBusExpectations expectations;
         setPMBusExpectations(mockPMBus, expectations);
+        EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+            .Times(1)
+            .WillOnce(Return("123000"));
         psu2.analyze();
         EXPECT_EQ(psu2.isFaulted(), false);
         // POWER_GOOD# inactive, and OFF bit on.
@@ -542,6 +625,9 @@
             // STATUS_INPUT, STATUS_MFR, STATUS_CML, STATUS_VOUT, and
             // STATUS_TEMPERATURE: Don't care if bits set or not (defaults).
             setPMBusExpectations(mockPMBus, expectations);
+            EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+                .Times(1)
+                .WillOnce(Return("124000"));
             psu2.analyze();
             EXPECT_EQ(psu2.isPresent(), true);
             if (x < DEGLITCH_LIMIT)
@@ -614,6 +700,9 @@
         // STATUS_WORD 0x0000 is powered on, no faults.
         PMBusExpectations expectations;
         setPMBusExpectations(mockPMBus, expectations);
+        EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+            .Times(1)
+            .WillOnce(Return("205000"));
         psu.analyze();
         // I definitely should be writting ON_OFF_CONFIG if I call the function
         EXPECT_CALL(mockPMBus, writeBinary(ON_OFF_CONFIG, ElementsAre(0x15),
@@ -639,6 +728,9 @@
     // STATUS_WORD 0x0000 is powered on, no faults.
     PMBusExpectations expectations;
     setPMBusExpectations(mockPMBus, expectations);
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("207000"));
     psu.analyze();
     EXPECT_EQ(psu.isPresent(), true);
     EXPECT_EQ(psu.isFaulted(), false);
@@ -673,6 +765,9 @@
     // STATUS_TEMPERATURE with bits on.
     expectations.statusTempValue = 0xFF;
     setPMBusExpectations(mockPMBus, expectations);
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("0"));
     psu.analyze();
     EXPECT_EQ(psu.isPresent(), true);
     EXPECT_EQ(psu.isFaulted(), true);
@@ -690,17 +785,23 @@
     // pgoodFault is deglitched up to DEGLITCH_LIMIT
     EXPECT_EQ(psu.hasPgoodFault(), false);
     setPMBusExpectations(mockPMBus, expectations);
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("0"));
     psu.analyze();
     EXPECT_EQ(psu.hasPgoodFault(), false);
     setPMBusExpectations(mockPMBus, expectations);
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("0"));
     psu.analyze();
     // DEGLITCH_LIMIT reached for pgoodFault
     EXPECT_EQ(psu.hasPgoodFault(), true);
     EXPECT_EQ(psu.hasPSKillFault(), true);
     EXPECT_EQ(psu.hasPS12VcsFault(), true);
     EXPECT_EQ(psu.hasPSCS12VFault(), true);
-
-    EXPECT_CALL(mockPMBus, read(READ_VIN, _)).Times(1).WillOnce(Return(207000));
+    // This is the CLEAR_FAULTS read that does not check the return value.
+    EXPECT_CALL(mockPMBus, read(READ_VIN, _)).Times(1).WillOnce(Return(3));
     psu.clearFaults();
     EXPECT_EQ(psu.isPresent(), true);
     EXPECT_EQ(psu.isFaulted(), false);
@@ -718,6 +819,75 @@
     EXPECT_EQ(psu.hasPS12VcsFault(), false);
     EXPECT_EQ(psu.hasPSCS12VFault(), false);
 
+    // Faults clear on READ_VIN 0 -> !0
+    // STATUS_WORD with fault bits galore!
+    expectations.statusWordValue = 0xFFFF;
+    // STATUS_INPUT with fault bits on.
+    expectations.statusInputValue = 0xFF;
+    // STATUS_MFR_SPEFIC with bits on.
+    expectations.statusMFRValue = 0xFF;
+    // STATUS_CML with bits on.
+    expectations.statusCMLValue = 0xFF;
+    // STATUS_VOUT with bits on.
+    expectations.statusVOUTValue = 0xFF;
+    // STATUS_IOUT with bits on.
+    expectations.statusIOUTValue = 0xFF;
+    // STATUS_FANS_1_2 with bits on.
+    expectations.statusFans12Value = 0xFF;
+    // STATUS_TEMPERATURE with bits on.
+    expectations.statusTempValue = 0xFF;
+    setPMBusExpectations(mockPMBus, expectations);
+    EXPECT_CALL(mockPMBus, read(READ_VIN, _)).Times(1).WillOnce(Return(0));
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("0"));
+    psu.analyze();
+    EXPECT_EQ(psu.isPresent(), true);
+    EXPECT_EQ(psu.isFaulted(), true);
+    EXPECT_EQ(psu.hasInputFault(), true);
+    EXPECT_EQ(psu.hasMFRFault(), true);
+    EXPECT_EQ(psu.hasVINUVFault(), true);
+    // True due to CML fault bits on
+    EXPECT_EQ(psu.hasCommFault(), true);
+    EXPECT_EQ(psu.hasVoutOVFault(), true);
+    EXPECT_EQ(psu.hasIoutOCFault(), true);
+    // Cannot have VOUT_OV_FAULT and VOUT_UV_FAULT.
+    // Rely on HasVoutUVFault() to verify this sets and clears.
+    EXPECT_EQ(psu.hasVoutUVFault(), false);
+    EXPECT_EQ(psu.hasFanFault(), true);
+    EXPECT_EQ(psu.hasTempFault(), true);
+    // PGOOD fault is deglitched before hasPgoodFault() returns true.
+    EXPECT_EQ(psu.hasPgoodFault(), false);
+    EXPECT_EQ(psu.hasPSKillFault(), true);
+    EXPECT_EQ(psu.hasPS12VcsFault(), true);
+    EXPECT_EQ(psu.hasPSCS12VFault(), true);
+    // STATUS_WORD with INPUT/VIN_UV fault bits off.
+    expectations.statusWordValue = 0xDFF7;
+    // STATUS_INPUT with VIN_UV_WARNING, VIN_UV_FAULT, and Unit Off For
+    // Insufficient Input Voltage bits off.
+    expectations.statusInputValue = 0xC7;
+    setPMBusExpectations(mockPMBus, expectations);
+    // READ_VIN back in range.
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("206000"));
+    psu.analyze();
+    EXPECT_EQ(psu.isPresent(), true);
+    EXPECT_EQ(psu.isFaulted(), false);
+    EXPECT_EQ(psu.hasInputFault(), false);
+    EXPECT_EQ(psu.hasMFRFault(), false);
+    EXPECT_EQ(psu.hasVINUVFault(), false);
+    EXPECT_EQ(psu.hasCommFault(), false);
+    EXPECT_EQ(psu.hasVoutOVFault(), false);
+    EXPECT_EQ(psu.hasIoutOCFault(), false);
+    EXPECT_EQ(psu.hasVoutUVFault(), false);
+    EXPECT_EQ(psu.hasFanFault(), false);
+    EXPECT_EQ(psu.hasTempFault(), false);
+    EXPECT_EQ(psu.hasPgoodFault(), false);
+    EXPECT_EQ(psu.hasPSKillFault(), false);
+    EXPECT_EQ(psu.hasPS12VcsFault(), false);
+    EXPECT_EQ(psu.hasPSCS12VFault(), false);
+
     // TODO: Faults clear on missing/present?
 }
 
@@ -750,7 +920,11 @@
         // STATUS_WORD 0x0000 is powered on, no faults.
         PMBusExpectations expectations;
         setPMBusExpectations(mockPMBus, expectations);
-        // Need analyze call to update power supply from missing to present.
+        // Call to analyze will read voltage, trigger clear faults for 0 to
+        // within range.
+        EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+            .Times(1)
+            .WillOnce(Return("123456"));
         psu.analyze();
         EXPECT_CALL(mockPMBus, readString(_, _)).WillRepeatedly(Return(""));
         psu.updateInventory();
@@ -792,6 +966,10 @@
     // Default expectations will be on, no faults.
     PMBusExpectations expectations;
     setPMBusExpectations(mockPMBus, expectations);
+    // Give it an input voltage in the 100-volt range.
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("123456"));
     psu.analyze();
     EXPECT_EQ(psu.isPresent(), true);
 }
@@ -811,6 +989,10 @@
     // Default expectations will be on, no faults.
     PMBusExpectations expectations;
     setPMBusExpectations(mockPMBus, expectations);
+    // Give it an input voltage in the 100-volt range.
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("124680"));
     psu.analyze();
     EXPECT_EQ(psu.isFaulted(), false);
     // STATUS_WORD with fault bits on.
@@ -830,6 +1012,10 @@
     // STATUS_TEMPERATURE with fault bits on.
     expectations.statusTempValue = 0xFF;
     setPMBusExpectations(mockPMBus, expectations);
+    // Also get another read of READ_VIN.
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("125790"));
     psu.analyze();
     EXPECT_EQ(psu.isFaulted(), true);
 }
@@ -848,6 +1034,10 @@
     // STATUS_WORD 0x0000 is powered on, no faults.
     PMBusExpectations expectations;
     setPMBusExpectations(mockPMBus, expectations);
+    // Analyze call will also need good READ_VIN value to check.
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("201100"));
     psu.analyze();
     EXPECT_EQ(psu.hasInputFault(), false);
     // STATUS_WORD with input fault/warn on.
@@ -855,11 +1045,19 @@
     // STATUS_INPUT with an input fault bit on.
     expectations.statusInputValue = 0x80;
     setPMBusExpectations(mockPMBus, expectations);
+    // Analyze call will also need good READ_VIN value to check.
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("201200"));
     psu.analyze();
     EXPECT_EQ(psu.hasInputFault(), true);
     // STATUS_WORD with no bits on.
     expectations.statusWordValue = 0;
     setPMBusExpectations(mockPMBus, expectations);
+    // Analyze call will also need good READ_VIN value to check.
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("201300"));
     psu.analyze();
     EXPECT_EQ(psu.hasInputFault(), false);
 }
@@ -879,6 +1077,10 @@
     // STATUS_WORD 0x0000 is powered on, no faults.
     PMBusExpectations expectations;
     setPMBusExpectations(mockPMBus, expectations);
+    // Analyze call will also need good READ_VIN value to check.
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("202100"));
     psu.analyze();
     EXPECT_EQ(psu.hasMFRFault(), false);
     // Next return STATUS_WORD with MFR fault bit on.
@@ -886,11 +1088,17 @@
     // STATUS_MFR_SPEFIC with bit(s) on.
     expectations.statusMFRValue = 0xFF;
     setPMBusExpectations(mockPMBus, expectations);
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("202200"));
     psu.analyze();
     EXPECT_EQ(psu.hasMFRFault(), true);
     // Back to no bits on in STATUS_WORD
     expectations.statusWordValue = 0;
     setPMBusExpectations(mockPMBus, expectations);
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("202300"));
     psu.analyze();
     EXPECT_EQ(psu.hasMFRFault(), false);
 }
@@ -906,9 +1114,21 @@
     EXPECT_CALL(*mockPresenceGPIO, read()).WillRepeatedly(Return(1));
     MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
     setMissingToPresentExpects(mockPMBus, mockedUtil);
+
+    // Presence change from missing to present will trigger in1_input read in
+    // an attempt to get CLEAR_FAULTS called. Return value ignored.
+    // Zero to non-zero voltage, for missing/present change, triggers clear
+    // faults call again. Return value ignored.
+    // Fault (low voltage) to not faulted (voltage in range) triggers clear
+    // faults call a third time.
+
     // STATUS_WORD 0x0000 is powered on, no faults.
     PMBusExpectations expectations;
     setPMBusExpectations(mockPMBus, expectations);
+    // Analyze call will also need good READ_VIN value to check.
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("201100"));
     psu.analyze();
     EXPECT_EQ(psu.hasVINUVFault(), false);
     // Turn fault on.
@@ -917,11 +1137,22 @@
     // Figure 16, and assume bits on in STATUS_INPUT.
     expectations.statusInputValue = 0x18;
     setPMBusExpectations(mockPMBus, expectations);
+    // If there is a VIN_UV fault, fake reading voltage of less than 20V
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("19876"));
     psu.analyze();
     EXPECT_EQ(psu.hasVINUVFault(), true);
     // Back to no fault bits on in STATUS_WORD
     expectations.statusWordValue = 0;
     setPMBusExpectations(mockPMBus, expectations);
+    // Updates now result in clearing faults if read voltage goes from below the
+    // minimum, to within a valid range.
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("201300"));
+    // Went from below minimum to within range, expect CLEAR_FAULTS.
+    EXPECT_CALL(mockPMBus, read(READ_VIN, _)).Times(1).WillOnce(Return(3));
     psu.analyze();
     EXPECT_EQ(psu.hasVINUVFault(), false);
 }
@@ -940,6 +1171,11 @@
     // STATUS_WORD 0x0000 is powered on, no faults.
     PMBusExpectations expectations;
     setPMBusExpectations(mockPMBus, expectations);
+    // Call to analyze will trigger read of "in1_input" to check voltage.
+    // Initial value would be 0, so this read updates it to non-zero.
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("202100"));
     psu.analyze();
     EXPECT_EQ(psu.hasVoutOVFault(), false);
     // Turn fault on.
@@ -948,11 +1184,17 @@
     expectations.statusVOUTValue = 0x80;
     // STATUS_TEMPERATURE default.
     setPMBusExpectations(mockPMBus, expectations);
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("202200"));
     psu.analyze();
     EXPECT_EQ(psu.hasVoutOVFault(), true);
     // Back to no fault bits on in STATUS_WORD
     expectations.statusWordValue = 0;
     setPMBusExpectations(mockPMBus, expectations);
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("202300"));
     psu.analyze();
     EXPECT_EQ(psu.hasVoutOVFault(), false);
 }
@@ -971,6 +1213,11 @@
     // STATUS_WORD 0x0000 is powered on, no faults.
     PMBusExpectations expectations;
     setPMBusExpectations(mockPMBus, expectations);
+    // Call to analyze will trigger read of "in1_input" to check voltage.
+    // Initial value would be 0, so this read updates it to non-zero.
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("203100"));
     psu.analyze();
     EXPECT_EQ(psu.hasIoutOCFault(), false);
     // Turn fault on.
@@ -978,11 +1225,17 @@
     // STATUS_IOUT fault bit(s)
     expectations.statusIOUTValue = 0x88;
     setPMBusExpectations(mockPMBus, expectations);
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("203200"));
     psu.analyze();
     EXPECT_EQ(psu.hasIoutOCFault(), true);
     // Back to no fault bits on in STATUS_WORD
     expectations.statusWordValue = 0;
     setPMBusExpectations(mockPMBus, expectations);
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("203300"));
     psu.analyze();
     EXPECT_EQ(psu.hasIoutOCFault(), false);
 }
@@ -1001,6 +1254,11 @@
     // STATUS_WORD 0x0000 is powered on, no faults.
     PMBusExpectations expectations;
     setPMBusExpectations(mockPMBus, expectations);
+    // Call to analyze will trigger read of "in1_input" to check voltage.
+    // Initial value would be 0, so this read updates it to non-zero.
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("204100"));
     psu.analyze();
     EXPECT_EQ(psu.hasVoutUVFault(), false);
     // Turn fault on.
@@ -1008,11 +1266,17 @@
     // STATUS_VOUT fault bit(s)
     expectations.statusVOUTValue = 0x30;
     setPMBusExpectations(mockPMBus, expectations);
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("204200"));
     psu.analyze();
     EXPECT_EQ(psu.hasVoutUVFault(), true);
     // Back to no fault bits on in STATUS_WORD
     expectations.statusWordValue = 0;
     setPMBusExpectations(mockPMBus, expectations);
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("204300"));
     psu.analyze();
     EXPECT_EQ(psu.hasVoutUVFault(), false);
 }
@@ -1031,6 +1295,11 @@
     // STATUS_WORD 0x0000 is powered on, no faults.
     PMBusExpectations expectations;
     setPMBusExpectations(mockPMBus, expectations);
+    // Call to analyze will trigger read of "in1_input" to check voltage.
+    // Initial value would be 0, so this read updates it to non-zero.
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("205100"));
     psu.analyze();
     EXPECT_EQ(psu.hasFanFault(), false);
     // Turn fault on.
@@ -1038,11 +1307,19 @@
     // STATUS_FANS_1_2 fault bit on (Fan 1 Fault)
     expectations.statusFans12Value = 0x80;
     setPMBusExpectations(mockPMBus, expectations);
+    // Call to analyze will trigger read of "in1_input" to check voltage.
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("205200"));
     psu.analyze();
     EXPECT_EQ(psu.hasFanFault(), true);
     // Back to no fault bits on in STATUS_WORD
     expectations.statusWordValue = 0;
     setPMBusExpectations(mockPMBus, expectations);
+    // Call to analyze will trigger read of "in1_input" to check voltage.
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("205300"));
     psu.analyze();
     EXPECT_EQ(psu.hasFanFault(), false);
 }
@@ -1061,6 +1338,11 @@
     // STATUS_WORD 0x0000 is powered on, no faults.
     PMBusExpectations expectations;
     setPMBusExpectations(mockPMBus, expectations);
+    // Call to analyze will trigger read of "in1_input" to check voltage.
+    // Initial value would be 0, so this read updates it to non-zero.
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("206100"));
     psu.analyze();
     EXPECT_EQ(psu.hasTempFault(), false);
     // Turn fault on.
@@ -1068,11 +1350,19 @@
     // STATUS_TEMPERATURE fault bit on (OT Fault)
     expectations.statusTempValue = 0x80;
     setPMBusExpectations(mockPMBus, expectations);
+    // Call to analyze will trigger read of "in1_input" to check voltage.
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("206200"));
     psu.analyze();
     EXPECT_EQ(psu.hasTempFault(), true);
     // Back to no fault bits on in STATUS_WORD
     expectations.statusWordValue = 0;
     setPMBusExpectations(mockPMBus, expectations);
+    // Call to analyze will trigger read of "in1_input" to check voltage.
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("206300"));
     psu.analyze();
     EXPECT_EQ(psu.hasTempFault(), false);
 }
@@ -1091,45 +1381,91 @@
     // STATUS_WORD 0x0000 is powered on, no faults.
     PMBusExpectations expectations;
     setPMBusExpectations(mockPMBus, expectations);
+    // Call to analyze will trigger read of "in1_input" to check voltage.
+    // Initial value would be 0, so this read updates it to non-zero.
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("207100"));
     psu.analyze();
     EXPECT_EQ(psu.hasPgoodFault(), false);
     // Setup another expectation of no faults.
     setPMBusExpectations(mockPMBus, expectations);
+    // Call to analyze will trigger read of "in1_input" to check voltage.
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("207200"));
+    psu.analyze();
+    EXPECT_EQ(psu.hasPgoodFault(), false);
+    // Setup another expectation of no faults.
+    setPMBusExpectations(mockPMBus, expectations);
+    // Call to analyze will trigger read of "in1_input" to check voltage.
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("207300"));
     psu.analyze();
     EXPECT_EQ(psu.hasPgoodFault(), false);
     // Turn PGOOD# off (fault on).
     expectations.statusWordValue = (status_word::POWER_GOOD_NEGATED);
     setPMBusExpectations(mockPMBus, expectations);
+    // Call to analyze will trigger read of "in1_input" to check voltage.
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("207400"));
     psu.analyze();
     // Expect false until reaches DEGLITCH_LIMIT
     EXPECT_EQ(psu.hasPgoodFault(), false);
     setPMBusExpectations(mockPMBus, expectations);
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("207500"));
     psu.analyze();
     // Expect false until reaches DEGLITCH_LIMIT
     EXPECT_EQ(psu.hasPgoodFault(), false);
     setPMBusExpectations(mockPMBus, expectations);
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("207600"));
     psu.analyze();
     // DEGLITCH_LIMIT reached, expect true.
     EXPECT_EQ(psu.hasPgoodFault(), true);
     // Back to no fault bits on in STATUS_WORD
     expectations.statusWordValue = 0;
     setPMBusExpectations(mockPMBus, expectations);
+    // Call to analyze will trigger read of "in1_input" to check voltage.
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("207700"));
     psu.analyze();
     EXPECT_EQ(psu.hasPgoodFault(), false);
+
     // Turn OFF bit on
     expectations.statusWordValue = (status_word::UNIT_IS_OFF);
     setPMBusExpectations(mockPMBus, expectations);
+    // Call to analyze will trigger read of "in1_input" to check voltage.
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("208100"));
     psu.analyze();
     EXPECT_EQ(psu.hasPgoodFault(), false);
     setPMBusExpectations(mockPMBus, expectations);
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("208200"));
     psu.analyze();
     EXPECT_EQ(psu.hasPgoodFault(), false);
     setPMBusExpectations(mockPMBus, expectations);
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("208300"));
     psu.analyze();
     EXPECT_EQ(psu.hasPgoodFault(), true);
     // Back to no fault bits on in STATUS_WORD
     expectations.statusWordValue = 0;
     setPMBusExpectations(mockPMBus, expectations);
+    // Call to analyze will trigger read of "in1_input" to check voltage.
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("208400"));
     psu.analyze();
     EXPECT_EQ(psu.hasPgoodFault(), false);
 }
@@ -1142,12 +1478,16 @@
         static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
     // Always return 1 to indicate present.
     EXPECT_CALL(*mockPresenceGPIO, read()).WillRepeatedly(Return(1));
-    psu.analyze();
-    EXPECT_EQ(psu.hasPSKillFault(), false);
     MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
+    setMissingToPresentExpects(mockPMBus, mockedUtil);
     // STATUS_WORD 0x0000 is powered on, no faults.
     PMBusExpectations expectations;
     setPMBusExpectations(mockPMBus, expectations);
+    // Call to analyze will trigger read of "in1_input" to check voltage.
+    // Initial value would be 0, so this read updates it to non-zero.
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("208100"));
     psu.analyze();
     EXPECT_EQ(psu.hasPSKillFault(), false);
     // Next return STATUS_WORD with MFR fault bit on.
@@ -1155,11 +1495,19 @@
     // STATUS_MFR_SPEFIC with bit(s) on.
     expectations.statusMFRValue = 0xFF;
     setPMBusExpectations(mockPMBus, expectations);
+    // Call to analyze will trigger read of "in1_input" to check voltage.
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("208200"));
     psu.analyze();
     EXPECT_EQ(psu.hasPSKillFault(), true);
     // Back to no bits on in STATUS_WORD
     expectations.statusWordValue = 0;
     setPMBusExpectations(mockPMBus, expectations);
+    // Call to analyze will trigger read of "in1_input" to check voltage.
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("208300"));
     psu.analyze();
     EXPECT_EQ(psu.hasPSKillFault(), false);
     // Next return STATUS_WORD with MFR fault bit on.
@@ -1167,11 +1515,19 @@
     // STATUS_MFR_SPEFIC with bit 4 on.
     expectations.statusMFRValue = 0x10;
     setPMBusExpectations(mockPMBus, expectations);
+    // Call to analyze will trigger read of "in1_input" to check voltage.
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("208400"));
     psu.analyze();
     EXPECT_EQ(psu.hasPSKillFault(), true);
     // Back to no bits on in STATUS_WORD
     expectations.statusWordValue = 0;
     setPMBusExpectations(mockPMBus, expectations);
+    // Call to analyze will trigger read of "in1_input" to check voltage.
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("208500"));
     psu.analyze();
     EXPECT_EQ(psu.hasPSKillFault(), false);
 }
@@ -1184,12 +1540,15 @@
         static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
     // Always return 1 to indicate present.
     EXPECT_CALL(*mockPresenceGPIO, read()).WillRepeatedly(Return(1));
-    psu.analyze();
-    EXPECT_EQ(psu.hasPS12VcsFault(), false);
     MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
+    setMissingToPresentExpects(mockPMBus, mockedUtil);
     // STATUS_WORD 0x0000 is powered on, no faults.
     PMBusExpectations expectations;
     setPMBusExpectations(mockPMBus, expectations);
+    // Call to analyze will trigger read of "in1_input" to check voltage.
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("209100"));
     psu.analyze();
     EXPECT_EQ(psu.hasPS12VcsFault(), false);
     // Next return STATUS_WORD with MFR fault bit on.
@@ -1197,11 +1556,17 @@
     // STATUS_MFR_SPEFIC with bit(s) on.
     expectations.statusMFRValue = 0xFF;
     setPMBusExpectations(mockPMBus, expectations);
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("209200"));
     psu.analyze();
     EXPECT_EQ(psu.hasPS12VcsFault(), true);
     // Back to no bits on in STATUS_WORD
     expectations.statusWordValue = 0;
     setPMBusExpectations(mockPMBus, expectations);
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("209300"));
     psu.analyze();
     EXPECT_EQ(psu.hasPS12VcsFault(), false);
     // Next return STATUS_WORD with MFR fault bit on.
@@ -1209,11 +1574,17 @@
     // STATUS_MFR_SPEFIC with bit 6 on.
     expectations.statusMFRValue = 0x40;
     setPMBusExpectations(mockPMBus, expectations);
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("209400"));
     psu.analyze();
     EXPECT_EQ(psu.hasPS12VcsFault(), true);
     // Back to no bits on in STATUS_WORD
     expectations.statusWordValue = 0;
     setPMBusExpectations(mockPMBus, expectations);
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("209500"));
     psu.analyze();
     EXPECT_EQ(psu.hasPS12VcsFault(), false);
 }
@@ -1226,12 +1597,14 @@
         static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
     // Always return 1 to indicate present.
     EXPECT_CALL(*mockPresenceGPIO, read()).WillRepeatedly(Return(1));
-    psu.analyze();
-    EXPECT_EQ(psu.hasPSCS12VFault(), false);
     MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
+    setMissingToPresentExpects(mockPMBus, mockedUtil);
     // STATUS_WORD 0x0000 is powered on, no faults.
     PMBusExpectations expectations;
     setPMBusExpectations(mockPMBus, expectations);
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("209100"));
     psu.analyze();
     EXPECT_EQ(psu.hasPSCS12VFault(), false);
     // Next return STATUS_WORD with MFR fault bit on.
@@ -1239,11 +1612,17 @@
     // STATUS_MFR_SPEFIC with bit(s) on.
     expectations.statusMFRValue = 0xFF;
     setPMBusExpectations(mockPMBus, expectations);
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("209200"));
     psu.analyze();
     EXPECT_EQ(psu.hasPSCS12VFault(), true);
     // Back to no bits on in STATUS_WORD
     expectations.statusWordValue = 0;
     setPMBusExpectations(mockPMBus, expectations);
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("209300"));
     psu.analyze();
     EXPECT_EQ(psu.hasPSCS12VFault(), false);
     // Next return STATUS_WORD with MFR fault bit on.
@@ -1251,11 +1630,17 @@
     // STATUS_MFR_SPEFIC with bit 7 on.
     expectations.statusMFRValue = 0x80;
     setPMBusExpectations(mockPMBus, expectations);
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("209400"));
     psu.analyze();
     EXPECT_EQ(psu.hasPSCS12VFault(), true);
     // Back to no bits on in STATUS_WORD
     expectations.statusWordValue = 0;
     setPMBusExpectations(mockPMBus, expectations);
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(1)
+        .WillOnce(Return("209500"));
     psu.analyze();
     EXPECT_EQ(psu.hasPSCS12VFault(), false);
 }