psu-ng: De-glitch all faults

Use DEGLITCH_LIMIT to determine all the faults. If a fault bit is on, do
not consider that a fault until it is seen at least DEGLITCH_LIMIT
times. With DEGLITCH_LIMIT set to 3, the monitor would need to see a
fault bit on 3 times in a row before indicating that the power supply
has that fault.

This was done earlier for the PGOOD fault detection.

Change-Id: I918c2fcdd1d90ae253ab268bd04aa7a0da0208b8
Signed-off-by: Brandon Wyman <bjwyman@gmail.com>
diff --git a/phosphor-power-supply/power_supply.cpp b/phosphor-power-supply/power_supply.cpp
index c2dccfb..cc846ac 100644
--- a/phosphor-power-supply/power_supply.cpp
+++ b/phosphor-power-supply/power_supply.cpp
@@ -193,15 +193,19 @@
 {
     if (statusWord & phosphor::pmbus::status_word::CML_FAULT)
     {
-        if (!cmlFault)
+        if (cmlFault < DEGLITCH_LIMIT)
         {
             log<level::ERR>(fmt::format("CML fault: STATUS_WORD = {:#04x}, "
                                         "STATUS_CML = {:#02x}",
                                         statusWord, statusCML)
                                 .c_str());
-        }
 
-        cmlFault = true;
+            cmlFault++;
+        }
+    }
+    else
+    {
+        cmlFault = 0;
     }
 }
 
@@ -209,16 +213,16 @@
 {
     if (statusWord & phosphor::pmbus::status_word::INPUT_FAULT_WARN)
     {
-        if (!inputFault)
+        if (inputFault < DEGLITCH_LIMIT)
         {
             log<level::ERR>(fmt::format("INPUT fault: STATUS_WORD = {:#04x}, "
                                         "STATUS_MFR_SPECIFIC = {:#02x}, "
                                         "STATUS_INPUT = {:#02x}",
                                         statusWord, statusMFR, statusInput)
                                 .c_str());
-        }
 
-        inputFault = true;
+            inputFault++;
+        }
     }
 
     // If had INPUT/VIN_UV fault, and now off.
@@ -232,7 +236,7 @@
                         "STATUS_INPUT = {:#02x}",
                         statusWord, statusMFR, statusInput)
                 .c_str());
-        inputFault = false;
+        inputFault = 0;
     }
 }
 
@@ -240,7 +244,7 @@
 {
     if (statusWord & phosphor::pmbus::status_word::VOUT_OV_FAULT)
     {
-        if (!voutOVFault)
+        if (voutOVFault < DEGLITCH_LIMIT)
         {
             log<level::ERR>(
                 fmt::format("VOUT_OV_FAULT fault: STATUS_WORD = {:#04x}, "
@@ -248,9 +252,13 @@
                             "STATUS_VOUT = {:#02x}",
                             statusWord, statusMFR, statusVout)
                     .c_str());
-        }
 
-        voutOVFault = true;
+            voutOVFault++;
+        }
+    }
+    else
+    {
+        voutOVFault = 0;
     }
 }
 
@@ -258,16 +266,20 @@
 {
     if (statusWord & phosphor::pmbus::status_word::IOUT_OC_FAULT)
     {
-        if (!ioutOCFault)
+        if (ioutOCFault < DEGLITCH_LIMIT)
         {
             log<level::ERR>(fmt::format("IOUT fault: STATUS_WORD = {:#04x}, "
                                         "STATUS_MFR_SPECIFIC = {:#02x}, "
                                         "STATUS_IOUT = {:#02x}",
                                         statusWord, statusMFR, statusIout)
                                 .c_str());
-        }
 
-        ioutOCFault = true;
+            ioutOCFault++;
+        }
+    }
+    else
+    {
+        ioutOCFault = 0;
     }
 }
 
@@ -276,7 +288,7 @@
     if ((statusWord & phosphor::pmbus::status_word::VOUT_FAULT) &&
         !(statusWord & phosphor::pmbus::status_word::VOUT_OV_FAULT))
     {
-        if (!voutUVFault)
+        if (voutUVFault < DEGLITCH_LIMIT)
         {
             log<level::ERR>(
                 fmt::format("VOUT_UV_FAULT fault: STATUS_WORD = {:#04x}, "
@@ -284,9 +296,13 @@
                             "STATUS_VOUT = {:#02x}",
                             statusWord, statusMFR, statusVout)
                     .c_str());
-        }
 
-        voutUVFault = true;
+            voutUVFault++;
+        }
+    }
+    else
+    {
+        voutUVFault = 0;
     }
 }
 
@@ -294,7 +310,7 @@
 {
     if (statusWord & phosphor::pmbus::status_word::FAN_FAULT)
     {
-        if (!fanFault)
+        if (fanFault < DEGLITCH_LIMIT)
         {
             log<level::ERR>(fmt::format("FANS fault/warning: "
                                         "STATUS_WORD = {:#04x}, "
@@ -302,9 +318,13 @@
                                         "STATUS_FANS_1_2 = {:#02x}",
                                         statusWord, statusMFR, statusFans12)
                                 .c_str());
-        }
 
-        fanFault = true;
+            fanFault++;
+        }
+    }
+    else
+    {
+        fanFault = 0;
     }
 }
 
@@ -312,7 +332,7 @@
 {
     if (statusWord & phosphor::pmbus::status_word::TEMPERATURE_FAULT_WARN)
     {
-        if (!tempFault)
+        if (tempFault < DEGLITCH_LIMIT)
         {
             log<level::ERR>(fmt::format("TEMPERATURE fault/warning: "
                                         "STATUS_WORD = {:#04x}, "
@@ -321,9 +341,13 @@
                                         statusWord, statusMFR,
                                         statusTemperature)
                                 .c_str());
-        }
 
-        tempFault = true;
+            tempFault++;
+        }
+    }
+    else
+    {
+        tempFault = 0;
     }
 }
 
@@ -356,17 +380,38 @@
         // IBM MFR_SPECIFIC[4] is PS_Kill fault
         if (statusMFR & 0x10)
         {
-            psKillFault = true;
+            if (psKillFault < DEGLITCH_LIMIT)
+            {
+                psKillFault++;
+            }
+        }
+        else
+        {
+            psKillFault = 0;
         }
         // IBM MFR_SPECIFIC[6] is 12Vcs fault.
         if (statusMFR & 0x40)
         {
-            ps12VcsFault = true;
+            if (ps12VcsFault < DEGLITCH_LIMIT)
+            {
+                ps12VcsFault++;
+            }
+        }
+        else
+        {
+            ps12VcsFault = 0;
         }
         // IBM MFR_SPECIFIC[7] is 12V Current-Share fault.
         if (statusMFR & 0x80)
         {
-            psCS12VFault = true;
+            if (psCS12VFault < DEGLITCH_LIMIT)
+            {
+                psCS12VFault++;
+            }
+        }
+        else
+        {
+            psCS12VFault = 0;
         }
     }
 }
