diff --git a/include/etl/debounce_multi_bit.h b/include/etl/debounce_multi_bit.h index 8655f922..0b5f81d2 100644 --- a/include/etl/debounce_multi_bit.h +++ b/include/etl/debounce_multi_bit.h @@ -100,7 +100,21 @@ namespace etl typedef TValue value_type; typedef TCount count_type; - typedef uint_least8_t state_type; + typedef uint_least8_t state_id_type; + + //*************************************************************************** + /// State fit in 2 bits, state_lo & state_hi. + //*************************************************************************** + struct state_id + { + enum + { + Off = 0, // Debounced state is Off. + On = 1, // Debounced state is On. + Held = 2, // Debounced state is Held. Implies On. + Repeating = 3 // Debounced state is Repeating. Implies Held and On. + }; + }; //*************************************************************************** /// Constructor. All bits start in the 'clear' state. @@ -210,10 +224,10 @@ namespace etl //*************************************************************************** bool is_set(size_t n) const { - const value_type bit = bit_mask(n); - const state_type state = get_bit_state(bit); + const value_type bit = bit_mask(n); + const state_id_type state = get_bit_state(bit); - return (state == On) || (state == Held) || (state == Repeating); + return (state >= state_id::On); } //*************************************************************************** @@ -222,10 +236,10 @@ namespace etl //*************************************************************************** bool is_held(size_t n) const { - const value_type bit = bit_mask(n); - const state_type state = get_bit_state(bit); + const value_type bit = bit_mask(n); + const state_id_type state = get_bit_state(bit); - return (state == Held) || (state == Repeating); + return (state >= state_id::Held); } //*************************************************************************** @@ -234,10 +248,10 @@ namespace etl //*************************************************************************** bool is_repeating(size_t n) const { - const value_type bit = bit_mask(n); - const state_type state = get_bit_state(bit); + const value_type bit = bit_mask(n); + const state_id_type state = get_bit_state(bit); - return (state == Repeating); + return (state == state_id::Repeating); } //*************************************************************************** @@ -249,7 +263,7 @@ namespace etl } //*************************************************************************** - /// Returns the current state. + /// Returns the current state of all bits as a value_type. //*************************************************************************** value_type get_state() const { @@ -258,24 +272,24 @@ namespace etl for (size_t i = 0; i < Width; ++i) { - result |= (get_bit_state(bit) >= On) ? bit : 0; + result |= (get_bit_state(bit) >= state_id::On) ? bit : 0; + bit <<= 1; } return result; } - private: - //*************************************************************************** - /// State fit in 2 bits, state_lo & state_hi. + /// Returns the current state id of a bit. //*************************************************************************** - enum state_id + state_id_type get_state(size_t n) const { - Off = 0, // Debounced state is Off. - On = 1, // Debounced state is On. - Held = 2, // Debounced state is Held. Implies On. - Repeating = 3 // Debounced state is Repeating. Implies Held and On. - }; + value_type bit = bit_mask(n); + + return get_bit_state(bit); + } + + private: //*************************************************************************** /// Updates a bit. @@ -292,25 +306,25 @@ namespace etl switch (get_bit_state(bit)) { - case Off: + case state_id::Off: { handle_off(pcount, bit, bit_is_set); break; } - case On: + case state_id::On: { handle_on(pcount, bit, bit_is_set); break; } - case Held: + case state_id::Held: { handle_held(pcount, bit, bit_is_set); break; } - case Repeating: + case state_id::Repeating: { handle_repeating(pcount, bit, bit_is_set); break; @@ -322,19 +336,19 @@ namespace etl /// Gets the current debounce state for a specific bit. ///\return The current state of the bit. //*************************************************************************** - state_type get_bit_state(const value_type bit) const + state_id_type get_bit_state(const value_type bit) const { - const state_type lo = static_cast((state_lo & bit) > 0); - const state_type hi = static_cast((state_hi & bit) > 0); + const state_id_type lo = static_cast((state_lo & bit) > 0); + const state_id_type hi = static_cast((state_hi & bit) > 0); - return static_cast(lo | (hi << 1)); + return static_cast(lo | (hi << 1)); } //*************************************************************************** /// Gets the current debounce state for a specific bit. ///\return The current state of the bit. //*************************************************************************** - void set_bit_state(state_type state, const value_type bit) + void set_bit_state(state_id_type state, const value_type bit) { state_lo = state & 1 ? state_lo | bit : state_lo & ~bit; state_hi = state & 2 ? state_hi | bit : state_hi & ~bit; @@ -344,7 +358,7 @@ namespace etl /// Increments *pcount; if it reaches 'threshold' the bit moves to /// 'new_state', the changed flag is set, and the timer is reset. //*************************************************************************** - void try_transition(count_type* pcount, uint32_t threshold, state_type new_state, value_type bit) + void check_for_transition(count_type* pcount, uint32_t threshold, state_id_type new_state, value_type bit) { ++(*pcount); @@ -363,7 +377,7 @@ namespace etl { if (bit_is_set) { - try_transition(pcount, Valid_Count, On, bit); + check_for_transition(pcount, Valid_Count, state_id::On, bit); } } @@ -376,12 +390,12 @@ namespace etl { if ETL_IF_CONSTEXPR (Hold_Count > 0) { - try_transition(pcount, Hold_Count, Held, bit); + check_for_transition(pcount, Hold_Count, state_id::Held, bit); } } else { - try_transition(pcount, Valid_Count, Off, bit); + check_for_transition(pcount, Valid_Count, state_id::Off, bit); } } @@ -394,12 +408,12 @@ namespace etl { if ETL_IF_CONSTEXPR (Repeat_Count > 0) { - try_transition(pcount, Repeat_Count, Repeating, bit); + check_for_transition(pcount, Repeat_Count, state_id::Repeating, bit); } } else { - try_transition(pcount, Valid_Count, Off, bit); + check_for_transition(pcount, Valid_Count, state_id::Off, bit); } } @@ -410,11 +424,11 @@ namespace etl { if (bit_is_set) { - try_transition(pcount, Repeat_Count, Repeating, bit); + check_for_transition(pcount, Repeat_Count, state_id::Repeating, bit); } else { - try_transition(pcount, Valid_Count, Off, bit); + check_for_transition(pcount, Valid_Count, state_id::Off, bit); } } @@ -426,7 +440,7 @@ namespace etl return static_cast(value_type(1) << n); } - value_type sample; // The last known state of the bits. + value_type sample; // The last known value of the bits. Note, this is not the same as the 'state' of the bits. value_type state_lo; // Low bits of the state. value_type state_hi; // High bits of the state. Combined with state_lo to form a 2-bit state for each bit in the field. value_type changed; // Bits that have changed at the last update. diff --git a/test/test_debounce_multi_bit.cpp b/test/test_debounce_multi_bit.cpp index 62019424..43944661 100644 --- a/test/test_debounce_multi_bit.cpp +++ b/test/test_debounce_multi_bit.cpp @@ -30,6 +30,7 @@ SOFTWARE. #include "etl/debounce_multi_bit.h" +#include #include namespace @@ -47,14 +48,28 @@ namespace const value_type Bit1 = 1; const value_type Bit2 = 2; - using debounce_valid = etl::debounce_multi_bit; - using debounce_valid_hold = etl::debounce_multi_bit; - using debounce_valid_hold_repeat = etl::debounce_multi_bit; + const size_t NBits = 3; + + using debounce_valid = etl::debounce_multi_bit; + using debounce_valid_hold = etl::debounce_multi_bit; + using debounce_valid_hold_repeat = etl::debounce_multi_bit; SUITE(test_debounce_multi_bit) { //************************************************************************* - TEST(test_debounce_no_hold_or_repeat) + TEST(test_debounce_status) + { + debounce_valid_hold_repeat value; + + CHECK_EQUAL(NBits, value.get_width()); + CHECK_EQUAL(0, value.get_state()); + CHECK_EQUAL(debounce_valid_hold_repeat::state_id::Off, value.get_state(0)); + CHECK_EQUAL(debounce_valid_hold_repeat::state_id::Off, value.get_state(1)); + CHECK_EQUAL(debounce_valid_hold_repeat::state_id::Off, value.get_state(2)); + } + + //************************************************************************* + TEST(test_debounce_valid) { debounce_valid value(Initial_Value); @@ -99,7 +114,7 @@ namespace } //************************************************************************* - TEST(test_debounce_no_hold_or_repeat_incremental) + TEST(test_debounce_valid_incremental) { debounce_valid value(Initial_Value); @@ -115,10 +130,6 @@ namespace for (size_t j = 0; j < value.get_width() - 1; ++j) { CHECK_FALSE(value.update_incremental(1)); - CHECK_FALSE(value.has_changed(Bit0)); - CHECK_FALSE(value.is_set(Bit0)); - CHECK_FALSE(value.is_held(Bit0)); - CHECK_FALSE(value.is_repeating(Bit0)); } CHECK_TRUE(value.update_incremental(1)); @@ -135,10 +146,6 @@ namespace for (size_t j = 0; j < value.get_width() - 1; ++j) { CHECK_FALSE(value.update_incremental(1)); - CHECK_FALSE(value.has_changed(Bit0)); - CHECK_FALSE(value.is_set(Bit0)); - CHECK_FALSE(value.is_held(Bit0)); - CHECK_FALSE(value.is_repeating(Bit0)); } CHECK_TRUE(value.update_incremental(1)); @@ -164,5 +171,663 @@ namespace CHECK_FALSE(value.is_repeating(Bit0)); } } + + //************************************************************************* + TEST(test_debounce_valid_hold) + { + debounce_valid_hold value(Initial_Value); + + CHECK_FALSE(value.has_changed(Bit0)); + CHECK_FALSE(value.is_set(Bit0)); + CHECK_FALSE(value.is_held(Bit0)); + CHECK_FALSE(value.is_repeating(Bit0)); + CHECK_EQUAL(0, value.get_state()); + + //******************************* + // Transition from Off to On. + for (size_t i = 0; i < Valid_Count - 1; ++i) + { + CHECK_FALSE(value.update(1)); + CHECK_FALSE(value.has_changed(Bit0)); + CHECK_FALSE(value.is_set(Bit0)); + CHECK_FALSE(value.is_held(Bit0)); + CHECK_FALSE(value.is_repeating(Bit0)); + } + + CHECK_EQUAL(0, value.get_state()); + + // Changed. + CHECK_TRUE(value.update(1)); + CHECK_TRUE(value.has_changed(Bit0)); + CHECK_TRUE(value.is_set(Bit0)); + CHECK_FALSE(value.is_held(Bit0)); + CHECK_FALSE(value.is_repeating(Bit0)); + + CHECK_EQUAL(1, value.get_state()); + + //******************************* + // Transition from On to Held. + for (size_t i = 0; i < Hold_Count - 1; ++i) + { + CHECK_FALSE(value.update(1)); + CHECK_FALSE(value.has_changed(Bit0)); + CHECK_TRUE(value.is_set(Bit0)); + CHECK_FALSE(value.is_held(Bit0)); + CHECK_FALSE(value.is_repeating(Bit0)); + } + + // Changed. + CHECK_TRUE(value.update(1)); + CHECK_TRUE(value.has_changed(Bit0)); + CHECK_TRUE(value.is_set(Bit0)); + CHECK_TRUE(value.is_held(Bit0)); + CHECK_FALSE(value.is_repeating(Bit0)); + + //******************************* + // Ensure no more transitions. + for (size_t i = 0; i < Valid_Count + Hold_Count; ++i) + { + CHECK_FALSE(value.update(1)); + CHECK_FALSE(value.has_changed(Bit0)); + CHECK_TRUE(value.is_set(Bit0)); + CHECK_TRUE(value.is_held(Bit0)); + CHECK_FALSE(value.is_repeating(Bit0)); + } + } + + //************************************************************************* + TEST(test_debounce_valid_hold_incremental) + { + debounce_valid_hold value(Initial_Value); + + CHECK_FALSE(value.has_changed(Bit0)); + CHECK_FALSE(value.is_set(Bit0)); + CHECK_FALSE(value.is_held(Bit0)); + CHECK_FALSE(value.is_repeating(Bit0)); + + //******************************* + // Transition from Off to On. + for (size_t i = 0; i < Valid_Count - 1; ++i) + { + for (size_t j = 0; j < value.get_width() - 1; ++j) + { + CHECK_FALSE(value.update_incremental(1)); + } + + CHECK_TRUE(value.update_incremental(1)); + CHECK_FALSE(value.has_changed(Bit0)); + CHECK_FALSE(value.is_set(Bit0)); + CHECK_FALSE(value.is_held(Bit0)); + CHECK_FALSE(value.is_repeating(Bit0)); + } + + // Final incremental update. + // Changed. + for (size_t j = 0; j < value.get_width() - 1; ++j) + { + CHECK_FALSE(value.update_incremental(1)); + } + + CHECK_TRUE(value.update_incremental(1)); + CHECK_TRUE(value.has_changed(Bit0)); + CHECK_TRUE(value.is_set(Bit0)); + CHECK_FALSE(value.is_held(Bit0)); + CHECK_FALSE(value.is_repeating(Bit0)); + + //******************************* + // Transition from On to Held. + for (size_t i = 0; i < Hold_Count - 1; ++i) + { + for (size_t j = 0; j < value.get_width() - 1; ++j) + { + CHECK_FALSE(value.update_incremental(1)); + } + + CHECK_TRUE(value.update_incremental(1)); + CHECK_FALSE(value.has_changed(Bit0)); + CHECK_TRUE(value.is_set(Bit0)); + CHECK_FALSE(value.is_held(Bit0)); + CHECK_FALSE(value.is_repeating(Bit0)); + } + + // Final incremental update. + // Changed. + for (size_t j = 0; j < value.get_width() - 1; ++j) + { + CHECK_FALSE(value.update_incremental(1)); + } + + CHECK_TRUE(value.update_incremental(1)); + CHECK_TRUE(value.has_changed(Bit0)); + CHECK_TRUE(value.is_set(Bit0)); + CHECK_TRUE(value.is_held(Bit0)); + CHECK_FALSE(value.is_repeating(Bit0)); + + //******************************* + // Ensure no more transitions. + for (size_t i = 0; i < Valid_Count + Hold_Count; ++i) + { + for (size_t j = 0; j < value.get_width(); ++j) + { + value.update_incremental(1); + } + + CHECK_FALSE(value.has_changed(Bit0)); + CHECK_TRUE(value.is_set(Bit0)); + CHECK_TRUE(value.is_held(Bit0)); + CHECK_FALSE(value.is_repeating(Bit0)); + } + } + + //************************************************************************* + TEST(test_debounce_valid_hold_repeat) + { + debounce_valid_hold_repeat value(Initial_Value); + + CHECK_FALSE(value.has_changed(Bit0)); + CHECK_FALSE(value.is_set(Bit0)); + CHECK_FALSE(value.is_held(Bit0)); + CHECK_FALSE(value.is_repeating(Bit0)); + CHECK_EQUAL(0, value.get_state()); + + //******************************* + // Transition from Off to On. + for (size_t i = 0; i < Valid_Count - 1; ++i) + { + CHECK_FALSE(value.update(1)); + CHECK_FALSE(value.has_changed(Bit0)); + CHECK_FALSE(value.is_set(Bit0)); + CHECK_FALSE(value.is_held(Bit0)); + CHECK_FALSE(value.is_repeating(Bit0)); + } + + CHECK_EQUAL(0, value.get_state()); + + // Changed. + CHECK_TRUE(value.update(1)); + CHECK_TRUE(value.has_changed(Bit0)); + CHECK_TRUE(value.is_set(Bit0)); + CHECK_FALSE(value.is_held(Bit0)); + CHECK_FALSE(value.is_repeating(Bit0)); + + CHECK_EQUAL(1, value.get_state()); + + //******************************* + // Transition from On to Held. + for (size_t i = 0; i < Hold_Count - 1; ++i) + { + CHECK_FALSE(value.update(1)); + CHECK_FALSE(value.has_changed(Bit0)); + CHECK_TRUE(value.is_set(Bit0)); + CHECK_FALSE(value.is_held(Bit0)); + CHECK_FALSE(value.is_repeating(Bit0)); + } + + // Changed. + CHECK_TRUE(value.update(1)); + CHECK_TRUE(value.has_changed(Bit0)); + CHECK_TRUE(value.is_set(Bit0)); + CHECK_TRUE(value.is_held(Bit0)); + CHECK_FALSE(value.is_repeating(Bit0)); + + //******************************* + // Transition from Held to Repeating. + for (size_t i = 0; i < Repeat_Count - 1; ++i) + { + CHECK_FALSE(value.update(1)); + CHECK_FALSE(value.has_changed(Bit0)); + CHECK_TRUE(value.is_set(Bit0)); + CHECK_TRUE(value.is_held(Bit0)); + CHECK_FALSE(value.is_repeating(Bit0)); + } + + // Changed. + CHECK_TRUE(value.update(1)); + CHECK_TRUE(value.has_changed(Bit0)); + CHECK_TRUE(value.is_set(Bit0)); + CHECK_TRUE(value.is_held(Bit0)); + CHECK_TRUE(value.is_repeating(Bit0)); + + //******************************* + // Check for more repeat transitions. + for (size_t i = 0; i < Repeat_Count - 1; ++i) + { + CHECK_FALSE(value.update(1)); + CHECK_FALSE(value.has_changed(Bit0)); + CHECK_TRUE(value.is_set(Bit0)); + CHECK_TRUE(value.is_held(Bit0)); + CHECK_TRUE(value.is_repeating(Bit0)); + } + + // Changed. + CHECK_TRUE(value.update(1)); + CHECK_TRUE(value.has_changed(Bit0)); + CHECK_TRUE(value.is_set(Bit0)); + CHECK_TRUE(value.is_held(Bit0)); + CHECK_TRUE(value.is_repeating(Bit0)); + } + + //************************************************************************* + TEST(test_debounce_valid_hold_repeat_incremental) + { + debounce_valid_hold_repeat value(Initial_Value); + + CHECK_FALSE(value.has_changed(Bit0)); + CHECK_FALSE(value.is_set(Bit0)); + CHECK_FALSE(value.is_held(Bit0)); + CHECK_FALSE(value.is_repeating(Bit0)); + + //******************************* + // Transition from Off to On. + for (size_t i = 0; i < Valid_Count - 1; ++i) + { + for (size_t j = 0; j < value.get_width() - 1; ++j) + { + CHECK_FALSE(value.update_incremental(1)); + } + + CHECK_TRUE(value.update_incremental(1)); + CHECK_FALSE(value.has_changed(Bit0)); + CHECK_FALSE(value.is_set(Bit0)); + CHECK_FALSE(value.is_held(Bit0)); + CHECK_FALSE(value.is_repeating(Bit0)); + } + + // Final incremental update. + // Changed. + for (size_t j = 0; j < value.get_width() - 1; ++j) + { + CHECK_FALSE(value.update_incremental(1)); + } + + CHECK_TRUE(value.update_incremental(1)); + CHECK_TRUE(value.has_changed(Bit0)); + CHECK_TRUE(value.is_set(Bit0)); + CHECK_FALSE(value.is_held(Bit0)); + CHECK_FALSE(value.is_repeating(Bit0)); + + //******************************* + // Transition from On to Held. + for (size_t i = 0; i < Hold_Count - 1; ++i) + { + for (size_t j = 0; j < value.get_width() - 1; ++j) + { + CHECK_FALSE(value.update_incremental(1)); + } + + CHECK_TRUE(value.update_incremental(1)); + CHECK_FALSE(value.has_changed(Bit0)); + CHECK_TRUE(value.is_set(Bit0)); + CHECK_FALSE(value.is_held(Bit0)); + CHECK_FALSE(value.is_repeating(Bit0)); + } + + // Final incremental update. + // Changed. + for (size_t j = 0; j < value.get_width() - 1; ++j) + { + CHECK_FALSE(value.update_incremental(1)); + } + + CHECK_TRUE(value.update_incremental(1)); + CHECK_TRUE(value.has_changed(Bit0)); + CHECK_TRUE(value.is_set(Bit0)); + CHECK_TRUE(value.is_held(Bit0)); + CHECK_FALSE(value.is_repeating(Bit0)); + + //******************************* + // Transition from Held to Repeating. + for (size_t i = 0; i < Repeat_Count - 1; ++i) + { + for (size_t j = 0; j < value.get_width() - 1; ++j) + { + CHECK_FALSE(value.update_incremental(1)); + } + + CHECK_TRUE(value.update_incremental(1)); + CHECK_FALSE(value.has_changed(Bit0)); + CHECK_TRUE(value.is_set(Bit0)); + CHECK_TRUE(value.is_held(Bit0)); + CHECK_FALSE(value.is_repeating(Bit0)); + } + + // Final incremental update. + // Changed. + for (size_t j = 0; j < value.get_width() - 1; ++j) + { + CHECK_FALSE(value.update_incremental(1)); + } + + CHECK_TRUE(value.update_incremental(1)); + CHECK_TRUE(value.has_changed(Bit0)); + CHECK_TRUE(value.is_set(Bit0)); + CHECK_TRUE(value.is_held(Bit0)); + CHECK_TRUE(value.is_repeating(Bit0)); + + //******************************* + // Check for more repeat transitions. + for (size_t i = 0; i < Repeat_Count - 1; ++i) + { + for (size_t j = 0; j < value.get_width() - 1; ++j) + { + CHECK_FALSE(value.update_incremental(1)); + } + + CHECK_TRUE(value.update_incremental(1)); + CHECK_FALSE(value.has_changed(Bit0)); + CHECK_TRUE(value.is_set(Bit0)); + CHECK_TRUE(value.is_held(Bit0)); + CHECK_TRUE(value.is_repeating(Bit0)); + } + + // Final incremental update. + // Changed. + for (size_t j = 0; j < value.get_width() - 1; ++j) + { + CHECK_FALSE(value.update_incremental(1)); + } + + CHECK_TRUE(value.update_incremental(1)); + CHECK_TRUE(value.has_changed(Bit0)); + CHECK_TRUE(value.is_set(Bit0)); + CHECK_TRUE(value.is_held(Bit0)); + CHECK_TRUE(value.is_repeating(Bit0)); + } + + //************************************************************************* + TEST(test_debounce_valid_hold_repeat_check_return_to_off) + { + debounce_valid_hold_repeat value(Initial_Value); + + //******************************* + // Transition from Off to On. + for (size_t i = 0; i < Valid_Count; ++i) + { + value.update(1); + } + + CHECK_TRUE(value.is_set(Bit0)); + CHECK_FALSE(value.is_held(Bit0)); + CHECK_FALSE(value.is_repeating(Bit0)); + + //******************************* + // Transition from On to Off. + for (size_t i = 0; i < Valid_Count; ++i) + { + value.update(0); + } + + CHECK_FALSE(value.is_set(Bit0)); + CHECK_FALSE(value.is_held(Bit0)); + CHECK_FALSE(value.is_repeating(Bit0)); + + //******************************* + // Transition from Off to Held. + for (size_t i = 0; i < Valid_Count; ++i) + { + value.update(1); + } + + for (size_t i = 0; i < Hold_Count; ++i) + { + value.update(1); + } + + CHECK_TRUE(value.is_set(Bit0)); + CHECK_TRUE(value.is_held(Bit0)); + CHECK_FALSE(value.is_repeating(Bit0)); + + //******************************* + // Transition from Held to Off. + for (size_t i = 0; i < Valid_Count; ++i) + { + value.update(0); + } + + CHECK_FALSE(value.is_set(Bit0)); + CHECK_FALSE(value.is_held(Bit0)); + CHECK_FALSE(value.is_repeating(Bit0)); + + //******************************* + // Transition from Off to Repeating. + for (size_t i = 0; i < Valid_Count; ++i) + { + value.update(1); + } + + for (size_t i = 0; i < Hold_Count; ++i) + { + value.update(1); + } + + for (size_t i = 0; i < Repeat_Count; ++i) + { + value.update(1); + } + + CHECK_TRUE(value.is_set(Bit0)); + CHECK_TRUE(value.is_held(Bit0)); + CHECK_TRUE(value.is_repeating(Bit0)); + + //******************************* + // Transition from Repeating to Off. + for (size_t i = 0; i < Valid_Count; ++i) + { + value.update(0); + } + + CHECK_FALSE(value.is_set(Bit0)); + CHECK_FALSE(value.is_held(Bit0)); + CHECK_FALSE(value.is_repeating(Bit0)); + } + + //************************************************************************* + TEST(test_debounce_valid_hold_repeat_check_return_to_off_incremental) + { + debounce_valid_hold_repeat value(Initial_Value); + + //******************************* + // Transition from Off to On. + for (size_t i = 0; i < Valid_Count; ++i) + { + for (size_t j = 0; j < value.get_width(); ++j) + { + value.update_incremental(1); + } + } + + CHECK_TRUE(value.is_set(Bit0)); + CHECK_FALSE(value.is_held(Bit0)); + CHECK_FALSE(value.is_repeating(Bit0)); + + //******************************* + // Transition from On to Off. + for (size_t i = 0; i < Valid_Count; ++i) + { + for (size_t j = 0; j < value.get_width(); ++j) + { + value.update_incremental(0); + } + } + + CHECK_FALSE(value.is_set(Bit0)); + CHECK_FALSE(value.is_held(Bit0)); + CHECK_FALSE(value.is_repeating(Bit0)); + + //******************************* + // Transition from Off to Held. + for (size_t i = 0; i < Valid_Count; ++i) + { + for (size_t j = 0; j < value.get_width(); ++j) + { + value.update_incremental(1); + } + } + + for (size_t i = 0; i < Hold_Count; ++i) + { + for (size_t j = 0; j < value.get_width(); ++j) + { + value.update_incremental(1); + } + } + + CHECK_TRUE(value.is_set(Bit0)); + CHECK_TRUE(value.is_held(Bit0)); + CHECK_FALSE(value.is_repeating(Bit0)); + + //******************************* + // Transition from Held to Off. + for (size_t i = 0; i < Valid_Count; ++i) + { + for (size_t j = 0; j < value.get_width(); ++j) + { + value.update_incremental(0); + } + } + + CHECK_FALSE(value.is_set(Bit0)); + CHECK_FALSE(value.is_held(Bit0)); + CHECK_FALSE(value.is_repeating(Bit0)); + + //******************************* + // Transition from Off to Repeating. + for (size_t i = 0; i < Valid_Count; ++i) + { + for (size_t j = 0; j < value.get_width(); ++j) + { + value.update_incremental(1); + } + } + + for (size_t i = 0; i < Hold_Count; ++i) + { + for (size_t j = 0; j < value.get_width(); ++j) + { + value.update_incremental(1); + } + } + + for (size_t i = 0; i < Repeat_Count; ++i) + { + for (size_t j = 0; j < value.get_width(); ++j) + { + value.update_incremental(1); + } + } + + CHECK_TRUE(value.is_set(Bit0)); + CHECK_TRUE(value.is_held(Bit0)); + CHECK_TRUE(value.is_repeating(Bit0)); + + //******************************* + // Transition from Repeating to Off. + for (size_t i = 0; i < Valid_Count; ++i) + { + for (size_t j = 0; j < value.get_width(); ++j) + { + value.update_incremental(0); + } + } + + CHECK_FALSE(value.is_set(Bit0)); + CHECK_FALSE(value.is_held(Bit0)); + CHECK_FALSE(value.is_repeating(Bit0)); + } + + //************************************************************************* + TEST(test_debounce_valid_hold_repeat_then_reset) + { + debounce_valid_hold_repeat value(Initial_Value); + + //******************************* + // Transition from Off to On. + for (size_t i = 0; i < Valid_Count; ++i) + { + value.update(1); + } + + //******************************* + // Transition from On to Held. + for (size_t i = 0; i < Hold_Count; ++i) + { + value.update(1); + } + + //******************************* + // Partly transition from Held to Repeating. + for (size_t i = 0; i < Repeat_Count - 1; ++i) + { + value.update(1); + } + + value.reset(Initial_Value); + + CHECK_FALSE(value.is_set(Bit0)); + CHECK_FALSE(value.is_held(Bit0)); + CHECK_FALSE(value.is_repeating(Bit0)); + + //******************************* + // Transition from Off to On. + for (size_t i = 0; i < Valid_Count; ++i) + { + value.update(1); + } + + CHECK_TRUE(value.is_set(Bit0)); + CHECK_FALSE(value.is_held(Bit0)); + CHECK_FALSE(value.is_repeating(Bit0)); + } + + //************************************************************************* + TEST(debounce_valid_hold_repeat_multiple_bits) + { + std::array input = {1, 0, 1, 0, 1, 3, 1, 3, 1, 3, 3, 3, 3, 7, 3, 6, 3, 6, 7, 6, 4, 6, 4, + 7, 5, 4, 5, 5, 1, 5, 1, 5, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0}; + + using state_id_type = debounce_valid_hold_repeat::state_id_type; + using state_id = debounce_valid_hold_repeat::state_id; + + std::array expected0 = { + state_id::Off, state_id::Off, state_id::Off, state_id::Off, state_id::Off, state_id::Off, + state_id::Off, state_id::On, state_id::On, state_id::On, state_id::Held, state_id::Held, + state_id::Repeating, state_id::Repeating, state_id::Repeating, state_id::Repeating, state_id::Repeating, state_id::Repeating, + state_id::Repeating, state_id::Repeating, state_id::Repeating, state_id::Repeating, state_id::Off, state_id::Off, + state_id::Off, state_id::Off, state_id::Off, state_id::Off, state_id::Off, state_id::On, + state_id::On, state_id::On, state_id::Held, state_id::Held, state_id::Repeating, state_id::Repeating, + state_id::Repeating, state_id::Repeating, state_id::Repeating, state_id::Repeating, state_id::Repeating, state_id::Repeating, + state_id::Repeating, state_id::Repeating, state_id::Off}; + + std::array expected1 = { + state_id::Off, state_id::Off, state_id::Off, state_id::Off, state_id::Off, state_id::Off, + state_id::Off, state_id::Off, state_id::Off, state_id::Off, state_id::Off, state_id::Off, + state_id::On, state_id::On, state_id::On, state_id::Held, state_id::Held, state_id::Repeating, + state_id::Repeating, state_id::Repeating, state_id::Repeating, state_id::Repeating, state_id::Repeating, state_id::Repeating, + state_id::Repeating, state_id::Repeating, state_id::Repeating, state_id::Off, state_id::Off, state_id::Off, + state_id::Off, state_id::Off, state_id::Off, state_id::Off, state_id::Off, state_id::Off, + state_id::Off, state_id::Off, state_id::Off, state_id::Off, state_id::Off, state_id::Off, + state_id::Off, state_id::Off, state_id::Off}; + + std::array expected2 = { + state_id::Off, state_id::Off, state_id::Off, state_id::Off, state_id::Off, state_id::Off, + state_id::Off, state_id::Off, state_id::Off, state_id::Off, state_id::Off, state_id::Off, + state_id::Off, state_id::Off, state_id::Off, state_id::Off, state_id::Off, state_id::Off, + state_id::Off, state_id::Off, state_id::On, state_id::On, state_id::On, state_id::Held, + state_id::Held, state_id::Repeating, state_id::Repeating, state_id::Repeating, state_id::Repeating, state_id::Repeating, + state_id::Repeating, state_id::Repeating, state_id::Repeating, state_id::Repeating, state_id::Repeating, state_id::Off, + state_id::Off, state_id::Off, state_id::Off, state_id::Off, state_id::Off, state_id::Off, + state_id::Off, state_id::Off, state_id::Off}; + + debounce_valid_hold_repeat value; + + for (size_t i = 0; i < input.size(); ++i) + { + value.update(input[i]); + + CHECK_EQUAL(int(expected0[i]), int(value.get_state(0))); + CHECK_EQUAL(int(expected1[i]), int(value.get_state(1))); + CHECK_EQUAL(int(expected2[i]), int(value.get_state(2))); + } + } } } // namespace