99 lines
3.1 KiB
Rust
99 lines
3.1 KiB
Rust
//! Project: CMtec CMDR joystick 24
|
|
//! Date: 2023-08-01
|
|
//! Author: Christoffer Martinsson
|
|
//! Email: cm@cmtec.se
|
|
//! License: Please refer to LICENSE in root directory
|
|
|
|
use core::convert::Infallible;
|
|
use cortex_m::delay::Delay;
|
|
use embedded_hal::digital::v2::*;
|
|
|
|
/// Button matrix driver
|
|
///
|
|
/// # Example
|
|
/// ```
|
|
/// let button_matrix: ButtonMatrix<4, 6, 48> = ButtonMatrix::new(row_pins, col_pins, 5);
|
|
/// ```
|
|
pub struct ButtonMatrix<'a, const R: usize, const C: usize, const N: usize> {
|
|
rows: &'a [&'a dyn InputPin<Error = Infallible>; R],
|
|
cols: &'a mut [&'a mut dyn OutputPin<Error = Infallible>; C],
|
|
pressed: [bool; N],
|
|
debounce: u8,
|
|
debounce_counter: [u8; N],
|
|
}
|
|
|
|
impl<'a, const R: usize, const C: usize, const N: usize> ButtonMatrix<'a, R, C, N> {
|
|
/// Creates a new button matrix.
|
|
///
|
|
/// # Arguments
|
|
///
|
|
/// * `rows` - An array of references to the row pins.
|
|
/// * `cols` - An array of references to the column pins.
|
|
/// * `debounce` - The debounce time in number of scans.
|
|
pub fn new(
|
|
rows: &'a [&'a dyn InputPin<Error = Infallible>; R],
|
|
cols: &'a mut [&'a mut dyn OutputPin<Error = Infallible>; C],
|
|
debounce: u8,
|
|
) -> Self {
|
|
Self {
|
|
rows,
|
|
cols,
|
|
pressed: [false; N],
|
|
debounce,
|
|
debounce_counter: [0; N],
|
|
}
|
|
}
|
|
|
|
/// Initializes the button matrix.
|
|
/// This should be called once before scanning the matrix.
|
|
pub fn init_pins(&mut self) {
|
|
for col in self.cols.iter_mut() {
|
|
col.set_high().unwrap();
|
|
}
|
|
}
|
|
|
|
/// Scans the button matrix and updates the pressed state of each button.
|
|
/// This should be called at regular intervals.
|
|
/// Allow at least 5 times the delay compared to the needed button latency.
|
|
///
|
|
/// # Arguments
|
|
///
|
|
/// * `delay` - A mutable reference to a delay object.
|
|
pub fn scan_matrix(&mut self, delay: &mut Delay) {
|
|
for col_index in 0..self.cols.len() {
|
|
self.cols[col_index].set_low().unwrap();
|
|
delay.delay_us(1);
|
|
self.process_column(col_index);
|
|
self.cols[col_index].set_high().unwrap();
|
|
delay.delay_us(1);
|
|
}
|
|
}
|
|
|
|
/// Processes a column of the button matrix.
|
|
///
|
|
/// # Arguments
|
|
///
|
|
/// * `col_index` - The index of the column to process.
|
|
fn process_column(&mut self, col_index: usize) {
|
|
for row_index in 0..self.rows.len() {
|
|
let button_index: usize = col_index + (row_index * C);
|
|
let current_state = self.rows[row_index].is_low().unwrap();
|
|
|
|
if current_state == self.pressed[button_index] {
|
|
self.debounce_counter[button_index] = 0;
|
|
continue;
|
|
}
|
|
|
|
self.debounce_counter[button_index] += 1;
|
|
if self.debounce_counter[button_index] >= self.debounce {
|
|
self.pressed[button_index] = current_state;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Returns an array of booleans indicating whether each button is pressed.
|
|
pub fn buttons_pressed(&mut self) -> [bool; N] {
|
|
self.pressed
|
|
}
|
|
}
|