@@ -375,34 +420,37 @@
 {
     if (statusWord & phosphor::pmbus::status_word::MFR_SPECIFIC_FAULT)
     {
-        if (!mfrFault)
+        if (mfrFault < DEGLITCH_LIMIT)
         {
             log<level::ERR>(fmt::format("MFR fault: "
                                         "STATUS_WORD = {:#04x} "
                                         "STATUS_MFR_SPECIFIC = {:#02x}",
                                         statusWord, statusMFR)
                                 .c_str());
+            mfrFault++;
         }
 
-        mfrFault = true;
         determineMFRFault();
     }
+    else
+    {
+        mfrFault = 0;
+    }
 }
 
 void PowerSupply::analyzeVinUVFault()
 {
     if (statusWord & phosphor::pmbus::status_word::VIN_UV_FAULT)
     {
-        if (!vinUVFault)
+        if (vinUVFault < DEGLITCH_LIMIT)
         {
             log<level::ERR>(fmt::format("VIN_UV fault: STATUS_WORD = {:#04x}, "
                                         "STATUS_MFR_SPECIFIC = {:#02x}, "
                                         "STATUS_INPUT = {:#02x}",
                                         statusWord, statusMFR, statusInput)
                                 .c_str());
+            vinUVFault++;
         }
-
-        vinUVFault = true;
     }
 
     if (vinUVFault &&
@@ -414,7 +462,7 @@
                         "STATUS_INPUT = {:#02x}",
                         statusWord, statusMFR, statusInput)
                 .c_str());
-        vinUVFault = false;
+        vinUVFault = 0;
     }
 }
 
diff --git a/phosphor-power-supply/power_supply.hpp b/phosphor-power-supply/power_supply.hpp
index eb53c14..b7459f5 100644
--- a/phosphor-power-supply/power_supply.hpp
+++ b/phosphor-power-supply/power_supply.hpp
@@ -109,20 +109,20 @@
      */
     void clearFaultFlags()
     {
-        inputFault = false;
-        mfrFault = false;
+        inputFault = 0;
+        mfrFault = 0;
         statusMFR = 0;
-        vinUVFault = false;
-        cmlFault = false;
-        voutOVFault = false;
-        ioutOCFault = false;
-        voutUVFault = false;
-        fanFault = false;
-        tempFault = false;
+        vinUVFault = 0;
+        cmlFault = 0;
+        voutOVFault = 0;
+        ioutOCFault = 0;
+        voutUVFault = 0;
+        fanFault = 0;
+        tempFault = 0;
         pgoodFault = 0;
-        psKillFault = false;
-        ps12VcsFault = false;
-        psCS12VFault = false;
+        psKillFault = 0;
+        ps12VcsFault = 0;
+        psCS12VFault = 0;
     }
 
     /**
@@ -229,9 +229,13 @@
      */
     bool isFaulted() const
     {
-        return (hasCommFault() || vinUVFault || inputFault || voutOVFault ||
-                ioutOCFault || voutUVFault || fanFault || tempFault ||
-                (pgoodFault >= DEGLITCH_LIMIT) || mfrFault);
+        return (hasCommFault() || (vinUVFault >= DEGLITCH_LIMIT) ||
+                (inputFault >= DEGLITCH_LIMIT) ||
+                (voutOVFault >= DEGLITCH_LIMIT) ||
+                (ioutOCFault >= DEGLITCH_LIMIT) ||
+                (voutUVFault >= DEGLITCH_LIMIT) ||
+                (fanFault >= DEGLITCH_LIMIT) || (tempFault >= DEGLITCH_LIMIT) ||
+                (pgoodFault >= DEGLITCH_LIMIT) || (mfrFault >= DEGLITCH_LIMIT));
     }
 
     /**
@@ -255,7 +259,7 @@
      */
     bool hasInputFault() const
     {
-        return inputFault;
+        return (inputFault >= DEGLITCH_LIMIT);
     }
 
     /**
@@ -263,7 +267,7 @@
      */
     bool hasMFRFault() const
     {
-        return mfrFault;
+        return (mfrFault >= DEGLITCH_LIMIT);
     }
 
     /**
@@ -271,7 +275,7 @@
      */
     bool hasVINUVFault() const
     {
-        return vinUVFault;
+        return (vinUVFault >= DEGLITCH_LIMIT);
     }
 
     /**
@@ -279,7 +283,7 @@
      */
     bool hasVoutOVFault() const
     {
-        return voutOVFault;
+        return (voutOVFault >= DEGLITCH_LIMIT);
     }
 
     /**
@@ -287,7 +291,7 @@
      */
     bool hasIoutOCFault() const
     {
-        return ioutOCFault;
+        return (ioutOCFault >= DEGLITCH_LIMIT);
     }
 
     /**
@@ -295,7 +299,7 @@
      */
     bool hasVoutUVFault() const
     {
-        return voutUVFault;
+        return (voutUVFault >= DEGLITCH_LIMIT);
     }
 
     /**
@@ -303,7 +307,7 @@
      */
     bool hasFanFault() const
     {
-        return fanFault;
+        return (fanFault >= DEGLITCH_LIMIT);
     }
 
     /**
@@ -311,7 +315,7 @@
      */
     bool hasTempFault() const
     {
-        return tempFault;
+        return (tempFault >= DEGLITCH_LIMIT);
     }
 
     /**
@@ -328,7 +332,7 @@
      */
     bool hasPSKillFault() const
     {
-        return psKillFault;
+        return (psKillFault >= DEGLITCH_LIMIT);
     }
 
     /**
@@ -336,7 +340,7 @@
      */
     bool hasPS12VcsFault() const
     {
-        return ps12VcsFault;
+        return (ps12VcsFault >= DEGLITCH_LIMIT);
     }
 
     /**
@@ -344,7 +348,7 @@
      */
     bool hasPSCS12VFault() const
     {
-        return psCS12VFault;
+        return (psCS12VFault >= DEGLITCH_LIMIT);
     }
 
     /**
@@ -391,7 +395,7 @@
      */
     bool hasCommFault() const
     {
-        return ((readFail >= LOG_LIMIT) || (cmlFault));
+        return ((readFail >= LOG_LIMIT) || (cmlFault >= DEGLITCH_LIMIT));
     }
 
     /**
@@ -439,33 +443,59 @@
     /** @brief True if an error for a fault has already been logged. */
     bool faultLogged = false;
 
