pybadge_high/
buttons.rs

1use super::hal;
2
3use cortex_m::asm::delay as cycle_delay;
4use gpio::v2::{Floating, Input, Output, PushPull};
5use hal::{
6	gpio::{self, *},
7	prelude::*
8};
9use num_enum::TryFromPrimitive;
10
11#[repr(u8)]
12#[derive(Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive)]
13/// There are 8 buttons on the front: A, B, Select, Start and four arranged in a d-pad.
14///
15/// ![🖼️](https://cdn-learn.adafruit.com/assets/assets/000/075/106/original/adafruit_products_PyBadge_Top_Buttons.jpg)
16pub enum Button {
17	B = 1 << 7,
18	A = 1 << 6,
19	Start = 1 << 5,
20	Sesect = 1 << 4,
21	Right = 1 << 3,
22	Down = 1 << 2,
23	Up = 1 << 1,
24	Left = 1
25}
26
27/// Button status changes.
28
29#[derive(Clone, Debug, Eq, PartialEq)]
30pub enum Event {
31	Pressed(Button),
32	Released(Button)
33}
34
35pub struct EventIter<'a> {
36	postion: u8,
37	buttons: &'a Buttons,
38	update_postions: u8
39}
40
41impl<'a> Iterator for EventIter<'a> {
42	type Item = Event;
43	fn next(&mut self) -> Option<Self::Item> {
44		for i in self.postion..8 {
45			let mask = 1 << i;
46			//check if state was changed
47			if mask & self.update_postions != 0 {
48				self.postion = i + 1;
49				//mask is always an valid Button value
50				let button = Button::try_from(mask).unwrap();
51				if self.buttons.button_pressed(button) {
52					return Some(Event::Pressed(button));
53				} else {
54					return Some(Event::Released(button));
55				}
56			}
57		}
58		None
59	}
60}
61
62/// Store the state of the Buttons.
63///
64/// The [`Button`]s do not connect to GPIO pins directly.
65/// Instead they connect to an 8-channel shift register to save pins.
66/// This result thate they must be manual updated by calling [`.update()`](Self::update)
67/// and can not be acess directly.
68pub struct Buttons {
69	pub(crate) current_state: u8,
70	pub(crate) last_state: u8,
71	pub(crate) latch: Pb0<Output<PushPull>>,
72	/// Button Out
73	pub(crate) data_in: Pb30<Input<Floating>>,
74	/// Button Clock
75	pub(crate) clock: Pb31<Output<PushPull>>
76}
77
78impl Buttons {
79	/// Check if some key is pressed.
80	pub fn some_pressed(&self) -> bool {
81		self.current_state != 0
82	}
83
84	/// Check if none key is pressed
85	pub fn none_pressed(&self) -> bool {
86		self.current_state == 0
87	}
88
89	/// Check if a button is pressed
90	pub fn button_pressed(&self, button: Button) -> bool {
91		self.current_state & button as u8 != 0
92	}
93
94	pub fn a_pressed(&self) -> bool {
95		self.button_pressed(Button::A)
96	}
97
98	pub fn b_pressed(&self) -> bool {
99		self.button_pressed(Button::B)
100	}
101
102	pub fn start_pressed(&self) -> bool {
103		self.button_pressed(Button::Start)
104	}
105
106	pub fn select_pressed(&self) -> bool {
107		self.button_pressed(Button::Sesect)
108	}
109
110	pub fn right_pressed(&self) -> bool {
111		self.button_pressed(Button::Right)
112	}
113
114	pub fn down_pressed(&self) -> bool {
115		self.button_pressed(Button::Down)
116	}
117
118	pub fn up_pressed(&self) -> bool {
119		self.button_pressed(Button::Up)
120	}
121
122	pub fn left_pressed(&self) -> bool {
123		self.button_pressed(Button::Left)
124	}
125
126	/// Iterator over alle [`Event`]s (Button status changes) occured between the last and penultimate update.
127	///
128	/// This does only include the changes of Buttons!
129	/// For example if a button was pressed at the penultimate update und is still pressed at the last update,
130	/// the iterator does skip the button.
131	pub fn events(&self) -> EventIter {
132		EventIter {
133			postion: 0,
134			buttons: self,
135			update_postions: self.current_state ^ self.last_state
136		}
137	}
138
139	//Returns a ButtonIter of button changes as Keys enums
140	//pub fn event(&self) {}
141
142	/// Update the state of the buttons.
143	/// 400ns total blocking read.
144	//
145	//based on https://github.com/atsamd-rs/atsamd/blob/master/boards/pygamer/src/buttons.rs
146	//120mhz, 1 cycle = 0.000000008333333 = 8.333333ns
147	//https://www.onsemi.com/pub/Collateral/MC74HC165A-D.PDF
148	//3v <=125c
149	//tsu min setup time 55ns = 7 cycles
150	//th min hold time 5ns = 1 cycles
151	//tw min pulse width 36ns = 5 cycles
152	//trec min recovery time 55ns, how long before you should attempt to read
153	// again?
154	pub fn update(&mut self) {
155		// 48*8.333ns total blocking read
156		self.latch.set_low().ok();
157		cycle_delay(7); //tsu?
158		self.latch.set_high().ok();
159		cycle_delay(1); //th?
160		let mut current: u8 = 0;
161
162		// they only use the top 8 bits
163		for _ in 0..8 {
164			current <<= 1;
165
166			self.clock.set_low().ok();
167			cycle_delay(5); //tw
168
169			if self.data_in.is_high().unwrap() {
170				current |= 1;
171			}
172			self.clock.set_high().ok();
173		}
174
175		self.last_state = self.current_state;
176		self.current_state = current;
177	}
178}