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
110
111
112
113
114
115
116
117
118
119
120
121
122
//! High-level driver for two buttons together.

use crate::buttons::core::{PollButton, TransitionEvent};

/// An event from this module's [`Monitor`].
#[derive(PartialEq, Eq, Debug)]
pub enum Event {
    ClickA,
    ClickB,
    ClickAB,
}

// The event-generation rules and internal state for Monitor.
//
// Promises that consecutive calls to handle() for different buttons don't
// both return Some.
struct MonitorState {
    seen_both: bool,
}

impl MonitorState {
    fn new() -> MonitorState {
        MonitorState {
            seen_both: false,
        }
    }

    // Handles a single poll result.
    //
    // The event parameter is the event being processed.
    //
    // The click_event parameter is the event to generate for this button, if
    // this is a release in a single-button 'transaction'.
    fn handle(
        &mut self,
        event: TransitionEvent,
        other_button_is_pressed: bool,
        click_event: Event,
    ) -> Option<Event> {
        match event {
            TransitionEvent::Press => {
                self.seen_both = other_button_is_pressed;
            }
            TransitionEvent::Release => {
                if self.seen_both {
                    if !other_button_is_pressed {
                        return Some(Event::ClickAB);
                    }
                } else {
                    return Some(click_event);
                }
            }
        };
        None
    }
}


/// Wrapper for two [`PollButton`]s generating click events on release.
///
/// The buttons don't have to be the micro:bit's built-in buttons, though the
/// generated [`Event`]s include 'A' and 'B' in their names.
pub struct Monitor<A: PollButton, B: PollButton> {
    button_a: A,
    button_b: B,
    state: MonitorState,
}

impl<A: PollButton, B: PollButton> Monitor<A, B> {
    /// Takes ownership of two [`PollButton`]s and returns a `Monitor`.
    pub fn new(button_a: A, button_b: B) -> Monitor<A, B> {
        Monitor {
            button_a,
            button_b,
            state: MonitorState::new(),
        }
    }

    /// Gives the underlying [`PollButton`] instances back.
    pub fn free(self) -> (A, B) {
        (self.button_a, self.button_b)
    }

    fn poll_a(&mut self) -> Option<Event> {
        self.button_a.poll_event()
            .and_then(|event| {
                self.state.handle(
                    event,
                    self.button_b.is_pressed(),
                    Event::ClickA,
                )})
    }

    fn poll_b(&mut self) -> Option<Event> {
        self.button_b.poll_event()
            .and_then(|event| {
                self.state.handle(
                    event,
                    self.button_a.is_pressed(),
                    Event::ClickB,
                )})
    }

    /// Polls both buttons and filters for events.
    ///
    /// If both buttons have been pressed, returns `Some(ClickAB)` when the
    /// second one is released.
    ///
    /// Otherwise, returns `Some(ClickA)` if the first button was released or
    /// `Some(ClickB)` if the second button was released.
    ///
    /// Otherwise returns `None`.
    pub fn poll(&mut self) -> Option<Event> {
        let event_a = self.poll_a();
        let event_b = self.poll_b();
        // MonitorState promises this
        assert!(event_a.is_none() || event_b.is_none());
        event_a.or(event_b)
    }

}