mirror of
https://github.com/ETLCPP/etl.git
synced 2026-11-10 15:19:50 +08:00
Added a debounce value class
This commit is contained in:
parent
97deef996f
commit
fa8e897237
258
include/etl/debounce_value.h
Normal file
258
include/etl/debounce_value.h
Normal file
@ -0,0 +1,258 @@
|
|||||||
|
///\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 ETL_DEBOUNCE_VALUE_INCLUDED
|
||||||
|
#define ETL_DEBOUNCE_VALUE_INCLUDED
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
#include "type_traits.h"
|
||||||
|
|
||||||
|
namespace etl
|
||||||
|
{
|
||||||
|
template <typename TValue>
|
||||||
|
class debounce_value_notification
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
: value(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 is stable.
|
||||||
|
//*************************************************************************
|
||||||
|
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 is_stable();
|
||||||
|
}
|
||||||
|
|
||||||
|
//*************************************************************************
|
||||||
|
/// 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 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 value;
|
||||||
|
value_type last_value;
|
||||||
|
count_type count;
|
||||||
|
notification_type* notification;
|
||||||
|
State state;
|
||||||
|
};
|
||||||
|
} // namespace private_debounce_value
|
||||||
|
|
||||||
|
template <typename TValue, typename TCount, typename TTag>
|
||||||
|
class debounce_value;
|
||||||
|
|
||||||
|
//*************************************************************************
|
||||||
|
/// A debounced for a value.
|
||||||
|
/// The debounced will only change its value if the new value has been stable for a given number of calls.
|
||||||
|
/// Compile-time stable count.
|
||||||
|
//*************************************************************************
|
||||||
|
template <typename TValue, typename TCount, TCount Stable_Count>
|
||||||
|
class debounce_value<TValue, TCount, etl::integral_constant<TCount, Stable_Count>> // (2) compile-time specialization
|
||||||
|
: 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;
|
||||||
|
|
||||||
|
//*************************************************************************
|
||||||
|
/// Constructor.
|
||||||
|
//*************************************************************************
|
||||||
|
explicit debounce_value(value_type initial_value)
|
||||||
|
: private_debounce_value::debounce_value_base<TValue, TCount>(initial_value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//*************************************************************************
|
||||||
|
/// Adds a new value to the debounced.
|
||||||
|
/// If the value has changed, the counter is reset and the debounced is marked as unstable.
|
||||||
|
//*************************************************************************
|
||||||
|
bool add(value_type value)
|
||||||
|
{
|
||||||
|
return private_debounce_value::debounce_value_base<TValue, TCount>::add(value, Stable_Count);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//*************************************************************************
|
||||||
|
/// A debounced for a value.
|
||||||
|
/// The debounced will only change its value if the new value has been stable for a given number of calls.
|
||||||
|
/// Runtime stable count.
|
||||||
|
//*************************************************************************
|
||||||
|
struct debounce_runtime_tag
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename TValue, typename TCount = uint16_t, typename TTag = debounce_runtime_tag>
|
||||||
|
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;
|
||||||
|
|
||||||
|
//*************************************************************************
|
||||||
|
/// 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)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//*************************************************************************
|
||||||
|
/// Adds a new value to the debounced.
|
||||||
|
/// If the value has changed, the counter is reset and the debounced is marked as unstable.
|
||||||
|
//*************************************************************************
|
||||||
|
bool add(value_type value)
|
||||||
|
{
|
||||||
|
return private_debounce_value::debounce_value_base<TValue, TCount>::add(value, stable_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
//*************************************************************************
|
||||||
|
/// Sets the stable count.
|
||||||
|
//*************************************************************************
|
||||||
|
void set_stable_count(count_type stable_count_)
|
||||||
|
{
|
||||||
|
stable_count = stable_count_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
count_type stable_count;
|
||||||
|
};
|
||||||
|
} // namespace etl
|
||||||
|
|
||||||
|
#endif
|
||||||
125
test/test_debounce_value.cpp
Normal file
125
test/test_debounce_value.cpp
Normal 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_value.h"
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
TEST(test_debounce_value_runtime)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
|
CHECK_FALSE(value.is_stable());
|
||||||
|
CHECK_FALSE(value.has_changed());
|
||||||
|
|
||||||
|
//*******************************
|
||||||
|
// Transition from unstable to stable.
|
||||||
|
CHECK_FALSE(value.add(2));
|
||||||
|
CHECK_FALSE(value.is_stable());
|
||||||
|
CHECK_FALSE(value.has_changed());
|
||||||
|
|
||||||
|
CHECK_FALSE(value.add(2));
|
||||||
|
CHECK_FALSE(value.is_stable());
|
||||||
|
CHECK_FALSE(value.has_changed());
|
||||||
|
|
||||||
|
CHECK_FALSE(value.add(2));
|
||||||
|
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());
|
||||||
|
|
||||||
|
// Notified.
|
||||||
|
CHECK_EQUAL(2, notification_value);
|
||||||
|
|
||||||
|
// Still stable.
|
||||||
|
CHECK_TRUE(value.add(2));
|
||||||
|
CHECK_TRUE(value.is_stable());
|
||||||
|
CHECK_FALSE(value.has_changed());
|
||||||
|
|
||||||
|
//*******************************
|
||||||
|
// 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());
|
||||||
|
|
||||||
|
// 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());
|
||||||
|
|
||||||
|
// Notified.
|
||||||
|
CHECK_EQUAL(3, notification_value);
|
||||||
|
|
||||||
|
// Stable.
|
||||||
|
CHECK_TRUE(value.add(3));
|
||||||
|
CHECK_TRUE(value.is_stable());
|
||||||
|
CHECK_FALSE(value.has_changed());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
@ -3539,6 +3539,7 @@
|
|||||||
<ClInclude Include="..\..\include\etl\crc8_opensafety.h" />
|
<ClInclude Include="..\..\include\etl\crc8_opensafety.h" />
|
||||||
<ClInclude Include="..\..\include\etl\crc8_rohc.h" />
|
<ClInclude Include="..\..\include\etl\crc8_rohc.h" />
|
||||||
<ClInclude Include="..\..\include\etl\crc8_wcdma.h" />
|
<ClInclude Include="..\..\include\etl\crc8_wcdma.h" />
|
||||||
|
<ClInclude Include="..\..\include\etl\debounce_value.h" />
|
||||||
<ClInclude Include="..\..\include\etl\delegate_observable.h" />
|
<ClInclude Include="..\..\include\etl\delegate_observable.h" />
|
||||||
<ClInclude Include="..\..\include\etl\expected.h" />
|
<ClInclude Include="..\..\include\etl\expected.h" />
|
||||||
<ClInclude Include="..\..\include\etl\format.h" />
|
<ClInclude Include="..\..\include\etl\format.h" />
|
||||||
@ -3564,6 +3565,7 @@
|
|||||||
<ClInclude Include="..\..\include\etl\math.h" />
|
<ClInclude Include="..\..\include\etl\math.h" />
|
||||||
<ClInclude Include="..\..\include\etl\message_broker.h" />
|
<ClInclude Include="..\..\include\etl\message_broker.h" />
|
||||||
<ClInclude Include="..\..\include\etl\monostate.h" />
|
<ClInclude Include="..\..\include\etl\monostate.h" />
|
||||||
|
<ClInclude Include="..\..\include\etl\notification.h" />
|
||||||
<ClInclude Include="..\..\include\etl\not_null.h" />
|
<ClInclude Include="..\..\include\etl\not_null.h" />
|
||||||
<ClInclude Include="..\..\include\etl\poly_span.h" />
|
<ClInclude Include="..\..\include\etl\poly_span.h" />
|
||||||
<ClInclude Include="..\..\include\etl\print.h" />
|
<ClInclude Include="..\..\include\etl\print.h" />
|
||||||
@ -10390,6 +10392,7 @@
|
|||||||
<ClCompile Include="..\test_crc8_opensafety.cpp" />
|
<ClCompile Include="..\test_crc8_opensafety.cpp" />
|
||||||
<ClCompile Include="..\test_crc8_rohc.cpp" />
|
<ClCompile Include="..\test_crc8_rohc.cpp" />
|
||||||
<ClCompile Include="..\test_crc8_wcdma.cpp" />
|
<ClCompile Include="..\test_crc8_wcdma.cpp" />
|
||||||
|
<ClCompile Include="..\test_debounce_value.cpp" />
|
||||||
<ClCompile Include="..\test_delegate_observable.cpp" />
|
<ClCompile Include="..\test_delegate_observable.cpp" />
|
||||||
<ClCompile Include="..\test_etl_assert.cpp" />
|
<ClCompile Include="..\test_etl_assert.cpp" />
|
||||||
<ClCompile Include="..\test_expected.cpp" />
|
<ClCompile Include="..\test_expected.cpp" />
|
||||||
@ -10408,6 +10411,7 @@
|
|||||||
<ClCompile Include="..\test_math_functions.cpp" />
|
<ClCompile Include="..\test_math_functions.cpp" />
|
||||||
<ClCompile Include="..\test_message.cpp" />
|
<ClCompile Include="..\test_message.cpp" />
|
||||||
<ClCompile Include="..\test_message_broker.cpp" />
|
<ClCompile Include="..\test_message_broker.cpp" />
|
||||||
|
<ClCompile Include="..\test_notification.cpp" />
|
||||||
<ClCompile Include="..\test_not_null_pointer.cpp" />
|
<ClCompile Include="..\test_not_null_pointer.cpp" />
|
||||||
<ClCompile Include="..\test_not_null_pointer_constexpr.cpp" />
|
<ClCompile Include="..\test_not_null_pointer_constexpr.cpp" />
|
||||||
<ClCompile Include="..\test_not_null_unique_pointer.cpp" />
|
<ClCompile Include="..\test_not_null_unique_pointer.cpp" />
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user