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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
use super::hal;

use cortex_m::asm::delay as cycle_delay;
use gpio::{Floating, Input, Output, PushPull};
use hal::gpio::{self, *};
use hal::prelude::*;

#[derive(Debug, PartialEq)]
pub enum Keys {
    SelectDown,
    SelectUp,
    StartDown,
    StartUp,
    BDown,
    BUp,
    ADown,
    AUp,
}

pub struct ButtonIter {
    pub pressed: u8,
    pub released: u8,
    pub bit_index: u8,
}

//should be impossible for released and pressed, but gives released preference
fn mask_to_event(mask: u8, released: u8, pressed: u8) -> Option<Keys> {
    let pressed_bool = mask & pressed == mask;
    let released_bool = mask & released == mask;

    match mask {
        0x8 => {
            if released_bool {
                Some(Keys::BUp)
            } else if pressed_bool {
                Some(Keys::BDown)
            } else {
                None
            }
        }
        0x4 => {
            if released_bool {
                Some(Keys::AUp)
            } else if pressed_bool {
                Some(Keys::ADown)
            } else {
                None
            }
        }
        0x2 => {
            if released_bool {
                Some(Keys::StartUp)
            } else if pressed_bool {
                Some(Keys::StartDown)
            } else {
                None
            }
        }
        0x1 => {
            if released_bool {
                Some(Keys::SelectUp)
            } else if pressed_bool {
                Some(Keys::SelectDown)
            } else {
                None
            }
        }
        _ => None,
    }
}

impl Iterator for ButtonIter {
    type Item = Keys;

    fn next(&mut self) -> Option<Keys> {
        //really want a while post increment but doesnt exist
        //only 4 buttons represented in the shift
        if self.bit_index >= 4 {
            return None;
        }

        //funky do while
        while {
            let mask = 0x01 << self.bit_index;
            self.bit_index += 1;

            let event = mask_to_event(mask, self.released, self.pressed);
            if event.is_some() {
                return event;
            }

            self.bit_index < 4
        } {}

        None
    }
}

/// Button pins

pub struct ButtonReader {
    /// Button Latch
    pub latch: Pb0<Output<PushPull>>,
    /// Button Out
    pub data_in: Pb30<Input<Floating>>,
    /// Button Clock
    pub clock: Pb31<Output<PushPull>>,
    pub last: u8,
}

//120mhz, 1 cycle = 0.000000008333333 = 8.333333ns
//https://www.onsemi.com/pub/Collateral/MC74HC165A-D.PDF
//3v <=125c
//tsu min setup time 55ns = 7 cycles
//th min hold time 5ns = 1 cycles
//tw min pulse width 36ns = 5 cycles
//trec min recovery time 55ns, how long before you should attempt to read
// again?

impl ButtonReader {
    // 28*8.333ns total blocking read
    /// Returns a ButtonIter of button changes as Keys enums
    pub fn events(&mut self) -> ButtonIter {
        self.latch.set_low().ok();
        cycle_delay(7); //tsu?
        self.latch.set_high().ok();
        cycle_delay(1); //th?

        let mut current: u8 = 0;

        // they only use the top 4 bits
        for _i in 0..4 {
            current <<= 1;

            self.clock.set_low().ok();
            cycle_delay(5); //tw

            if self.data_in.is_high().unwrap() {
                current |= 1;
            }
            self.clock.set_high().ok();
        }

        let iter = ButtonIter {
            pressed: (self.last ^ current) & current,
            released: (self.last ^ current) & self.last,
            bit_index: 0,
        };

        self.last = current;

        iter
    }
}