1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
//! Support for detecting button 'hold' events.
//!
//! This is part of the implementation of the [`single_with_hold`] and
//! [`dual_with_hold`] button monitors, public so that it's possible to make
//! variants with different timings.
//!
//! [`single_with_hold`]: crate::buttons::monitors::single_with_hold
//! [`dual_with_hold`]: crate::buttons::monitors::dual_with_hold

use core::ops::AddAssign;
use crate::buttons::core::Transition;

/// Description of the number of ticks to treat as a 'hold'.
pub trait HoldDescriptor: {
    /// Integer type wide enough to hold the tick count
    type width: PartialOrd + AddAssign + Copy;
    /// Zero of the `width` type
    const HOLD_START: Self::width;
    /// One of the `width` type
    const HOLD_INCREMENT: Self::width;
    /// The number of ticks
    const HOLD_TICKS: Self::width;
}

/// The default `HoldDescriptor`.
///
/// Represents 250 ticks (which is 1.5s for 6ms ticks).
pub struct DefaultHoldDescriptor ();

impl HoldDescriptor for DefaultHoldDescriptor {
    type width = u8;
    const HOLD_START: u8 = 0;
    const HOLD_INCREMENT: u8 = 1;
    const HOLD_TICKS: u8 = 250;
}



/// Variant of [`TransitionEvent`] with an additional `Hold`
/// event.
///
/// [`TransitionEvent`]: crate::buttons::core::TransitionEvent
#[derive(Debug)]
pub enum Event {
    Press,
    Release,
    Hold,
}

/// A hold-detection algorithm and associated state.
#[derive(Debug)]
pub struct HoldAnnotator<T: HoldDescriptor> {
    counter: T::width,
}

impl<T: HoldDescriptor> HoldAnnotator<T> {

    /// Returns a new `HoldAnnotator`.
    pub fn new() -> HoldAnnotator<T> {
        HoldAnnotator { counter: T::HOLD_START }
    }

    /// Convert the result of a button poll to an event.
    ///
    /// Returns [events] similar to those from [`PollButton::poll_event`], but
    /// with `Hold` as possibility as well as `Press` and `Release`.
    ///
    /// If the button has been down for longer than `HOLD_TICKS`, immediately
    /// reports `Hold`, and reports no event when the button is next released.
    ///
    /// See [`DefaultHoldDescriptor`] for the default `HOLD_TICKS`.
    ///
    /// # Example
    /// ```ignore
    /// match hold_annotator.annotate(button.poll_transition()) {
    ///     Some(holding::Event::Press) => ...,
    ///     Some(holding::Event::Release) => ...,
    ///     Some(holding::Event::Hold) => ...,
    ///     None => ...,
    /// }
    /// ```
    /// [events]: Event
    /// [`PollButton::poll_event`]: crate::buttons::core::PollButton::poll_event
    pub fn annotate(&mut self, transition: Transition)
                    -> Option<Event> {
        match transition {
            Transition {was_pressed: false, is_pressed: true} => {
                self.counter = T::HOLD_START;
                Some(Event::Press)
            },
            Transition {was_pressed: true, is_pressed: false} => {
                Some(Event::Release)
            },
            Transition {was_pressed: true, is_pressed: true} => {
                if self.counter <= T::HOLD_TICKS {
                    self.counter += T::HOLD_INCREMENT;
                }
                if self.counter == T::HOLD_TICKS {
                    Some(Event::Hold)
                } else {
                    None
                }
            },
            Transition {was_pressed: false, is_pressed: false} => None,
        }
    }

}