-    /** @brief True if bit 1 of STATUS_WORD low byte is on. */
-    bool cmlFault = false;
+    /** @brief Incremented if bit 1 of STATUS_WORD low byte is on.
+     *
+     * Considered faulted if reaches DEGLITCH_LIMIT.
+     */
+    size_t cmlFault = 0;
 
-    /** @brief True if bit 5 of STATUS_WORD high byte is on. */
-    bool inputFault = false;
+    /** @brief Incremented if bit 5 of STATUS_WORD high byte is on.
+     *
+     * Considered faulted if reaches DEGLITCH_LIMIT.
+     */
+    size_t inputFault = 0;
 
-    /** @brief True if bit 4 of STATUS_WORD high byte is on. */
-    bool mfrFault = false;
+    /** @brief Incremented if bit 4 of STATUS_WORD high byte is on.
+     *
+     * Considered faulted if reaches DEGLITCH_LIMIT.
+     */
+    size_t mfrFault = 0;
 
-    /** @brief True if bit 3 of STATUS_WORD low byte is on. */
-    bool vinUVFault = false;
+    /** @brief Incremented if bit 3 of STATUS_WORD low byte is on.
+     *
+     * Considered faulted if reaches DEGLITCH_LIMIT.
+     */
+    size_t vinUVFault = 0;
 
-    /** @brief True if bit 5 of STATUS_WORD low byte is on. */
-    bool voutOVFault = false;
+    /** @brief Incremented if bit 5 of STATUS_WORD low byte is on.
+     *
+     * Considered faulted if reaches DEGLITCH_LIMIT.
+     */
+    size_t voutOVFault = 0;
 
-    /** @brief True if bit 4 of STATUS_WORD low byte is on. */
-    bool ioutOCFault = false;
+    /** @brief Incremented if bit 4 of STATUS_WORD low byte is on.
+     *
+     * Considered faulted if reaches DEGLITCH_LIMIT.
+     */
+    size_t ioutOCFault = 0;
 
-    /** @brief True if bit 7 of STATUS_WORD high byte is on and bit 5 (VOUT_OV)
-     * of low byte is off. */
-    bool voutUVFault = false;
+    /** @brief Incremented if bit 7 of STATUS_WORD high byte is on and bit 5
+     * (VOUT_OV) of low byte is off.
+     *
+     * Considered faulted if reaches DEGLITCH_LIMIT.
+     */
+    size_t voutUVFault = 0;
 
-    /** @brief True if FANS fault/warn bit on in STATUS_WORD. */
-    bool fanFault = false;
+    /** @brief Incremented if FANS fault/warn bit on in STATUS_WORD.
+     *
+     * Considered faulted if reaches DEGLITCH_LIMIT.
+     */
+    size_t fanFault = 0;
 
-    /** @brief True if bit 2 of STATUS_WORD low byte is on. */
-    bool tempFault = false;
+    /** @brief Incremented if bit 2 of STATUS_WORD low byte is on.
+     *
+     * Considered faulted if reaches DEGLITCH_LIMIT. */
+    size_t tempFault = 0;
 
     /**
      * @brief Incremented if bit 11 or 6 of STATUS_WORD is on. PGOOD# is
@@ -477,18 +507,30 @@
 
     /**
      * @brief Power Supply Kill fault.
+     *
+     * Incremented based on bits in STATUS_MFR_SPECIFIC. IBM power supplies use
+     * bit 4 to indicate this fault. Considered faulted if it reaches
+     * DEGLITCH_LIMIT.
      */
-    bool psKillFault = false;
+    size_t psKillFault = 0;
 
     /**
      * @brief Power Supply 12Vcs fault (standby power).
+     *
+     * Incremented based on bits in STATUS_MFR_SPECIFIC. IBM power supplies use
+     * bit 6 to indicate this fault. Considered faulted if it reaches
+     * DEGLITCH_LIMIT.
      */
-    bool ps12VcsFault = false;
+    size_t ps12VcsFault = 0;
 
     /**
      * @brief Power Supply Current-Share fault in 12V domain.
+     *
+     * Incremented based on bits in STATUS_MFR_SPECIFIC. IBM power supplies use
+     * bit 7 to indicate this fault. Considered faulted if it reaches
+     * DEGLITCH_LIMIT.
      */
-    bool psCS12VFault = false;
+    size_t psCS12VFault = 0;
 
     /** @brief Count of the number of read failures. */
     size_t readFail = 0;
diff --git a/phosphor-power-supply/test/power_supply_tests.cpp b/phosphor-power-supply/test/power_supply_tests.cpp
index 1eec2a0..22c15e2 100644
--- a/phosphor-power-supply/test/power_supply_tests.cpp
+++ b/phosphor-power-supply/test/power_supply_tests.cpp
@@ -284,28 +284,36 @@
         // STATUS_INPUT fault bits ... on.
         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);
-        EXPECT_EQ(psu2.hasInputFault(), true);
-        EXPECT_EQ(psu2.hasMFRFault(), false);
-        EXPECT_EQ(psu2.hasVINUVFault(), false);
-        EXPECT_EQ(psu2.hasCommFault(), false);
-        EXPECT_EQ(psu2.hasVoutOVFault(), false);
-        EXPECT_EQ(psu2.hasIoutOCFault(), false);
-        EXPECT_EQ(psu2.hasVoutUVFault(), false);
-        EXPECT_EQ(psu2.hasFanFault(), false);
-        EXPECT_EQ(psu2.hasTempFault(), false);
-        EXPECT_EQ(psu2.hasPgoodFault(), false);
-        EXPECT_EQ(psu2.hasPSKillFault(), false);
-        EXPECT_EQ(psu2.hasPS12VcsFault(), false);
-        EXPECT_EQ(psu2.hasPSCS12VFault(), false);
+
+        for (auto x = 1; x <= DEGLITCH_LIMIT; x++)
+        {
+            setPMBusExpectations(mockPMBus, expectations);
+            EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+                .Times(1)
+                .WillOnce(Return("207000"));
+            psu2.analyze();
+            EXPECT_EQ(psu2.isPresent(), true);
+            // Should not be faulted until it reaches the deglitch limit.
+            EXPECT_EQ(psu2.isFaulted(), x >= DEGLITCH_LIMIT);
+            EXPECT_EQ(psu2.hasInputFault(), x >= DEGLITCH_LIMIT);
+            EXPECT_EQ(psu2.hasMFRFault(), false);
+            EXPECT_EQ(psu2.hasVINUVFault(), false);
+            EXPECT_EQ(psu2.hasCommFault(), false);
+            EXPECT_EQ(psu2.hasVoutOVFault(), false);
+            EXPECT_EQ(psu2.hasIoutOCFault(), false);
+            EXPECT_EQ(psu2.hasVoutUVFault(), false);
+            EXPECT_EQ(psu2.hasFanFault(), false);
+            EXPECT_EQ(psu2.hasTempFault(), false);
+            EXPECT_EQ(psu2.hasPgoodFault(), false);
+            EXPECT_EQ(psu2.hasPSKillFault(), false);
+            EXPECT_EQ(psu2.hasPS12VcsFault(), false);
+            EXPECT_EQ(psu2.hasPSCS12VFault(), false);
+        }
     }
 
