Work in progress

This commit is contained in:
John Wellbelove 2026-11-04 18:18:34 +00:00
parent 9236f8f313
commit 1d01450757
7 changed files with 689 additions and 231 deletions

97
docs/IO/debounce-value.md Normal file
View File

@ -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 <typename TValue, typename TCount>
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.

View File

@ -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 <stddef.h>
#include <stdint.h>
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 <typename TValue, typename TCount, size_t Width, uint32_t Valid_Count, uint32_t Hold_Count = 0, uint32_t Repeat_Count = 0>
class debounce_multi_bit
{
public:
ETL_STATIC_ASSERT(std::is_integral<TValue>::value&& std::is_unsigned<TValue>::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>(~TCount(0)) && Hold_Count <= static_cast<TCount>(~TCount(0))
&& Repeat_Count <= static_cast<TCount>(~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_type>((state_lo & bit) > 0);
state_type hi = static_cast<state_type>((state_hi & bit) > 0);
return static_cast<state_type>(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>(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

View File

@ -36,163 +36,101 @@ SOFTWARE.
namespace etl
{
template <typename TValue>
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 <typename TValue, typename TCount = uint16_t>
class debounce_value
{
public:
virtual void on_debounce_value_notification(TValue value) = 0;
};
namespace private_debounce_value
{
template <typename TValue, typename TCount>
class debounce_value_base
{
public:
typedef TCount count_type;
typedef TValue value_type;
typedef debounce_value_notification<value_type> 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<State>(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 = &notification_;
}
//*************************************************************************
/// 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 <typename TValue, typename TCount>
class debounce_value : public private_debounce_value::debounce_value_base<TValue, TCount>
{
public:
using value_type = typename private_debounce_value::debounce_value_base<TValue, TCount>::value_type;
using count_type = typename private_debounce_value::debounce_value_base<TValue, TCount>::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<TValue, TCount>(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<TValue, TCount>::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<State>(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

View File

@ -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 <vector>
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<value_type, count_type, 1, Valid_Count>;
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

View File

@ -34,18 +34,6 @@ SOFTWARE.
namespace
{
uint8_t notification_value = 0;
class Notification : public etl::debounce_value<uint8_t, uint8_t>::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<uint8_t, uint8_t> 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<uint8_t, uint8_t> 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<uint8_t, uint8_t> 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<uint8_t> input = { 1, 2, 3, 3, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 6 };
std::vector<uint8_t> input = {1, 2, 3, 3, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 6};
std::vector<uint8_t> output;
std::vector<uint8_t> expected = { 2, 3, 4, 6 };
std::vector<uint8_t> expected = {2, 3, 4, 6};
const uint8_t Stable_Count = 3;
const uint8_t Stable_Count = 3;
etl::debounce_value<uint8_t, uint8_t> value(0, Stable_Count);
for (uint8_t v : input)

View File

@ -3539,6 +3539,7 @@
<ClInclude Include="..\..\include\etl\crc8_opensafety.h" />
<ClInclude Include="..\..\include\etl\crc8_rohc.h" />
<ClInclude Include="..\..\include\etl\crc8_wcdma.h" />
<ClInclude Include="..\..\include\etl\debounce_multi_bit.h" />
<ClInclude Include="..\..\include\etl\debounce_value.h" />
<ClInclude Include="..\..\include\etl\delegate_observable.h" />
<ClInclude Include="..\..\include\etl\expected.h" />
@ -10392,6 +10393,7 @@
<ClCompile Include="..\test_crc8_opensafety.cpp" />
<ClCompile Include="..\test_crc8_rohc.cpp" />
<ClCompile Include="..\test_crc8_wcdma.cpp" />
<ClCompile Include="..\test_debounce_multi_bit.cpp" />
<ClCompile Include="..\test_debounce_value.cpp" />
<ClCompile Include="..\test_delegate_observable.cpp" />
<ClCompile Include="..\test_etl_assert.cpp" />

View File

@ -1566,12 +1566,15 @@
<ClInclude Include="..\..\include\etl\format.h">
<Filter>UnitTest++\Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\include\etl\debounce_value.h">
<Filter>UnitTest++\Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\include\etl\notification.h">
<Filter>UnitTest++\Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\include\etl\debounce_value.h">
<Filter>ETL\Utilities</Filter>
</ClInclude>
<ClInclude Include="..\..\include\etl\debounce_multi_bit.h">
<Filter>ETL\Utilities</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\test_string_char.cpp">
@ -3848,6 +3851,9 @@
<ClCompile Include="..\test_debounce_value.cpp">
<Filter>Tests\Misc</Filter>
</ClCompile>
<ClCompile Include="..\test_debounce_multi_bit.cpp">
<Filter>Tests\Algorithms</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\..\library.properties">