From 1d01450757650fd61016bce6030b98389409d898 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 4 Nov 2026 18:18:34 +0000 Subject: [PATCH] Work in progress --- docs/IO/debounce-value.md | 97 +++++++++ include/etl/debounce_multi_bit.h | 360 +++++++++++++++++++++++++++++++ include/etl/debounce_value.h | 234 ++++++++------------ test/test_debounce_multi_bit.cpp | 125 +++++++++++ test/test_debounce_value.cpp | 90 +------- test/vs2022/etl.vcxproj | 2 + test/vs2022/etl.vcxproj.filters | 12 +- 7 files changed, 689 insertions(+), 231 deletions(-) create mode 100644 docs/IO/debounce-value.md create mode 100644 include/etl/debounce_multi_bit.h create mode 100644 test/test_debounce_multi_bit.cpp diff --git a/docs/IO/debounce-value.md b/docs/IO/debounce-value.md new file mode 100644 index 00000000..50ace490 --- /dev/null +++ b/docs/IO/debounce-value.md @@ -0,0 +1,97 @@ +--- +title: "debounce_value" +--- + +{{< callout type="info">}} + Header: `debounce_value.h` + Since: `20.50.0` +{{< /callout >}} + +This class is designed to take an input value that may take time to become stable, such as a binary rotary encoder or DIP switches, and indicate when it has settled to a stable state. + +```cpp +template +etl::debounce_value; +``` + +## Types + +`value_type` : The type of the input value. +`count_type` : The type for the counter. + + +## Member functions + +```cpp +debounce_value(value_type initial_value, count_type stable_count) +``` +**Description** +Constructor. + +**Parameters** +`initial_value` : The initial value of the 'last' sample. + +`stable_count` : The count at which an input is deemed to be stable. + +--- + +```cpp +bool add(value_type value) +``` +**Description** +Adds a new value. +If the value has changed, the count is reset and the value is marked as unstable. + +**Parameters** +`value` : The next input value. + +**Return** +Returns `true` if the value has changed. + +--- + +```cpp +value_type get() const +``` +**Description** +Gets the current value. +May not be stable unless `is_stable()` returns `true`. + +--- + +```cpp +operator value_type() const +``` +**Description** +Conversion operator. +May not be stable unless `is_stable()` returns `true`. + +--- + +```cpp +bool has_changed() const +``` +**Description** +Gets the current change state. + +**Return** +`true` if the stable value has changed. + +--- + +```cpp +bool is_stable() const +``` +**Description** +Gets the current stable state. + +**Return** +`true` if the value is stable. + +--- + +```cpp +void set_stable_count(count_type stable_count) +``` +**Description** +Sets the count at which a non-changing input value is seen as stable. diff --git a/include/etl/debounce_multi_bit.h b/include/etl/debounce_multi_bit.h new file mode 100644 index 00000000..83d8852f --- /dev/null +++ b/include/etl/debounce_multi_bit.h @@ -0,0 +1,360 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2026 John Wellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef DEBOUNCE_MULTI_BIT_INCLUDED +#define DEBOUNCE_MULTI_BIT_INCLUDED + +//----------------------------------------------------------------------------- +// debounce_multi_bit +// +// Debounces a contiguous group of bits read from an IO port. Each bit is +// debounced independently, using the same semantics as etl::debounce: +// +// Valid_Count : Number of consecutive samples a bit must differ from its +// previous debounced state before the state changes (>= 1). +// Hold_Count : Number of samples a bit must remain set (after becoming +// valid) before a 'held' event is generated. 0 = disabled. +// Repeat_Count : Once held, a 'repeat' event is generated every +// Repeat_Count samples. 0 = disabled. +// +// TValue : unsigned integer type of the port (uint8_t/16_t/32_t/64_t). +// Shift : Position of the lowest bit of the field within the port value. +// Width : Number of contiguous bits in the field. +// TCount : Type of the per-bit counters. Must be able to hold the largest of +// Valid_Count, Hold_Count and Repeat_Count. +// +// All masks returned by this class are field-aligned, i.e. bit 0 of a mask +// corresponds to the lowest bit of the field (port bit 'Shift'). +// +// Call update() at a fixed sampling interval (e.g. every 1ms from a timer). +//----------------------------------------------------------------------------- + +#include "platform.h" +#include "binary.h" +#include "memory.h" +#include "static_assert.h" + +#include +#include + +namespace etl +{ + //************************************************************************* + /// Debounces a contiguous group of bits read from an IO port. + ///\tparam TValue The type of the port value (uint8_t/16_t/32_t/64_t). + ///\tparam Width The number of bits in the field (1..sizeof(TValue) * 8). + ///\tparam Valid_Count The number of consecutive samples a bit must differ + /// from its previous debounced state before the state + /// changes (>= 1). + ///\tparam Hold_Count The number of samples a bit must remain set (after + /// becoming valid) before a 'held' event is generated. + /// 0 = disabled. + ///\tparam Repeat_Count Once held, a 'repeat' event is generated every + /// Repeat_Count samples. 0 = disabled. + ///\tparam TCount The type of the per-bit counters. Must be able to hold + /// the largest of Valid_Count, Hold_Count and Repeat_Count. + //************************************************************************* + template + class debounce_multi_bit + { + public: + + ETL_STATIC_ASSERT(std::is_integral::value&& std::is_unsigned::value, "TValue must be an unsigned integer type"); + ETL_STATIC_ASSERT(Width >= 1, "Width must be at least 1"); + ETL_STATIC_ASSERT(Width <= sizeof(TValue) * 8, "Field does not fit in the value type"); + ETL_STATIC_ASSERT(Valid_Count >= 1, "Valid_Count must be at least 1"); + ETL_STATIC_ASSERT(Valid_Count <= static_cast(~TCount(0)) && Hold_Count <= static_cast(~TCount(0)) + && Repeat_Count <= static_cast(~TCount(0)), + "TCount is too small for the configured counts"); + + typedef TValue value_type; + typedef TCount count_type; + typedef uint_least8_t state_type; + + //*************************************************************************** + /// Constructor. All bits start in the 'clear' state. + //*************************************************************************** + debounce_multi_bit(value_type initial = 0) + { + reset(initial); + } + + //*************************************************************************** + /// Resets the debouncer state. + //*************************************************************************** + void reset(value_type initial = 0) + { + sample = initial; + state_lo = 0; + state_hi = 0; + changed = 0; + + // Clear the timers for all bits. + etl::fill(ETL_OR_STD::begin(counts), ETL_OR_STD::end(counts), 0); + } + + //*************************************************************************** + /// Adds a new next of the whole port value. + /// Returns true if any bit changed state, became held, or repeated. + //*************************************************************************** + void update(const value_type next) + { + value_type changed_bits = sample ^ next; + sample = next; + + changed = 0; + + count_type* pcount = &counts[0]; + value_type bit = 1U; + pcount = &counts[0]; + + for (size_t i = 0; i < Width; ++i) + { + bool bit_is_set = (sample & bit) != 0; + bool bit_has_changed = (changed_bits & bit) != 0; + + if (bit_has_changed) + { + // Reset the timer for this bit. + *pcount = 0; + } + + switch (get_state(bit)) + { + case Off: + { + if (bit_is_set) + { + ++(*pcount); + + // If we have reached the 'Valid_Count' move to the On state. + if (*pcount >= Valid_Count) + { + set_state(On, bit); + changed |= bit; + *pcount = 0; + } + } + } + break; + + case On: + { + if (Hold_Count > 0) + { + ++(*pcount); + + if (bit_is_set) + { + // If we have reached the 'Hold_Count', and hold is enabled, we move to the Held state. + if (*pcount >= Hold_Count) + { + set_state(Held, bit); + changed |= bit; + *pcount = 0; + } + } + else + { + // If we have reached the 'Valid_Count' we move back to the Off state. + if (*pcount >= Valid_Count) + { + set_state(Off, bit); + changed |= bit; + *pcount = 0; + } + } + } + } + break; + + case Held: + { + if (Repeat_Count > 0) + { + ++(*pcount); + + if (bit_is_set) + { + // If we have reached the 'repeat count', and repeat is enabled, we move to the Repeating state. + if (*pcount >= Repeat_Count) + { + set_state(Repeating, bit); + changed |= bit; + *pcount = 0; + } + } + else + { + // If we have reached the 'Valid_Count' we move back to the Off state. + if (*pcount >= Valid_Count) + { + set_state(Off, bit); + changed |= bit; + *pcount = 0; + } + } + } + } + break; + + case Repeating: + { + ++(*pcount); + + if (bit_is_set) + { + // If we have reached the 'Repeat_Count', and repeat is enabled, we set the changed flag again. + if (*pcount >= Repeat_Count) + { + changed |= bit; + *pcount = 0; + } + } + else + { + // If we have reached the 'Valid_Count' we move back to the Off state. + if (*pcount >= Valid_Count) + { + set_state(Off, bit); + changed |= bit; + *pcount = 0; + } + } + } + break; + } + + // changed_bits = changed_bits >> 1U; // Move to the next bit. + bit = bit << 1U; // Move to the next bit. + ++pcount; // Move to the next bit's timer. + } + } + + //*************************************************************************** + /// Returns true if the bit changed state on the last update. + ///\param n The bit number (0..Width - 1). + //*************************************************************************** + bool has_changed(size_t n) const + { + value_type bit = bit_mask(n); + + return (changed & bit) != 0; + } + + //*************************************************************************** + /// Returns true if the bit is currently set. + ///\param n The bit number (0..Width - 1). + //*************************************************************************** + bool is_set(size_t n) const + { + value_type bit = bit_mask(n); + state_type state = get_state(bit); + + return (state == On) || (state == Held) || (state == Repeating); + } + + //*************************************************************************** + /// Returns true if the bit is currently held. + ///\param n The bit number (0..Width - 1). + //*************************************************************************** + bool is_held(size_t n) const + { + value_type bit = bit_mask(n); + state_type state = get_state(bit); + + return (state == Held) || (state == Repeating); + } + + //*************************************************************************** + /// Returns true if the bit is currently repeating. + ///\param n The bit number (0..Width - 1). + //*************************************************************************** + bool is_repeating(size_t n) const + { + value_type bit = bit_mask(n); + state_type state = get_state(bit); + + return (state == Repeating); + } + + private: + + //*************************************************************************** + /// State fit in 2 bits, state_lo & state_hi. + //*************************************************************************** + enum state + { + Off = 0, // Debounced state is Off. + On = 1, // Debounced state is On. + Held = 2, // Debounced state is Held. + Repeating = 3 // Debounced state is Repeating. + }; + + //*************************************************************************** + /// Gets the current debounce state for a specific bit. + ///\return The current state of the bit. + //*************************************************************************** + state_type get_state(const value_type bit) const + { + state_type lo = static_cast((state_lo & bit) > 0); + state_type hi = static_cast((state_hi & bit) > 0); + + return static_cast(lo | (hi << 1)); + } + + //*************************************************************************** + /// Gets the current debounce state for a specific bit. + ///\return The current state of the bit. + //*************************************************************************** + void set_state(state_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; + } + + //************************************************************************* + /// Returns a mask with only the nth bit set. + //***************************************************************************** + static value_type bit_mask(size_t n) + { + return static_cast(value_type(1) << n); + } + + value_type sample; // The last known state of the bits. + value_type state_lo; // Low bits of the state. + value_type state_hi; // High bits of the state. + value_type changed; // Bits that have changed at the last update. + + count_type counts[Width]; // Off / On / Hold / Repeat timers. + }; +} // namespace etl + +#endif diff --git a/include/etl/debounce_value.h b/include/etl/debounce_value.h index e8bd82eb..52ffaedc 100644 --- a/include/etl/debounce_value.h +++ b/include/etl/debounce_value.h @@ -36,163 +36,101 @@ SOFTWARE. namespace etl { - template - class debounce_value_notification + //*************************************************************************** + /// This class is designed to take an input value that may take time to become stable, + /// such as a binary rotary encoder or DIP switches, and indicate when it has settled to a stable state. + /// TValue : The type of the value being debounced. + /// TCount : The type of the counter used to determine stability. + //*************************************************************************** + template + class debounce_value { public: - virtual void on_debounce_value_notification(TValue value) = 0; - }; - - namespace private_debounce_value - { - template - class debounce_value_base - { - public: - - typedef TCount count_type; - typedef TValue value_type; - - typedef debounce_value_notification notification_type; - - //************************************************************************* - /// Constructor. - //************************************************************************* - debounce_value_base(value_type initial_value) - : last_value(initial_value) - , count(0) - , state(Unstable) - , notification(nullptr) - { - } - - //************************************************************************* - /// Adds a new value. - /// If the value has changed, the counter is reset and the value is marked as unstable. - /// Returns 'true' if the value has changed. - //************************************************************************* - bool add(value_type value, count_type stable_count) - { - // Changed from last time? - if (value != last_value) - { - count = 1; - state = Unstable; - } - else - { - // Increment the counter if we haven't reached the stable count yet. - if (count < stable_count) - { - ++count; - - // Check if we've reached the stable count. - if (count == stable_count) - { - state = static_cast(Stable | Changed); - - if (notification) - { - notification->on_debounce_value_notification(value); - } - } - } - else - { - // If the counter has already reached the stable count then we are already stable, but no further change has occurred. - state = Stable; - } - } - - last_value = value; - - return has_changed(); - } - - //************************************************************************* - /// Sets the notification interface. - ///\param notification_ The notification interface. - //************************************************************************* - void set_notification(notification_type& notification_) - { - notification = ¬ification_; - } - - //************************************************************************* - /// Clears the notification interface. - //************************************************************************* - void clear_notification() - { - notification = nullptr; - } - - //************************************************************************* - /// Gets the current value. - //************************************************************************* - value_type get() const - { - return last_value; - } - - //************************************************************************* - /// Gets the current change state. - ///\return 'true' if the value has changed. - //************************************************************************* - bool has_changed() const - { - return (state & Changed) != 0; - } - - //************************************************************************* - /// Gets the current stable state. - ///\return 'true' if the value is stable. - //************************************************************************* - bool is_stable() const - { - return (state & Stable) != 0; - } - - protected: - - enum State - { - Unstable = 0, - Stable = 1, - Changed = 2 - }; - - value_type last_value; - count_type count; - notification_type* notification; - State state; - }; - } // namespace private_debounce_value - - template - class debounce_value : public private_debounce_value::debounce_value_base - { - public: - - using value_type = typename private_debounce_value::debounce_value_base::value_type; - using count_type = typename private_debounce_value::debounce_value_base::count_type; + typedef TValue value_type; + typedef TCount count_type; //************************************************************************* /// Constructor. //************************************************************************* - explicit debounce_value(value_type initial_value, count_type stable_count) - : private_debounce_value::debounce_value_base(initial_value) - , stable_count(stable_count) + debounce_value(value_type initial_value_, count_type stable_count_) + : last_value(initial_value_) + , count(0) + , stable_count(stable_count_) + , state(Unstable) { } //************************************************************************* - /// Adds a new value to the debounced. - /// If the value has changed, the counter is reset and the debounced is marked as unstable. + /// Adds a new value. + /// If the value has changed, the counter is reset and the value is marked as unstable. + /// Returns 'true' if the value has changed. //************************************************************************* bool add(value_type value) { - return private_debounce_value::debounce_value_base::add(value, stable_count); + // Changed from last time? + if (value != last_value) + { + count = 1; + state = Unstable; + } + else + { + // Increment the counter if we haven't reached the stable count yet. + if (count < stable_count) + { + ++count; + + // Have we reached the stable count? + if (count == stable_count) + { + state = static_cast(Stable | Changed); + } + } + else + { + // If the counter has already reached the stable count then we are already stable, but no further change has occurred. + state = Stable; + } + } + + last_value = value; + + return has_changed(); + } + + //************************************************************************* + /// Gets the current value. + //************************************************************************* + value_type get() const + { + return last_value; + } + + //************************************************************************* + /// Conversion operator. + //************************************************************************* + operator value_type() const + { + return last_value; + } + + //************************************************************************* + /// Gets the current change state. + ///\return 'true' if the value has changed. + //************************************************************************* + bool has_changed() const + { + return (state & Changed) != 0; + } + + //************************************************************************* + /// Gets the current stable state. + ///\return 'true' if the value is stable. + //************************************************************************* + bool is_stable() const + { + return (state & Stable) != 0; } //************************************************************************* @@ -205,7 +143,17 @@ namespace etl private: + enum State + { + Unstable = 0, + Stable = 1, + Changed = 2 + }; + + value_type last_value; + count_type count; count_type stable_count; + State state; }; } // namespace etl diff --git a/test/test_debounce_multi_bit.cpp b/test/test_debounce_multi_bit.cpp new file mode 100644 index 00000000..99f6b9ab --- /dev/null +++ b/test/test_debounce_multi_bit.cpp @@ -0,0 +1,125 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2026 John Wellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include "unit_test_framework.h" + +#include "etl/debounce_multi_bit.h" + +#include + +namespace +{ + using value_type = uint8_t; + using count_type = uint16_t; + + const value_type Initial_Value = 0; + + const count_type Valid_Count = 4; + const count_type Hold_Count = 3; + const count_type Repeat_Count = 2; + + const value_type Bit0 = 0; + const value_type Bit1 = 1; + const value_type Bit2 = 2; + + using debounce_type1 = etl::debounce_multi_bit; + + SUITE(test_debounce_multi_bit) + { + //************************************************************************* + TEST(test_debounce1) + { + debounce_type1 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. + 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)); + + 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)); + + 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)); + + // Stable & changed. + 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)); + + // Still stable. + 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)); + + ////******************************* + //// Transition from unstable to stable. + //// Unstable. + // CHECK_FALSE(value.add(3)); + // CHECK_FALSE(value.is_stable()); + // CHECK_FALSE(value.has_changed()); + + // CHECK_FALSE(value.add(3)); + // CHECK_FALSE(value.is_stable()); + // CHECK_FALSE(value.has_changed()); + + // CHECK_FALSE(value.add(3)); + // CHECK_FALSE(value.is_stable()); + // CHECK_FALSE(value.has_changed()); + + //// Stable & changed. + // CHECK_TRUE(value.add(3)); + // CHECK_TRUE(value.is_stable()); + // CHECK_TRUE(value.has_changed()); + // CHECK_EQUAL(3, value.get()); + + //// Stable. + // CHECK_FALSE(value.add(3)); + // CHECK_TRUE(value.is_stable()); + // CHECK_FALSE(value.has_changed()); + } + } +} // namespace diff --git a/test/test_debounce_value.cpp b/test/test_debounce_value.cpp index f3f87e03..29e60a8c 100644 --- a/test/test_debounce_value.cpp +++ b/test/test_debounce_value.cpp @@ -34,18 +34,6 @@ SOFTWARE. namespace { - uint8_t notification_value = 0; - - class Notification : public etl::debounce_value::notification_type - { - void on_debounce_value_notification(uint8_t value) override - { - notification_value = value; - } - }; - - Notification notification; - SUITE(test_debounce) { //************************************************************************* @@ -56,10 +44,6 @@ namespace etl::debounce_value value(Initial_Value, Stable_Count); - value.set_notification(notification); - - notification_value = 0; - CHECK_FALSE(value.is_stable()); CHECK_FALSE(value.has_changed()); @@ -77,18 +61,12 @@ namespace CHECK_FALSE(value.is_stable()); CHECK_FALSE(value.has_changed()); - // Not notified yet. - CHECK_EQUAL(0, notification_value); - // Stable & changed. CHECK_TRUE(value.add(2)); CHECK_TRUE(value.is_stable()); CHECK_TRUE(value.has_changed()); CHECK_EQUAL(2, value.get()); - // Notified. - CHECK_EQUAL(2, notification_value); - // Still stable. CHECK_FALSE(value.add(2)); CHECK_TRUE(value.is_stable()); @@ -109,18 +87,12 @@ namespace CHECK_FALSE(value.is_stable()); CHECK_FALSE(value.has_changed()); - // Not notified yet. - CHECK_EQUAL(2, notification_value); - // Stable & changed. CHECK_TRUE(value.add(3)); CHECK_TRUE(value.is_stable()); CHECK_TRUE(value.has_changed()); CHECK_EQUAL(3, value.get()); - // Notified. - CHECK_EQUAL(3, notification_value); - // Stable. CHECK_FALSE(value.add(3)); CHECK_TRUE(value.is_stable()); @@ -131,14 +103,10 @@ namespace TEST(test_debounce_value_modify_stable_count) { const uint8_t Initial_Value = 1; - const uint8_t Stable_Count = 4; + const uint8_t Stable_Count = 4; etl::debounce_value value(Initial_Value, Stable_Count); - value.set_notification(notification); - - notification_value = 0; - CHECK_FALSE(value.is_stable()); CHECK_FALSE(value.has_changed()); @@ -156,18 +124,12 @@ namespace CHECK_FALSE(value.is_stable()); CHECK_FALSE(value.has_changed()); - // Not notified yet. - CHECK_EQUAL(0, notification_value); - // Stable & changed. CHECK_TRUE(value.add(2)); CHECK_TRUE(value.is_stable()); CHECK_TRUE(value.has_changed()); CHECK_EQUAL(2, value.get()); - // Notified. - CHECK_EQUAL(2, notification_value); - // Still stable. CHECK_FALSE(value.add(2)); CHECK_TRUE(value.is_stable()); @@ -184,18 +146,12 @@ namespace CHECK_FALSE(value.is_stable()); CHECK_FALSE(value.has_changed()); - // Not notified yet. - CHECK_EQUAL(2, notification_value); - // Stable & changed. CHECK_TRUE(value.add(3)); CHECK_TRUE(value.is_stable()); CHECK_TRUE(value.has_changed()); CHECK_EQUAL(3, value.get()); - // Notified. - CHECK_EQUAL(3, notification_value); - // Stable. CHECK_FALSE(value.add(3)); CHECK_TRUE(value.is_stable()); @@ -203,49 +159,13 @@ namespace } //************************************************************************* - TEST(test_debounce_value_modify_notification) + TEST(test_debounce_values_from_an_input_stream) { - const uint8_t Initial_Value = 1; - const uint8_t Stable_Count = 4; - - etl::debounce_value value(Initial_Value, Stable_Count); - - value.set_notification(notification); - - notification_value = 0; - - //******************************* - // Transition from unstable to stable. - CHECK_FALSE(value.add(2)); - CHECK_FALSE(value.add(2)); - CHECK_FALSE(value.add(2)); - CHECK_TRUE(value.add(2)); - - // Notified. - CHECK_EQUAL(2, notification_value); - - value.clear_notification(); - - //******************************* - // Transition from unstable to stable. - // Unstable. - CHECK_FALSE(value.add(3)); - CHECK_FALSE(value.add(3)); - CHECK_FALSE(value.add(3)); - CHECK_TRUE(value.add(3)); - - // Not notified, so the value remains the same. - CHECK_EQUAL(2, notification_value); - } - - //************************************************************************* - TEST(test_debounce_values_from_an_input) - { - std::vector input = { 1, 2, 3, 3, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 6 }; + std::vector input = {1, 2, 3, 3, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 6}; std::vector output; - std::vector expected = { 2, 3, 4, 6 }; + std::vector expected = {2, 3, 4, 6}; - const uint8_t Stable_Count = 3; + const uint8_t Stable_Count = 3; etl::debounce_value value(0, Stable_Count); for (uint8_t v : input) diff --git a/test/vs2022/etl.vcxproj b/test/vs2022/etl.vcxproj index 6ebafcc4..4e6ad089 100644 --- a/test/vs2022/etl.vcxproj +++ b/test/vs2022/etl.vcxproj @@ -3539,6 +3539,7 @@ + @@ -10392,6 +10393,7 @@ + diff --git a/test/vs2022/etl.vcxproj.filters b/test/vs2022/etl.vcxproj.filters index d53a1889..20e9937d 100644 --- a/test/vs2022/etl.vcxproj.filters +++ b/test/vs2022/etl.vcxproj.filters @@ -1566,12 +1566,15 @@ UnitTest++\Header Files - - UnitTest++\Header Files - UnitTest++\Header Files + + ETL\Utilities + + + ETL\Utilities + @@ -3848,6 +3851,9 @@ Tests\Misc + + Tests\Algorithms +