+    EXPECT_CALL(mockPMBus, read(READ_VIN, _)).Times(1).WillOnce(Return(1));
+    psu2.clearFaults();
+
     // STATUS_WORD INPUT/UV fault.
     {
         // First need it to return good status, then the fault
@@ -315,33 +323,38 @@
             .Times(1)
             .WillOnce(Return("208000"));
         psu2.analyze();
+        EXPECT_EQ(psu2.isFaulted(), false);
+        EXPECT_EQ(psu2.hasInputFault(), false);
         // Now set fault bits in STATUS_WORD
         expectations.statusWordValue =
             (status_word::INPUT_FAULT_WARN | status_word::VIN_UV_FAULT);
         // 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);
-        EXPECT_EQ(psu2.hasInputFault(), true);
-        EXPECT_EQ(psu2.hasMFRFault(), false);
-        EXPECT_EQ(psu2.hasVINUVFault(), true);
-        EXPECT_EQ(psu2.hasCommFault(), false);
-        EXPECT_EQ(psu2.hasVoutOVFault(), false);
-        EXPECT_EQ(psu2.hasIoutOCFault(), false);
-        EXPECT_EQ(psu2.hasVoutUVFault(), false);
-        EXPECT_EQ(psu2.hasFanFault(), false);
-        EXPECT_EQ(psu2.hasTempFault(), false);
-        EXPECT_EQ(psu2.hasPgoodFault(), false);
-        EXPECT_EQ(psu2.hasPSKillFault(), false);
-        EXPECT_EQ(psu2.hasPS12VcsFault(), false);
-        EXPECT_EQ(psu2.hasPSCS12VFault(), false);
-
+        for (auto x = 1; x <= DEGLITCH_LIMIT; x++)
+        {
+            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);
+            // Only faulted if hit deglitch limit
+            EXPECT_EQ(psu2.isFaulted(), x >= DEGLITCH_LIMIT);
+            EXPECT_EQ(psu2.hasInputFault(), x >= DEGLITCH_LIMIT);
+            EXPECT_EQ(psu2.hasVINUVFault(), x >= DEGLITCH_LIMIT);
+            EXPECT_EQ(psu2.hasMFRFault(), false);
+            EXPECT_EQ(psu2.hasCommFault(), false);
+            EXPECT_EQ(psu2.hasVoutOVFault(), false);
+            EXPECT_EQ(psu2.hasIoutOCFault(), false);
+            EXPECT_EQ(psu2.hasVoutUVFault(), false);
+            EXPECT_EQ(psu2.hasFanFault(), false);
+            EXPECT_EQ(psu2.hasTempFault(), false);
+            EXPECT_EQ(psu2.hasPgoodFault(), false);
+            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;
@@ -361,6 +374,9 @@
         EXPECT_EQ(psu2.hasVINUVFault(), false);
     }
 
+    EXPECT_CALL(mockPMBus, read(READ_VIN, _)).Times(1).WillOnce(Return(1));
+    psu2.clearFaults();
+
     // STATUS_WORD MFR fault.
     {
         // First need it to return good status, then the fault
@@ -374,28 +390,34 @@
         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);
-        EXPECT_EQ(psu2.hasInputFault(), false);
-        EXPECT_EQ(psu2.hasMFRFault(), true);
-        EXPECT_EQ(psu2.hasVINUVFault(), false);
-        EXPECT_EQ(psu2.hasCommFault(), false);
-        EXPECT_EQ(psu2.hasVoutOVFault(), false);
-        EXPECT_EQ(psu2.hasIoutOCFault(), false);
-        EXPECT_EQ(psu2.hasVoutUVFault(), false);
-        EXPECT_EQ(psu2.hasFanFault(), false);
-        EXPECT_EQ(psu2.hasTempFault(), false);
-        EXPECT_EQ(psu2.hasPgoodFault(), false);
-        EXPECT_EQ(psu2.hasPSKillFault(), true);
-        EXPECT_EQ(psu2.hasPS12VcsFault(), true);
-        EXPECT_EQ(psu2.hasPSCS12VFault(), true);
+
+        for (auto x = 1; x <= DEGLITCH_LIMIT; x++)
+        {
+            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(), x >= DEGLITCH_LIMIT);
+            EXPECT_EQ(psu2.hasInputFault(), false);
+            EXPECT_EQ(psu2.hasMFRFault(), x >= DEGLITCH_LIMIT);
+            EXPECT_EQ(psu2.hasPSKillFault(), x >= DEGLITCH_LIMIT);
+            EXPECT_EQ(psu2.hasPS12VcsFault(), x >= DEGLITCH_LIMIT);
+            EXPECT_EQ(psu2.hasPSCS12VFault(), x >= DEGLITCH_LIMIT);
+            EXPECT_EQ(psu2.hasVINUVFault(), false);
+            EXPECT_EQ(psu2.hasCommFault(), false);
+            EXPECT_EQ(psu2.hasVoutOVFault(), false);
+            EXPECT_EQ(psu2.hasIoutOCFault(), false);
+            EXPECT_EQ(psu2.hasVoutUVFault(), false);
+            EXPECT_EQ(psu2.hasFanFault(), false);
+            EXPECT_EQ(psu2.hasTempFault(), false);
+            EXPECT_EQ(psu2.hasPgoodFault(), false);
+        }
     }
 
+    EXPECT_CALL(mockPMBus, read(READ_VIN, _)).Times(1).WillOnce(Return(1));
+    psu2.clearFaults();
     // Temperature fault.
     {
         // First STATUS_WORD with no bits set, then with temperature fault.
@@ -409,28 +431,33 @@
         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);
