未验证 提交 68a0ab21 编写于 作者: R Raf (Raffaele Rialdi) 提交者: GitHub

Debouncing implementation and test (#1720)

* Debouncing implementation and test

* Changed debounceTime parameter as optional in ButtonBase

* Debounce argument check
Renamed private variable

* Longer interval during test

* Fixing test max debounce time
上级 82cb8e88
......@@ -19,6 +19,8 @@ namespace Iot.Device.Button
private long _doublePressTicks;
private long _holdingMs;
private TimeSpan _debounceTime;
private long _debounceStartTicks;
private ButtonHoldingState _holdingState = ButtonHoldingState.Completed;
......@@ -78,10 +80,17 @@ namespace Iot.Device.Button
/// </summary>
/// <param name="doublePress">Max ticks between button presses to count as doublepress.</param>
/// <param name="holding">Min ms a button is pressed to count as holding.</param>
public ButtonBase(TimeSpan doublePress, TimeSpan holding)
/// <param name="debounceTime">The amount of time during which the transitions are ignored, or zero</param>
public ButtonBase(TimeSpan doublePress, TimeSpan holding, TimeSpan debounceTime = default(TimeSpan))
{
if (debounceTime.TotalMilliseconds * 3 > doublePress.TotalMilliseconds)
{
throw new ArgumentException($"The parameter {nameof(doublePress)} should be at least three times {nameof(debounceTime)}");
}
_doublePressTicks = doublePress.Ticks;
_holdingMs = (long)holding.TotalMilliseconds;
_debounceTime = debounceTime;
}
/// <summary>
......@@ -89,6 +98,11 @@ namespace Iot.Device.Button
/// </summary>
protected void HandleButtonPressed()
{
if (DateTime.UtcNow.Ticks - _debounceStartTicks < _debounceTime.Ticks)
{
return;
}
IsPressed = true;
ButtonDown?.Invoke(this, new EventArgs());
......@@ -104,6 +118,12 @@ namespace Iot.Device.Button
/// </summary>
protected void HandleButtonReleased()
{
if (_debounceTime.Ticks > 0 && !IsPressed)
{
return;
}
_debounceStartTicks = DateTime.UtcNow.Ticks;
_holdingTimer?.Dispose();
_holdingTimer = null;
......
......@@ -14,6 +14,7 @@ namespace Iot.Device.Button
{
private GpioController _gpioController;
private PinMode _pinMode;
private TimeSpan _debounceTime;
private int _buttonPin;
private bool _shouldDispose;
......@@ -27,8 +28,10 @@ namespace Iot.Device.Button
/// <param name="pinMode">Pin mode of the system.</param>
/// <param name="gpio">Gpio Controller.</param>
/// <param name="shouldDispose">True to dispose the GpioController.</param>
public GpioButton(int buttonPin, GpioController? gpio = null, bool shouldDispose = true, PinMode pinMode = PinMode.InputPullUp)
: this(buttonPin, TimeSpan.FromTicks(DefaultDoublePressTicks), TimeSpan.FromMilliseconds(DefaultHoldingMilliseconds), gpio, shouldDispose, pinMode)
/// <param name="debounceTime">The amount of time during which the transitions are ignored, or zero</param>
public GpioButton(int buttonPin, GpioController? gpio = null, bool shouldDispose = true, PinMode pinMode = PinMode.InputPullUp,
TimeSpan debounceTime = default(TimeSpan))
: this(buttonPin, TimeSpan.FromTicks(DefaultDoublePressTicks), TimeSpan.FromMilliseconds(DefaultHoldingMilliseconds), gpio, shouldDispose, pinMode, debounceTime)
{
}
......@@ -41,13 +44,15 @@ namespace Iot.Device.Button
/// <param name="holding">Min ms a button is pressed to count as holding.</param>
/// <param name="gpio">Gpio Controller.</param>
/// <param name="shouldDispose">True to dispose the GpioController.</param>
public GpioButton(int buttonPin, TimeSpan doublePress, TimeSpan holding, GpioController? gpio = null, bool shouldDispose = true, PinMode pinMode = PinMode.InputPullUp)
: base(doublePress, holding)
/// <param name="debounceTime">The amount of time during which the transitions are ignored, or zero</param>
public GpioButton(int buttonPin, TimeSpan doublePress, TimeSpan holding, GpioController? gpio = null, bool shouldDispose = true, PinMode pinMode = PinMode.InputPullUp, TimeSpan debounceTime = default(TimeSpan))
: base(doublePress, holding, debounceTime)
{
_gpioController = gpio ?? new GpioController();
_shouldDispose = shouldDispose;
_buttonPin = buttonPin;
_pinMode = pinMode;
_debounceTime = debounceTime;
if (_pinMode == PinMode.Input | _pinMode == PinMode.InputPullDown | _pinMode == PinMode.InputPullUp)
{
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Threading;
using Xunit;
namespace Iot.Device.Button.Tests
......@@ -245,5 +247,46 @@ namespace Iot.Device.Button.Tests
Assert.False(pressed);
}
[Fact]
public void If_Button_Is_Pressed_Too_Fast_Debouncing_Removes_Events()
{
bool holding = false;
bool doublePressed = false;
int pressedCounter = 0;
TestButton button = new TestButton(TimeSpan.FromMilliseconds(1000));
button.Press += (sender, e) =>
{
pressedCounter++;
};
button.Holding += (sender, e) =>
{
holding = true;
};
button.DoublePress += (sender, e) =>
{
doublePressed = true;
};
button.PressButton();
button.ReleaseButton();
button.PressButton();
button.ReleaseButton();
button.PressButton();
button.ReleaseButton();
button.PressButton();
button.ReleaseButton();
button.PressButton();
button.ReleaseButton();
Assert.Equal(1, pressedCounter);
Assert.False(holding);
Assert.False(doublePressed);
}
}
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
namespace Iot.Device.Button.Tests
{
public class TestButton : ButtonBase
......@@ -10,6 +12,11 @@ namespace Iot.Device.Button.Tests
{
}
public TestButton(TimeSpan debounceTime)
: base(TimeSpan.FromSeconds(5), TimeSpan.FromMilliseconds(2000), debounceTime)
{
}
public void PressButton()
{
HandleButtonPressed();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册