From 016dacada73f55f5e318efb05e7af0052604e5f7 Mon Sep 17 00:00:00 2001 From: makuo12 Date: Wed, 15 Jan 2025 20:14:00 +0100 Subject: [PATCH 1/2] adding struct for 4x4 matrix --- Cargo.lock | 41 ++++++++++++ src/keypad_4x4.rs | 155 ++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 40 ++---------- src/utils.rs | 43 +++++++++++++ 4 files changed, 243 insertions(+), 36 deletions(-) create mode 100644 Cargo.lock create mode 100644 src/keypad_4x4.rs create mode 100644 src/utils.rs diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..5662fc4 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,41 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "embedded-hal" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" +dependencies = [ + "nb 0.1.3", + "void", +] + +[[package]] +name = "keypad2" +version = "0.1.0" +dependencies = [ + "embedded-hal", +] + +[[package]] +name = "nb" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" +dependencies = [ + "nb 1.1.0", +] + +[[package]] +name = "nb" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" diff --git a/src/keypad_4x4.rs b/src/keypad_4x4.rs new file mode 100644 index 0000000..1f67233 --- /dev/null +++ b/src/keypad_4x4.rs @@ -0,0 +1,155 @@ + +/*! +# Platform-agnostic driver for 4X4 numeric keypads + +Provides a driver for reading from standard 4X4 keypads + +## Example + +```rust +let rows = ( + gpiob.pb15.into_pull_up_input(&mut gpiob.crh), + gpioa.pa7.into_pull_up_input(&mut gpioa.crl), + gpiob.pb6.into_pull_up_input(&mut gpiob.crl), + gpioa.pa9.into_pull_up_input(&mut gpioa.crh), +); + +let cols = ( + gpioa.pa8.into_open_drain_output(&mut gpioa.crh), + gpiob.pb5.into_open_drain_output(&mut gpiob.crl), + gpioc.pc7.into_open_drain_output(&mut gpioc.crl), + gpioc.pc6.into_open_drain_output(&mut gpioc.crl), +); + +let mut keypad = Keypad::new(rows, cols); + +let key = keypad.read_char(&mut delay); +if key != ' ' { + ... +} +``` +*/ +use embedded_hal::digital::v2::{InputPin, OutputPin}; +use embedded_hal::blocking::delay::DelayMs; + +use crate::utils::convert; +/// Defines a type that makes it easier to supply the four pins required for rows in the keypad. +/// These pins need to support the `embedded_hal::digital::v2::InputPin` trait +pub type Rows = (R0, R1, R2, R3); + +/// Defines a type that makes it easier to supply the four pins required for rows in the keypad +/// These pins need to support the `embedded_hal::digital::v2::OutputPin` trait +pub type Columns = (C0, C1, C2, C3); + +/// Manages the pins and the logic for scanning a keypad +pub struct Keypad4x4< + R0: InputPin, + R1: InputPin, + R2: InputPin, + R3: InputPin, + C0: OutputPin, + C1: OutputPin, + C2: OutputPin, + C3: OutputPin, +> { + rows: Rows, + columns: Columns, +} + +impl< + R0: InputPin, + R1: InputPin, + R2: InputPin, + R3: InputPin, + C0: OutputPin, + C1: OutputPin, + C2: OutputPin, + C3: OutputPin, + > Keypad4x4 +{ + /// Create a new instance of this structure + pub fn new(rows: Rows, columns: Columns) -> Self { + Self { rows, columns } + } + + /** + Reads a character from the keypad. This method returns even if no keys are pressed. + It will return: + + * `'0'` through `'9'` + * `'*'` + * `'#'` + * `' '` if no keys are pressed. + */ + pub fn read_char(&mut self, delay: &mut dyn DelayMs) -> char { + let raw = self.read(delay); + if raw != 0 { + self.get_char(raw) + } else { + ' ' + } + } + + // Performs a "raw" read of the keypad and returns a bit set for each key down. Note, + // this doesn't mean this code supports multiple key presses. + fn read(&mut self, delay: &mut dyn DelayMs) -> u16 { + let mut res = 0; + + self.columns.0.set_low().unwrap_or_default(); + res |= self.read_column(delay) << 0; + self.columns.0.set_high().unwrap_or_default(); + + self.columns.1.set_low().unwrap_or_default(); + res |= self.read_column(delay) << 4; + self.columns.1.set_high().unwrap_or_default(); + + self.columns.2.set_low().unwrap_or_default(); + res |= self.read_column(delay) << 8; + self.columns.2.set_high().unwrap_or_default(); + self.columns.3.set_low().unwrap_or_default(); + res |= self.read_column(delay) << 12; + self.columns.3.set_high().unwrap_or_default(); + res + } + + // Converts the raw value from the read() method into a character that corresponds to the + // label on each key + fn get_char(&self, raw_value: u16) -> char { + let value = convert(raw_value); + match value { + -1 => '*', + -2 => '#', + -3 => 'A', + -4 => 'B', + -5 => 'C', + -6 => 'D', + _ => char::from_digit(value as u32, 10).unwrap(), + } + } + + fn read_column(&self, delay: &mut dyn DelayMs) -> u16 { + let mut res = 0; + + delay.delay_ms(1u16); + if self.rows.0.is_low().unwrap_or_default() { + res |= 1 << 0; + } + if self.rows.1.is_low().unwrap_or_default() { + res |= 1 << 1; + } + if self.rows.2.is_low().unwrap_or_default() { + res |= 1 << 2; + } + if self.rows.3.is_low().unwrap_or_default() { + res |= 1 << 3; + } + + res + } + + // Converts the raw value (2^N) from the read() method into a keypad digit. This will be + // 0..9 digits + // -1 * + // -2 # + // -3 A +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index fd4604d..dd83284 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,9 +28,12 @@ if key != ' ' { ``` */ #![no_std] +pub mod keypad_4x4; +pub mod utils; use embedded_hal::digital::v2::{InputPin, OutputPin}; use embedded_hal::blocking::delay::DelayMs; +use utils::convert; /// Defines a type that makes it easier to supply the four pins required for rows in the keypad. /// These pins need to support the `embedded_hal::digital::v2::InputPin` trait @@ -110,7 +113,7 @@ impl< // Converts the raw value from the read() method into a character that corresponds to the // label on each key fn get_char(&self, raw_value: u16) -> char { - let value = self.convert(raw_value); + let value = convert(raw_value); match value { -1 => '*', -2 => '#', @@ -137,39 +140,4 @@ impl< res } - - // Converts the raw value (2^N) from the read() method into a keypad digit. This will be - // 0..9 digits - // -1 * - // -2 # - pub fn convert(&self, value: u16) -> i16 { - match value { - KEY_1 => 1, - KEY_4 => 4, - KEY_7 => 7, - KEY_STAR => -1, - KEY_2 => 2, - KEY_5 => 5, - KEY_8 => 8, - KEY_0 => 0, - KEY_3 => 3, - KEY_6 => 6, - KEY_9 => 9, - KEY_HASH => -2, - _ => -10, - } - } } - -const KEY_1: u16 = 1; -const KEY_4: u16 = 1 << 1; -const KEY_7: u16 = 1 << 2; -const KEY_STAR: u16 = 1 << 3; -const KEY_2: u16 = 1 << 4; -const KEY_5: u16 = 1 << 5; -const KEY_8: u16 = 1 << 6; -const KEY_0: u16 = 1 << 7; -const KEY_3: u16 = 1 << 8; -const KEY_6: u16 = 1 << 9; -const KEY_9: u16 = 1 << 10; -const KEY_HASH: u16 = 1 << 11; diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..ae14702 --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,43 @@ +// Converts the raw value (2^N) from the read() method into a keypad digit. This will be +// 0..9 digits +// -1 * +// -2 # + +pub(crate) fn convert(value: u16) -> i16 { + match value { + KEY_1 => 1, + KEY_4 => 4, + KEY_7 => 7, + KEY_STAR => -1, + KEY_2 => 2, + KEY_5 => 5, + KEY_8 => 8, + KEY_0 => 0, + KEY_3 => 3, + KEY_6 => 6, + KEY_9 => 9, + KEY_HASH => -2, + KEY_A => -3, + KEY_B => -4, + KEY_C => -5, + KEY_D => -6, + _ => -10 + } +} + +const KEY_1: u16 = 1; +const KEY_4: u16 = 1 << 1; +const KEY_7: u16 = 1 << 2; +const KEY_STAR: u16 = 1 << 3; +const KEY_2: u16 = 1 << 4; +const KEY_5: u16 = 1 << 5; +const KEY_8: u16 = 1 << 6; +const KEY_0: u16 = 1 << 7; +const KEY_3: u16 = 1 << 8; +const KEY_6: u16 = 1 << 9; +const KEY_9: u16 = 1 << 10; +const KEY_HASH: u16 = 1 << 11; +const KEY_A: u16 = 1 << 12; +const KEY_B: u16 = 1 << 13; +const KEY_C: u16 = 1 << 14; +const KEY_D: u16 = 1 << 15; \ No newline at end of file From d2fbca4b6dcd8c3fee5b01bfc1f54d08ef5b32d2 Mon Sep 17 00:00:00 2001 From: makuo12 Date: Tue, 28 Jan 2025 17:47:35 +0100 Subject: [PATCH 2/2] updated the embedded-hal to 1.0.0 --- Cargo.lock | 31 +++---------------------------- Cargo.toml | 2 +- src/keypad_4x4.rs | 12 ++++++------ src/lib.rs | 12 ++++++------ 4 files changed, 16 insertions(+), 41 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5662fc4..9222667 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,16 +1,12 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "embedded-hal" -version = "0.2.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" -dependencies = [ - "nb 0.1.3", - "void", -] +checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" [[package]] name = "keypad2" @@ -18,24 +14,3 @@ version = "0.1.0" dependencies = [ "embedded-hal", ] - -[[package]] -name = "nb" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" -dependencies = [ - "nb 1.1.0", -] - -[[package]] -name = "nb" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" - -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" diff --git a/Cargo.toml b/Cargo.toml index ab1702f..4d4a6b0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,4 +13,4 @@ authors = ["John Socha-Leialoha"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -embedded-hal = { version = "^0.2.4", features = ["unproven"] } +embedded-hal = { version = "1.0.0" } diff --git a/src/keypad_4x4.rs b/src/keypad_4x4.rs index 1f67233..3207463 100644 --- a/src/keypad_4x4.rs +++ b/src/keypad_4x4.rs @@ -29,8 +29,8 @@ if key != ' ' { } ``` */ -use embedded_hal::digital::v2::{InputPin, OutputPin}; -use embedded_hal::blocking::delay::DelayMs; +use embedded_hal::digital::{InputPin, OutputPin}; +use embedded_hal::delay::DelayNs; use crate::utils::convert; /// Defines a type that makes it easier to supply the four pins required for rows in the keypad. @@ -81,7 +81,7 @@ impl< * `'#'` * `' '` if no keys are pressed. */ - pub fn read_char(&mut self, delay: &mut dyn DelayMs) -> char { + pub fn read_char(&mut self, delay: &mut dyn DelayNs) -> char { let raw = self.read(delay); if raw != 0 { self.get_char(raw) @@ -92,7 +92,7 @@ impl< // Performs a "raw" read of the keypad and returns a bit set for each key down. Note, // this doesn't mean this code supports multiple key presses. - fn read(&mut self, delay: &mut dyn DelayMs) -> u16 { + fn read(&mut self, delay: &mut dyn DelayNs) -> u16 { let mut res = 0; self.columns.0.set_low().unwrap_or_default(); @@ -127,10 +127,10 @@ impl< } } - fn read_column(&self, delay: &mut dyn DelayMs) -> u16 { + fn read_column(&mut self, delay: &mut dyn DelayNs) -> u16 { let mut res = 0; - delay.delay_ms(1u16); + delay.delay_ms(1u32); if self.rows.0.is_low().unwrap_or_default() { res |= 1 << 0; } diff --git a/src/lib.rs b/src/lib.rs index dd83284..d6b7a75 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,8 +31,8 @@ if key != ' ' { pub mod keypad_4x4; pub mod utils; -use embedded_hal::digital::v2::{InputPin, OutputPin}; -use embedded_hal::blocking::delay::DelayMs; +use embedded_hal::digital::{InputPin, OutputPin}; +use embedded_hal::delay::DelayNs; use utils::convert; /// Defines a type that makes it easier to supply the four pins required for rows in the keypad. @@ -81,7 +81,7 @@ impl< * `'#'` * `' '` if no keys are pressed. */ - pub fn read_char(&mut self, delay: &mut dyn DelayMs) -> char { + pub fn read_char(&mut self, delay: &mut dyn DelayNs) -> char { let raw = self.read(delay); if raw != 0 { self.get_char(raw) @@ -92,7 +92,7 @@ impl< // Performs a "raw" read of the keypad and returns a bit set for each key down. Note, // this doesn't mean this code supports multiple key presses. - fn read(&mut self, delay: &mut dyn DelayMs) -> u16 { + fn read(&mut self, delay: &mut dyn DelayNs) -> u16 { let mut res = 0; self.columns.0.set_low().unwrap_or_default(); @@ -121,10 +121,10 @@ impl< } } - fn read_column(&self, delay: &mut dyn DelayMs) -> u16 { + fn read_column(&mut self, delay: &mut dyn DelayNs) -> u16 { let mut res = 0; - delay.delay_ms(1u16); + delay.delay_ms(1u32); if self.rows.0.is_low().unwrap_or_default() { res |= 1 << 0; }