-        EXPECT_EQ(psu2.hasInputFault(), false);
-        EXPECT_EQ(psu2.hasMFRFault(), false);
-        EXPECT_EQ(psu2.hasVINUVFault(), false);
-        EXPECT_EQ(psu2.hasCommFault(), false);
-        EXPECT_EQ(psu2.hasVoutOVFault(), false);
-        EXPECT_EQ(psu2.hasIoutOCFault(), false);
-        EXPECT_EQ(psu2.hasVoutUVFault(), false);
-        EXPECT_EQ(psu2.hasFanFault(), false);
-        EXPECT_EQ(psu2.hasTempFault(), true);
-        EXPECT_EQ(psu2.hasPgoodFault(), false);
-        EXPECT_EQ(psu2.hasPSKillFault(), false);
-        EXPECT_EQ(psu2.hasPS12VcsFault(), false);
-        EXPECT_EQ(psu2.hasPSCS12VFault(), false);
+        for (auto x = 1; x <= DEGLITCH_LIMIT; x++)
+        {
+            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(), x >= DEGLITCH_LIMIT);
+            EXPECT_EQ(psu2.hasInputFault(), false);
+            EXPECT_EQ(psu2.hasMFRFault(), false);
+            EXPECT_EQ(psu2.hasVINUVFault(), false);
+            EXPECT_EQ(psu2.hasCommFault(), false);
+            EXPECT_EQ(psu2.hasVoutOVFault(), false);
+            EXPECT_EQ(psu2.hasIoutOCFault(), false);
+            EXPECT_EQ(psu2.hasVoutUVFault(), false);
+            EXPECT_EQ(psu2.hasFanFault(), false);
+            EXPECT_EQ(psu2.hasTempFault(), x >= DEGLITCH_LIMIT);
+            EXPECT_EQ(psu2.hasPgoodFault(), false);
+            EXPECT_EQ(psu2.hasPSKillFault(), false);
+            EXPECT_EQ(psu2.hasPS12VcsFault(), false);
+            EXPECT_EQ(psu2.hasPSCS12VFault(), false);
+        }
     }
 
+    EXPECT_CALL(mockPMBus, read(READ_VIN, _)).Times(1).WillOnce(Return(1));
+    psu2.clearFaults();
     // CML fault
     {
         // First STATUS_WORD wit no bits set, then with CML fault.
@@ -444,28 +471,33 @@
         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);
-        EXPECT_EQ(psu2.hasInputFault(), false);
-        EXPECT_EQ(psu2.hasMFRFault(), false);
-        EXPECT_EQ(psu2.hasVINUVFault(), false);
-        EXPECT_EQ(psu2.hasCommFault(), true);
-        EXPECT_EQ(psu2.hasVoutOVFault(), false);
-        EXPECT_EQ(psu2.hasIoutOCFault(), false);
-        EXPECT_EQ(psu2.hasVoutUVFault(), false);
-        EXPECT_EQ(psu2.hasFanFault(), false);
-        EXPECT_EQ(psu2.hasTempFault(), false);
-        EXPECT_EQ(psu2.hasPgoodFault(), false);
-        EXPECT_EQ(psu2.hasPSKillFault(), false);
-        EXPECT_EQ(psu2.hasPS12VcsFault(), false);
-        EXPECT_EQ(psu2.hasPSCS12VFault(), false);
+        for (auto x = 1; x <= DEGLITCH_LIMIT; x++)
+        {
+            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(), x >= DEGLITCH_LIMIT);
+            EXPECT_EQ(psu2.hasCommFault(), x >= DEGLITCH_LIMIT);
+            EXPECT_EQ(psu2.hasInputFault(), false);
+            EXPECT_EQ(psu2.hasMFRFault(), false);
+            EXPECT_EQ(psu2.hasVINUVFault(), false);
+            EXPECT_EQ(psu2.hasVoutOVFault(), false);
+            EXPECT_EQ(psu2.hasIoutOCFault(), false);
+            EXPECT_EQ(psu2.hasVoutUVFault(), false);
+            EXPECT_EQ(psu2.hasFanFault(), false);
+            EXPECT_EQ(psu2.hasTempFault(), false);
+            EXPECT_EQ(psu2.hasPgoodFault(), false);
+            EXPECT_EQ(psu2.hasPSKillFault(), false);
+            EXPECT_EQ(psu2.hasPS12VcsFault(), false);
+            EXPECT_EQ(psu2.hasPSCS12VFault(), false);
+        }
     }
 
+    EXPECT_CALL(mockPMBus, read(READ_VIN, _)).Times(1).WillOnce(Return(1));
+    psu2.clearFaults();
     // VOUT_OV_FAULT fault
     {
         // First STATUS_WORD with no bits set, then with VOUT/VOUT_OV fault.
@@ -480,27 +512,30 @@
             ((status_word::VOUT_FAULT) | (status_word::VOUT_OV_FAULT));
         // Turn on STATUS_VOUT fault bit(s)
         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);
-        EXPECT_EQ(psu2.hasInputFault(), false);
-        EXPECT_EQ(psu2.hasMFRFault(), false);
-        EXPECT_EQ(psu2.hasVINUVFault(), false);
-        EXPECT_EQ(psu2.hasCommFault(), false);
-        EXPECT_EQ(psu2.hasVoutOVFault(), true);
-        EXPECT_EQ(psu2.hasVoutUVFault(), false);
-        EXPECT_EQ(psu2.hasIoutOCFault(), false);
-        EXPECT_EQ(psu2.hasFanFault(), false);
-        EXPECT_EQ(psu2.hasTempFault(), false);
-        EXPECT_EQ(psu2.hasPgoodFault(), false);
-        EXPECT_EQ(psu2.hasPSKillFault(), false);
-        EXPECT_EQ(psu2.hasPS12VcsFault(), false);
-        EXPECT_EQ(psu2.hasPSCS12VFault(), false);
+        for (auto x = 1; x <= DEGLITCH_LIMIT; x++)
+        {
+            // 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(), x >= DEGLITCH_LIMIT);
+            EXPECT_EQ(psu2.hasInputFault(), false);
+            EXPECT_EQ(psu2.hasMFRFault(), false);
+            EXPECT_EQ(psu2.hasVINUVFault(), false);
+            EXPECT_EQ(psu2.hasCommFault(), false);
+            EXPECT_EQ(psu2.hasVoutOVFault(), x >= DEGLITCH_LIMIT);
+            EXPECT_EQ(psu2.hasVoutUVFault(), false);
+            EXPECT_EQ(psu2.hasIoutOCFault(), false);
+            EXPECT_EQ(psu2.hasFanFault(), false);
+            EXPECT_EQ(psu2.hasTempFault(), false);
+            EXPECT_EQ(psu2.hasPgoodFault(), false);
+            EXPECT_EQ(psu2.hasPSKillFault(), false);
+            EXPECT_EQ(psu2.hasPS12VcsFault(), false);
+            EXPECT_EQ(psu2.hasPSCS12VFault(), false);
+        }
     }
 
     // IOUT_OC_FAULT fault
