mirror of
https://github.com/ETLCPP/etl.git
synced 2026-11-10 07:09:46 +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_rohc.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\expected.h" />
|
||||
<ClInclude Include="..\..\include\etl\format.h" />
|
||||
@ -3564,6 +3565,7 @@
|
||||
<ClInclude Include="..\..\include\etl\math.h" />
|
||||
<ClInclude Include="..\..\include\etl\message_broker.h" />
|
||||
<ClInclude Include="..\..\include\etl\monostate.h" />
|
||||
<ClInclude Include="..\..\include\etl\notification.h" />
|
||||
<ClInclude Include="..\..\include\etl\not_null.h" />
|
||||
<ClInclude Include="..\..\include\etl\poly_span.h" />
|
||||
<ClInclude Include="..\..\include\etl\print.h" />
|
||||
@ -10390,6 +10392,7 @@
|
||||
<ClCompile Include="..\test_crc8_opensafety.cpp" />
|
||||
<ClCompile Include="..\test_crc8_rohc.cpp" />
|
||||
<ClCompile Include="..\test_crc8_wcdma.cpp" />
|
||||
<ClCompile Include="..\test_debounce_value.cpp" />
|
||||
<ClCompile Include="..\test_delegate_observable.cpp" />
|
||||
<ClCompile Include="..\test_etl_assert.cpp" />
|
||||
<ClCompile Include="..\test_expected.cpp" />
|
||||
@ -10408,6 +10411,7 @@
|
||||
<ClCompile Include="..\test_math_functions.cpp" />
|
||||
<ClCompile Include="..\test_message.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_constexpr.cpp" />
|
||||
<ClCompile Include="..\test_not_null_unique_pointer.cpp" />
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user