@@ -516,26 +551,29 @@
         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);
-        EXPECT_EQ(psu2.hasInputFault(), false);
-        EXPECT_EQ(psu2.hasMFRFault(), false);
-        EXPECT_EQ(psu2.hasVINUVFault(), false);
-        EXPECT_EQ(psu2.hasCommFault(), false);
-        EXPECT_EQ(psu2.hasVoutOVFault(), false);
-        EXPECT_EQ(psu2.hasIoutOCFault(), true);
-        EXPECT_EQ(psu2.hasVoutUVFault(), false);
-        EXPECT_EQ(psu2.hasFanFault(), false);
-        EXPECT_EQ(psu2.hasTempFault(), false);
-        EXPECT_EQ(psu2.hasPgoodFault(), false);
-        EXPECT_EQ(psu2.hasPSKillFault(), false);
-        EXPECT_EQ(psu2.hasPS12VcsFault(), false);
-        EXPECT_EQ(psu2.hasPSCS12VFault(), false);
+        for (auto x = 1; x <= DEGLITCH_LIMIT; x++)
+        {
+            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(), x >= DEGLITCH_LIMIT);
+            EXPECT_EQ(psu2.hasInputFault(), false);
+            EXPECT_EQ(psu2.hasMFRFault(), false);
+            EXPECT_EQ(psu2.hasVINUVFault(), false);
+            EXPECT_EQ(psu2.hasCommFault(), false);
+            EXPECT_EQ(psu2.hasVoutOVFault(), false);
+            EXPECT_EQ(psu2.hasIoutOCFault(), x >= DEGLITCH_LIMIT);
+            EXPECT_EQ(psu2.hasVoutUVFault(), false);
+            EXPECT_EQ(psu2.hasFanFault(), false);
+            EXPECT_EQ(psu2.hasTempFault(), false);
+            EXPECT_EQ(psu2.hasPgoodFault(), false);
+            EXPECT_EQ(psu2.hasPSKillFault(), false);
+            EXPECT_EQ(psu2.hasPS12VcsFault(), false);
+            EXPECT_EQ(psu2.hasPSCS12VFault(), false);
+        }
     }
 
     // VOUT_UV_FAULT
@@ -551,26 +589,29 @@
         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);
-        EXPECT_EQ(psu2.hasInputFault(), false);
-        EXPECT_EQ(psu2.hasMFRFault(), false);
-        EXPECT_EQ(psu2.hasVINUVFault(), false);
-        EXPECT_EQ(psu2.hasCommFault(), false);
-        EXPECT_EQ(psu2.hasVoutOVFault(), false);
-        EXPECT_EQ(psu2.hasIoutOCFault(), false);
-        EXPECT_EQ(psu2.hasVoutUVFault(), true);
-        EXPECT_EQ(psu2.hasFanFault(), false);
-        EXPECT_EQ(psu2.hasTempFault(), false);
-        EXPECT_EQ(psu2.hasPgoodFault(), false);
-        EXPECT_EQ(psu2.hasPSKillFault(), false);
-        EXPECT_EQ(psu2.hasPS12VcsFault(), false);
-        EXPECT_EQ(psu2.hasPSCS12VFault(), false);
+        for (auto x = 1; x <= DEGLITCH_LIMIT; x++)
+        {
+            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(), x >= DEGLITCH_LIMIT);
+            EXPECT_EQ(psu2.hasInputFault(), false);
+            EXPECT_EQ(psu2.hasMFRFault(), false);
+            EXPECT_EQ(psu2.hasVINUVFault(), false);
+            EXPECT_EQ(psu2.hasCommFault(), false);
+            EXPECT_EQ(psu2.hasVoutOVFault(), false);
+            EXPECT_EQ(psu2.hasIoutOCFault(), false);
+            EXPECT_EQ(psu2.hasVoutUVFault(), x >= DEGLITCH_LIMIT);
+            EXPECT_EQ(psu2.hasFanFault(), false);
+            EXPECT_EQ(psu2.hasTempFault(), false);
+            EXPECT_EQ(psu2.hasPgoodFault(), false);
+            EXPECT_EQ(psu2.hasPSKillFault(), false);
+            EXPECT_EQ(psu2.hasPS12VcsFault(), false);
+            EXPECT_EQ(psu2.hasPSCS12VFault(), false);
+        }
     }
 
     // Fan fault
@@ -585,26 +626,30 @@
         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);
-        EXPECT_EQ(psu2.hasInputFault(), false);
-        EXPECT_EQ(psu2.hasMFRFault(), false);
-        EXPECT_EQ(psu2.hasVINUVFault(), false);
-        EXPECT_EQ(psu2.hasCommFault(), false);
-        EXPECT_EQ(psu2.hasVoutOVFault(), false);
-        EXPECT_EQ(psu2.hasIoutOCFault(), false);
-        EXPECT_EQ(psu2.hasVoutUVFault(), false);
-        EXPECT_EQ(psu2.hasFanFault(), true);
-        EXPECT_EQ(psu2.hasTempFault(), false);
-        EXPECT_EQ(psu2.hasPgoodFault(), false);
-        EXPECT_EQ(psu2.hasPSKillFault(), false);
-        EXPECT_EQ(psu2.hasPS12VcsFault(), false);
-        EXPECT_EQ(psu2.hasPSCS12VFault(), false);
+
+        for (auto x = 1; x <= DEGLITCH_LIMIT; x++)
+        {
+            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(), x >= DEGLITCH_LIMIT);
+            EXPECT_EQ(psu2.hasFanFault(), x >= DEGLITCH_LIMIT);
+            EXPECT_EQ(psu2.hasInputFault(), false);
+            EXPECT_EQ(psu2.hasMFRFault(), false);
+            EXPECT_EQ(psu2.hasVINUVFault(), false);
+            EXPECT_EQ(psu2.hasCommFault(), false);
+            EXPECT_EQ(psu2.hasVoutOVFault(), false);
+            EXPECT_EQ(psu2.hasIoutOCFault(), false);
+            EXPECT_EQ(psu2.hasVoutUVFault(), false);
+            EXPECT_EQ(psu2.hasTempFault(), false);
+            EXPECT_EQ(psu2.hasPgoodFault(), false);
+            EXPECT_EQ(psu2.hasPSKillFault(), false);
+            EXPECT_EQ(psu2.hasPS12VcsFault(), false);
+            EXPECT_EQ(psu2.hasPSCS12VFault(), false);
+        }
     }
 
     // PGOOD/OFF fault. Deglitched, needs to reach DEGLITCH_LIMIT.
@@ -630,14 +675,7 @@
                 .WillOnce(Return("124000"));
             psu2.analyze();
             EXPECT_EQ(psu2.isPresent(), true);
-            if (x < DEGLITCH_LIMIT)
-            {
-                EXPECT_EQ(psu2.isFaulted(), false);
-            }
-            else
-            {
-                EXPECT_EQ(psu2.isFaulted(), true);
-            }
+            EXPECT_EQ(psu2.isFaulted(), x >= DEGLITCH_LIMIT);
             EXPECT_EQ(psu2.hasInputFault(), false);
             EXPECT_EQ(psu2.hasMFRFault(), false);
             EXPECT_EQ(psu2.hasVINUVFault(), false);
@@ -764,44 +802,35 @@
     expectations.statusFans12Value = 0xFF;
     // 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);
-    EXPECT_EQ(psu.hasInputFault(), true);
-    EXPECT_EQ(psu.hasMFRFault(), true);
-    EXPECT_EQ(psu.hasVINUVFault(), true);
-    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);
-    // 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);
-    // This is the CLEAR_FAULTS read that does not check the return value.
-    EXPECT_CALL(mockPMBus, read(READ_VIN, _)).Times(1).WillOnce(Return(3));
+
+    for (auto x = 1; x <= DEGLITCH_LIMIT; x++)
+    {
+        setPMBusExpectations(mockPMBus, expectations);
+        EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+            .Times(1)
+            .WillOnce(Return("0"));
+        psu.analyze();
+        EXPECT_EQ(psu.isPresent(), true);
+        // Cannot have VOUT_OV_FAULT and VOUT_UV_FAULT.
+        // Rely on HasVoutUVFault() to verify this sets and clears.
+        EXPECT_EQ(psu.hasVoutUVFault(), false);
+        // All faults are deglitched up to DEGLITCH_LIMIT
+        EXPECT_EQ(psu.isFaulted(), x >= DEGLITCH_LIMIT);
+        EXPECT_EQ(psu.hasInputFault(), x >= DEGLITCH_LIMIT);
+        EXPECT_EQ(psu.hasMFRFault(), x >= DEGLITCH_LIMIT);
+        EXPECT_EQ(psu.hasVINUVFault(), x >= DEGLITCH_LIMIT);
+        EXPECT_EQ(psu.hasCommFault(), x >= DEGLITCH_LIMIT);
+        EXPECT_EQ(psu.hasVoutOVFault(), x >= DEGLITCH_LIMIT);
+        EXPECT_EQ(psu.hasIoutOCFault(), x >= DEGLITCH_LIMIT);
+        EXPECT_EQ(psu.hasFanFault(), x >= DEGLITCH_LIMIT);
+        EXPECT_EQ(psu.hasTempFault(), x >= DEGLITCH_LIMIT);
+        EXPECT_EQ(psu.hasPgoodFault(), x >= DEGLITCH_LIMIT);
+        EXPECT_EQ(psu.hasPSKillFault(), x >= DEGLITCH_LIMIT);
+        EXPECT_EQ(psu.hasPS12VcsFault(), x >= DEGLITCH_LIMIT);
+        EXPECT_EQ(psu.hasPSCS12VFault(), x >= DEGLITCH_LIMIT);
+    }
+
+    EXPECT_CALL(mockPMBus, read(READ_VIN, _)).Times(1).WillOnce(Return(207000));
     psu.clearFaults();
     EXPECT_EQ(psu.isPresent(), true);
     EXPECT_EQ(psu.isFaulted(), false);
@@ -836,12 +865,17 @@
     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();
+
+    // All faults degltiched now. Check for false before limit above.
+    for (auto x = 1; x <= DEGLITCH_LIMIT; x++)
+    {
+        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);
     EXPECT_EQ(psu.hasInputFault(), true);
@@ -856,8 +890,7 @@
     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.hasPgoodFault(), true);
     EXPECT_EQ(psu.hasPSKillFault(), true);
     EXPECT_EQ(psu.hasPS12VcsFault(), true);
     EXPECT_EQ(psu.hasPSCS12VFault(), true);
@@ -871,6 +904,7 @@
     EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
         .Times(1)
         .WillOnce(Return("206000"));
+    EXPECT_CALL(mockPMBus, read(READ_VIN, _)).Times(1).WillOnce(Return(0));
     psu.analyze();
     EXPECT_EQ(psu.isPresent(), true);
     EXPECT_EQ(psu.isFaulted(), false);
@@ -1011,13 +1045,16 @@
     expectations.statusFans12Value = 0xFF;
     // 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);
+    for (auto x = 1; x <= DEGLITCH_LIMIT; x++)
+    {
+        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(), x >= DEGLITCH_LIMIT);
+    }
 }
 
 TEST_F(PowerSupplyTests, HasInputFault)
@@ -1044,13 +1081,16 @@
     expectations.statusWordValue = (status_word::INPUT_FAULT_WARN);
     // 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);
+    for (auto x = 1; x <= DEGLITCH_LIMIT; x++)
+    {
+        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(), x >= DEGLITCH_LIMIT);
+    }
     // STATUS_WORD with no bits on.
     expectations.statusWordValue = 0;
     setPMBusExpectations(mockPMBus, expectations);
@@ -1087,12 +1127,15 @@
     expectations.statusWordValue = (status_word::MFR_SPECIFIC_FAULT);
     // 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);
+    for (auto x = 1; x <= DEGLITCH_LIMIT; x++)
+    {
+        setPMBusExpectations(mockPMBus, expectations);
+        EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+            .Times(1)
+            .WillOnce(Return("202200"));
+        psu.analyze();
+        EXPECT_EQ(psu.hasMFRFault(), x >= DEGLITCH_LIMIT);
+    }
     // Back to no bits on in STATUS_WORD
     expectations.statusWordValue = 0;
     setPMBusExpectations(mockPMBus, expectations);
@@ -1136,13 +1179,16 @@
     // Curious disagreement between PMBus Spec. Part II Figure 16 and 33. Go by
     // 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);
+    for (auto x = 1; x <= DEGLITCH_LIMIT; x++)
+    {
+        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(), x >= DEGLITCH_LIMIT);
+    }
     // Back to no fault bits on in STATUS_WORD
     expectations.statusWordValue = 0;
     setPMBusExpectations(mockPMBus, expectations);
@@ -1182,13 +1228,15 @@
     expectations.statusWordValue = (status_word::VOUT_OV_FAULT);
     // STATUS_VOUT fault bit(s)
     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);
+    for (auto x = 1; x <= DEGLITCH_LIMIT; x++)
+    {
+        setPMBusExpectations(mockPMBus, expectations);
+        EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+            .Times(1)
+            .WillOnce(Return("202200"));
+        psu.analyze();
+        EXPECT_EQ(psu.hasVoutOVFault(), x >= DEGLITCH_LIMIT);
+    }
     // Back to no fault bits on in STATUS_WORD
     expectations.statusWordValue = 0;
     setPMBusExpectations(mockPMBus, expectations);
@@ -1224,12 +1272,15 @@
     expectations.statusWordValue = status_word::IOUT_OC_FAULT;
     // 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);
+    for (auto x = 1; x <= DEGLITCH_LIMIT; x++)
+    {
+        setPMBusExpectations(mockPMBus, expectations);
+        EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+            .Times(1)
+            .WillOnce(Return("203200"));
+        psu.analyze();
+        EXPECT_EQ(psu.hasIoutOCFault(), x >= DEGLITCH_LIMIT);
+    }
     // Back to no fault bits on in STATUS_WORD
     expectations.statusWordValue = 0;
     setPMBusExpectations(mockPMBus, expectations);
@@ -1265,12 +1316,15 @@
     expectations.statusWordValue = (status_word::VOUT_FAULT);
     // 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);
+    for (auto x = 1; x <= DEGLITCH_LIMIT; x++)
+    {
+        setPMBusExpectations(mockPMBus, expectations);
+        EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+            .Times(1)
+            .WillOnce(Return("204200"));
+        psu.analyze();
+        EXPECT_EQ(psu.hasVoutUVFault(), x >= DEGLITCH_LIMIT);
+    }
     // Back to no fault bits on in STATUS_WORD
     expectations.statusWordValue = 0;
     setPMBusExpectations(mockPMBus, expectations);
@@ -1306,13 +1360,16 @@
     expectations.statusWordValue = (status_word::FAN_FAULT);
     // 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);
+    for (auto x = 1; x <= DEGLITCH_LIMIT; x++)
+    {
+        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(), x >= DEGLITCH_LIMIT);
+    }
     // Back to no fault bits on in STATUS_WORD
     expectations.statusWordValue = 0;
     setPMBusExpectations(mockPMBus, expectations);
@@ -1349,13 +1406,16 @@
     expectations.statusWordValue = (status_word::TEMPERATURE_FAULT_WARN);
     // 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);
+    for (auto x = 1; x <= DEGLITCH_LIMIT; x++)
+    {
+        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(), x >= DEGLITCH_LIMIT);
+    }
     // Back to no fault bits on in STATUS_WORD
     expectations.statusWordValue = 0;
     setPMBusExpectations(mockPMBus, expectations);
@@ -1494,13 +1554,19 @@
     expectations.statusWordValue = (status_word::MFR_SPECIFIC_FAULT);
     // 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);
+
+    // Deglitching faults, false until read the fault bits on up to the limit.
+    for (auto x = 1; x <= DEGLITCH_LIMIT; x++)
+    {
+        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(), x >= DEGLITCH_LIMIT);
+    }
+
     // Back to no bits on in STATUS_WORD
     expectations.statusWordValue = 0;
     setPMBusExpectations(mockPMBus, expectations);
@@ -1514,13 +1580,18 @@
     expectations.statusWordValue = (status_word::MFR_SPECIFIC_FAULT);
     // 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);
+
+    for (auto x = 1; x <= DEGLITCH_LIMIT; x++)
+    {
+        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(), x >= DEGLITCH_LIMIT);
+    }
+
     // Back to no bits on in STATUS_WORD
     expectations.statusWordValue = 0;
     setPMBusExpectations(mockPMBus, expectations);
@@ -1555,12 +1626,17 @@
     expectations.statusWordValue = (status_word::MFR_SPECIFIC_FAULT);
     // 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);
+
+    for (auto x = 1; x <= DEGLITCH_LIMIT; x++)
+    {
+        setPMBusExpectations(mockPMBus, expectations);
+        EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+            .Times(1)
+            .WillOnce(Return("209200"));
+        psu.analyze();
+        EXPECT_EQ(psu.hasPS12VcsFault(), x >= DEGLITCH_LIMIT);
+    }
+
     // Back to no bits on in STATUS_WORD
     expectations.statusWordValue = 0;
     setPMBusExpectations(mockPMBus, expectations);
@@ -1573,12 +1649,17 @@
     expectations.statusWordValue = (status_word::MFR_SPECIFIC_FAULT);
     // 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);
+
+    for (auto x = 1; x <= DEGLITCH_LIMIT; x++)
+    {
+        setPMBusExpectations(mockPMBus, expectations);
+        EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+            .Times(1)
+            .WillOnce(Return("209400"));
+        psu.analyze();
+        EXPECT_EQ(psu.hasPS12VcsFault(), x >= DEGLITCH_LIMIT);
+    }
+
     // Back to no bits on in STATUS_WORD
     expectations.statusWordValue = 0;
     setPMBusExpectations(mockPMBus, expectations);
@@ -1611,12 +1692,17 @@
     expectations.statusWordValue = (status_word::MFR_SPECIFIC_FAULT);
     // 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);
+
+    for (auto x = 1; x <= DEGLITCH_LIMIT; x++)
+    {
+        setPMBusExpectations(mockPMBus, expectations);
+        EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+            .Times(1)
+            .WillOnce(Return("209200"));
+        psu.analyze();
+        EXPECT_EQ(psu.hasPSCS12VFault(), x >= DEGLITCH_LIMIT);
+    }
+
     // Back to no bits on in STATUS_WORD
     expectations.statusWordValue = 0;
     setPMBusExpectations(mockPMBus, expectations);
@@ -1629,12 +1715,17 @@
     expectations.statusWordValue = (status_word::MFR_SPECIFIC_FAULT);
     // 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);
+
+    for (auto x = 1; x <= DEGLITCH_LIMIT; x++)
+    {
+        setPMBusExpectations(mockPMBus, expectations);
+        EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+            .Times(1)
+            .WillOnce(Return("209400"));
+        psu.analyze();
+        EXPECT_EQ(psu.hasPSCS12VFault(), x >= DEGLITCH_LIMIT);
+    }
+
     // Back to no bits on in STATUS_WORD
     expectations.statusWordValue = 0;
     setPMBusExpectations(mockPMBus, expectations);