From 5e537be5a3eaff8f5ea016ff7f65b80b42ec0221 Mon Sep 17 00:00:00 2001 From: sawyer bristol Date: Thu, 26 Jun 2025 20:00:44 -0600 Subject: [PATCH] keyboard & peripheral enhancement --- Cargo.lock | 2 + Cargo.toml | 4 +- src/main.rs | 6 - src/peripherals/battery.rs | 20 --- src/peripherals/keyboard.rs | 294 ++++++++++++------------------------ src/peripherals/mod.rs | 99 ++++++++---- 6 files changed, 167 insertions(+), 258 deletions(-) delete mode 100644 src/peripherals/battery.rs diff --git a/Cargo.lock b/Cargo.lock index 22f91fc..fe98260 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1336,6 +1336,7 @@ checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" name = "picocalc-os-rs" version = "0.1.0" dependencies = [ + "bitflags 2.9.1", "bt-hci", "cortex-m", "cortex-m-rt", @@ -1729,6 +1730,7 @@ dependencies = [ [[package]] name = "st7365p-lcd" version = "0.10.0" +source = "git+https://github.com/legitcamper/st7365p-lcd-rs#d751e8d30f1a3f964ffe05e4bb16f82112fbefce" dependencies = [ "embedded-graphics-core", "embedded-hal 1.0.0", diff --git a/Cargo.toml b/Cargo.toml index 4fa8de1..5a9425d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -71,7 +71,7 @@ defmt-rtt = "0.4.2" embedded-graphics = { version = "0.8.1" } embedded-sdmmc = { git = "https://github.com/Be-ing/embedded-sdmmc-rs", branch = "bisync", default-features = false } -# st7365p-lcd = { git = "https://github.com/legitcamper/st7365p-lcd-rs" } -st7365p-lcd = { path = "../ST7365P-lcd-rs" } +st7365p-lcd = { git = "https://github.com/legitcamper/st7365p-lcd-rs" } static_cell = "2.1.1" +bitflags = "2.9.1" diff --git a/src/main.rs b/src/main.rs index 91102b6..56b63f8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -54,10 +54,4 @@ async fn main(spawner: Spawner) { // spawner // .spawn(display_task(spi1, p.PIN_13, p.PIN_14, p.PIN_15)) // .unwrap(); - - let receiver = keyboard_events.receiver(); - loop { - let key = receiver.receive().await; - info!("got key: {}", key); - } } diff --git a/src/peripherals/battery.rs b/src/peripherals/battery.rs deleted file mode 100644 index 405b797..0000000 --- a/src/peripherals/battery.rs +++ /dev/null @@ -1,20 +0,0 @@ -use embassy_rp::{ - i2c::{Async, I2c}, - peripherals::I2C1, -}; -use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, mutex::Mutex, watch::Watch}; - -const REG_ID_BAT: u8 = 0x0b; - -pub static BATTERY_PCT: Watch = Watch::new(); - -pub async fn read_battery(i2c: &mut I2c<'static, I2C1, Async>) { - let mut buf = [0_u8; 2]; - i2c.write_read_async(super::MCU_ADDR, [REG_ID_BAT], &mut buf) - .await - .unwrap(); - - if buf[0] == REG_ID_BAT { - BATTERY_PCT.sender().send(buf[0]); - } -} diff --git a/src/peripherals/keyboard.rs b/src/peripherals/keyboard.rs index 16da474..eaa07c7 100644 --- a/src/peripherals/keyboard.rs +++ b/src/peripherals/keyboard.rs @@ -8,20 +8,19 @@ use embassy_sync::{ channel::Sender, }; -const REG_ID_CFG: u8 = 0x02; +use crate::peripherals::PERIPHERAL_BUS; + const REG_ID_KEY: u8 = 0x04; const REG_ID_FIF: u8 = 0x09; -// const REG_ID_C64_MTX: u8 = 0x0c; -// const REG_ID_C64_JS: u8 = 0x0d; const KEY_CAPSLOCK: u8 = 1 << 5; const KEY_NUMLOCK: u8 = 1 << 6; const KEY_COUNT_MASK: u8 = 0x1F; // 0x1F == 31 -pub async fn read_keyboard_fifo( - i2c: &mut I2c<'static, I2C1, Async>, - channel: &mut Sender<'static, NoopRawMutex, KeyEvent, 10>, -) { +pub async fn read_keyboard_fifo(channel: &mut Sender<'static, NoopRawMutex, KeyEvent, 10>) { + let mut i2c = PERIPHERAL_BUS.get().lock().await; + let i2c = i2c.as_mut().unwrap(); + let mut key_status = [0_u8; 1]; if i2c @@ -29,9 +28,8 @@ pub async fn read_keyboard_fifo( .await .is_ok() { - // TODO: use caps & num lock - let caps = key_status[0] & KEY_CAPSLOCK == KEY_CAPSLOCK; - let num = key_status[0] & KEY_NUMLOCK == KEY_NUMLOCK; + let _caps = key_status[0] & KEY_CAPSLOCK == KEY_CAPSLOCK; + let _num = key_status[0] & KEY_NUMLOCK == KEY_NUMLOCK; let fifo_count = key_status[0] & KEY_COUNT_MASK; if fifo_count >= 1 { @@ -42,13 +40,13 @@ pub async fn read_keyboard_fifo( .await .is_ok() { - if let Ok(state) = KeyState::try_from(event[0]) { - if let Ok(key) = KeyCode::try_from(event[1]) { - channel - .try_send(KeyEvent { key, state }) - .expect("Failed to push key"); - } - } + channel + .try_send(KeyEvent { + state: KeyState::from(event[0]), + key: KeyCode::from(event[1]), + mods: Modifiers::NONE, + }) + .expect("Failed to push key"); } } } @@ -57,82 +55,84 @@ pub async fn read_keyboard_fifo( const REG_ID_DEB: u8 = 0x06; const REG_ID_FRQ: u8 = 0x07; -pub async fn configure_keyboard(i2c: &mut I2c<'static, I2C1, Async>, debounce: u8, poll_freq: u8) { - i2c.write_read_async(super::MCU_ADDR, [REG_ID_DEB], &mut [debounce]) - .await - .unwrap(); +pub async fn configure_keyboard(debounce: u8, poll_freq: u8) { + let mut i2c = PERIPHERAL_BUS.get().lock().await; + let i2c = i2c.as_mut().unwrap(); - i2c.write_read_async(super::MCU_ADDR, [REG_ID_FRQ], &mut [poll_freq]) - .await - .unwrap(); + let _ = i2c + .write_read_async(super::MCU_ADDR, [REG_ID_DEB], &mut [debounce]) + .await; + + let _ = i2c + .write_read_async(super::MCU_ADDR, [REG_ID_FRQ], &mut [poll_freq]) + .await; +} + +bitflags::bitflags! { + #[derive(Default, Debug, PartialEq, Eq, Clone, Copy)] + pub struct Modifiers: u8 { + const NONE = 0; + const CTRL = 1; + const ALT = 2; + const LSHIFT = 4; + const RSHIFT = 8; + const SYM = 16; + } } -#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[derive(Debug)] pub struct KeyEvent { pub key: KeyCode, pub state: KeyState, + pub mods: Modifiers, } #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum KeyState { Idle = 0, - Pressed, - Hold, - Released, + Pressed = 1, + Hold = 2, + Released = 3, } -impl TryFrom for KeyState { - type Error = (); - - fn try_from(value: u8) -> Result { +impl From for KeyState { + fn from(value: u8) -> Self { match value { - 0 => Ok(KeyState::Idle), - 1 => Ok(KeyState::Pressed), - 2 => Ok(KeyState::Hold), - 3 => Ok(KeyState::Released), - _ => Err(()), + 1 => KeyState::Pressed, + 2 => KeyState::Hold, + 3 => KeyState::Released, + 0 | _ => KeyState::Idle, } } } #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u8)] pub enum KeyCode { - // Joystick JoyUp = 0x01, JoyDown = 0x02, JoyLeft = 0x03, JoyRight = 0x04, JoyCenter = 0x05, - - // Buttons BtnLeft1 = 0x06, BtnRight1 = 0x07, BtnLeft2 = 0x11, BtnRight2 = 0x12, - - // Basic Keys Backspace = 0x08, Tab = 0x09, Enter = 0x0A, - - // Modifiers ModAlt = 0xA1, ModShiftLeft = 0xA2, ModShiftRight = 0xA3, ModSym = 0xA4, ModCtrl = 0xA5, - - // Navigation Esc = 0xB1, Left = 0xB4, Up = 0xB5, Down = 0xB6, Right = 0xB7, - - // Specials Break = 0xD0, Insert = 0xD1, Home = 0xD2, @@ -140,11 +140,7 @@ pub enum KeyCode { End = 0xD5, PageUp = 0xD6, PageDown = 0xD7, - - // Locks CapsLock = 0xC1, - - // Function keys F1 = 0x81, F2 = 0x82, F3 = 0x83, @@ -155,155 +151,57 @@ pub enum KeyCode { F8 = 0x88, F9 = 0x89, F10 = 0x90, - - // Printable ASCII (0x20 - 0x7F) - Space = 0x20, - Exclamation = 0x21, // ! - Quote = 0x22, // " - Hash = 0x23, // # - Dollar = 0x24, // $ - Percent = 0x25, // % - Ampersand = 0x26, // & - Apostrophe = 0x27, // ' - LeftParen = 0x28, // ( - RightParen = 0x29, // ) - Asterisk = 0x2A, // * - Plus = 0x2B, // + - Comma = 0x2C, // , - Minus = 0x2D, // - - Period = 0x2E, // . - Slash = 0x2F, // / - Num0 = 0x30, - Num1 = 0x31, - Num2 = 0x32, - Num3 = 0x33, - Num4 = 0x34, - Num5 = 0x35, - Num6 = 0x36, - Num7 = 0x37, - Num8 = 0x38, - Num9 = 0x39, - Colon = 0x3A, - Semicolon = 0x3B, - LessThan = 0x3C, - Equal = 0x3D, - GreaterThan = 0x3E, - Question = 0x3F, - At = 0x40, - A = 0x41, - B = 0x42, - C = 0x43, - D = 0x44, - E = 0x45, - F = 0x46, - G = 0x47, - H = 0x48, - I = 0x49, - J = 0x4A, - K = 0x4B, - L = 0x4C, - M = 0x4D, - N = 0x4E, - O = 0x4F, - P = 0x50, - Q = 0x51, - R = 0x52, - S = 0x53, - T = 0x54, - U = 0x55, - V = 0x56, - W = 0x57, - X = 0x58, - Y = 0x59, - Z = 0x5A, - LeftBracket = 0x5B, - Backslash = 0x5C, - RightBracket = 0x5D, - Caret = 0x5E, - Underscore = 0x5F, - Backtick = 0x60, - a = 0x61, - b = 0x62, - c = 0x63, - d = 0x64, - e = 0x65, - f = 0x66, - g = 0x67, - h = 0x68, - i = 0x69, - j = 0x6A, - k = 0x6B, - l = 0x6C, - m = 0x6D, - n = 0x6E, - o = 0x6F, - p = 0x70, - q = 0x71, - r = 0x72, - s = 0x73, - t = 0x74, - u = 0x75, - v = 0x76, - w = 0x77, - x = 0x78, - y = 0x79, - z = 0x7A, - LeftBrace = 0x7B, - Pipe = 0x7C, - RightBrace = 0x7D, - Tilde = 0x7E, - Delete = 0x7F, + Char(char), + Unknown(u8), } -impl TryFrom for KeyCode { - type Error = (); - - fn try_from(value: u8) -> Result { - use KeyCode::*; +impl From for KeyCode { + fn from(value: u8) -> Self { match value { - 0x01 => Ok(JoyUp), - 0x02 => Ok(JoyDown), - 0x03 => Ok(JoyLeft), - 0x04 => Ok(JoyRight), - 0x05 => Ok(JoyCenter), - 0x06 => Ok(BtnLeft1), - 0x07 => Ok(BtnRight1), - 0x08 => Ok(Backspace), - 0x09 => Ok(Tab), - 0x0A => Ok(Enter), - 0x11 => Ok(BtnLeft2), - 0x12 => Ok(BtnRight2), - 0xA1 => Ok(ModAlt), - 0xA2 => Ok(ModShiftLeft), - 0xA3 => Ok(ModShiftRight), - 0xA4 => Ok(ModSym), - 0xA5 => Ok(ModCtrl), - 0xB1 => Ok(Esc), - 0xB4 => Ok(Left), - 0xB5 => Ok(Up), - 0xB6 => Ok(Down), - 0xB7 => Ok(Right), - 0xC1 => Ok(CapsLock), - 0xD0 => Ok(Break), - 0xD1 => Ok(Insert), - 0xD2 => Ok(Home), - 0xD4 => Ok(Del), - 0xD5 => Ok(End), - 0xD6 => Ok(PageUp), - 0xD7 => Ok(PageDown), - 0x81 => Ok(F1), - 0x82 => Ok(F2), - 0x83 => Ok(F3), - 0x84 => Ok(F4), - 0x85 => Ok(F5), - 0x86 => Ok(F6), - 0x87 => Ok(F7), - 0x88 => Ok(F8), - 0x89 => Ok(F9), - 0x90 => Ok(F10), - // ASCII 0x20 to 0x7F - 0x20..=0x7F => unsafe { Ok(core::mem::transmute(value)) }, - _ => Err(()), + 0x01 => Self::JoyUp, + 0x02 => Self::JoyDown, + 0x03 => Self::JoyLeft, + 0x04 => Self::JoyRight, + 0x05 => Self::JoyCenter, + 0x06 => Self::BtnLeft1, + 0x07 => Self::BtnRight1, + 0x08 => Self::Backspace, + 0x09 => Self::Tab, + 0x0A => Self::Enter, + 0x11 => Self::BtnLeft2, + 0x12 => Self::BtnRight2, + 0xA1 => Self::ModAlt, + 0xA2 => Self::ModShiftLeft, + 0xA3 => Self::ModShiftRight, + 0xA4 => Self::ModSym, + 0xA5 => Self::ModCtrl, + 0xB1 => Self::Esc, + 0xB4 => Self::Left, + 0xB5 => Self::Up, + 0xB6 => Self::Down, + 0xB7 => Self::Right, + 0xC1 => Self::CapsLock, + 0xD0 => Self::Break, + 0xD1 => Self::Insert, + 0xD2 => Self::Home, + 0xD4 => Self::Del, + 0xD5 => Self::End, + 0xD6 => Self::PageUp, + 0xD7 => Self::PageDown, + 0x81 => Self::F1, + 0x82 => Self::F2, + 0x83 => Self::F3, + 0x84 => Self::F4, + 0x85 => Self::F5, + 0x86 => Self::F6, + 0x87 => Self::F7, + 0x88 => Self::F8, + 0x89 => Self::F9, + 0x90 => Self::F10, + _ => match char::from_u32(value as u32) { + Some(c) => Self::Char(c), + None => Self::Unknown(value), + }, } } } diff --git a/src/peripherals/mod.rs b/src/peripherals/mod.rs index 1e85314..b3e7d1a 100644 --- a/src/peripherals/mod.rs +++ b/src/peripherals/mod.rs @@ -1,71 +1,106 @@ //! handles all the peripherals exposed by mcu through i2c (keyboard & battery registers) //! -use embassy_futures::join::join; use embassy_rp::{ i2c::{Async, I2c}, peripherals::I2C1, }; -use embassy_sync::{blocking_mutex::raw::NoopRawMutex, channel::Sender, mutex::Mutex}; +use embassy_sync::{ + blocking_mutex::raw::NoopRawMutex, channel::Sender, lazy_lock::LazyLock, mutex::Mutex, +}; use embassy_time::{Duration, Timer}; -#[cfg(feature = "defmt")] -use defmt::info; - pub mod keyboard; use keyboard::{KeyCode, KeyEvent, KeyState}; -mod battery; -pub use battery::BATTERY_PCT; -use battery::read_battery; use crate::peripherals::keyboard::{configure_keyboard, read_keyboard_fifo}; const MCU_ADDR: u8 = 0x1F; +type I2CBUS = I2c<'static, I2C1, Async>; +pub static PERIPHERAL_BUS: LazyLock>> = + LazyLock::new(|| Mutex::new(None)); + const REG_ID_VER: u8 = 0x01; const REG_ID_RST: u8 = 0x08; const REG_ID_INT: u8 = 0x03; #[embassy_executor::task] pub async fn peripherals_task( - mut i2c: I2c<'static, I2C1, Async>, + i2c: I2CBUS, mut keyboard_channel: Sender<'static, NoopRawMutex, KeyEvent, 10>, ) { Timer::after(embassy_time::Duration::from_millis(100)).await; - #[cfg(feature = "defmt")] - { - let mut ver = [0_u8; 1]; - if let Ok(_) = i2c.write_read_async(MCU_ADDR, [REG_ID_VER], &mut ver).await { - info!("stm32 firmware version: v{}", ver[0]); - } - } + PERIPHERAL_BUS.get().lock().await.replace(i2c); - let i2c: Mutex> = Mutex::new(i2c); - let mut guard = i2c.lock().await; - - configure_keyboard(&mut guard, 200, 100).await; - lcd_backlight(&mut guard, 255).await; - key_backlight(&mut guard, 0).await; + configure_keyboard(200, 100).await; + set_lcd_backlight(255).await; + set_key_backlight(0).await; loop { Timer::after(Duration::from_millis(200)).await; - read_keyboard_fifo(&mut guard, &mut keyboard_channel).await; + read_keyboard_fifo(&mut keyboard_channel).await; } } -const REG_ID_BKL: u8 = 0x05; +/// return major & minor mcu version +async fn get_version() -> (u8, u8) { + let mut i2c = PERIPHERAL_BUS.get().lock().await; + let i2c = i2c.as_mut().unwrap(); -pub async fn lcd_backlight(i2c: &mut I2c<'static, I2C1, Async>, brightness: u8) { - i2c.write_read_async(MCU_ADDR, [REG_ID_BKL], &mut [brightness]) - .await - .unwrap(); + let mut ver = [0_u8; 1]; + let _ = i2c.write_read_async(MCU_ADDR, [REG_ID_VER], &mut ver).await; + + (ver[0] >> 4, ver[0] & 0x0F) +} + +const REG_ID_BKL: u8 = 0x05; +pub async fn set_lcd_backlight(brightness: u8) { + let mut i2c = PERIPHERAL_BUS.get().lock().await; + let i2c = i2c.as_mut().unwrap(); + + let _ = i2c + .write_read_async(MCU_ADDR, [REG_ID_BKL], &mut [brightness]) + .await; +} +pub async fn get_lcd_backlight() -> u8 { + let mut i2c = PERIPHERAL_BUS.get().lock().await; + let i2c = i2c.as_mut().unwrap(); + + let mut buf = [0_u8; 2]; + + let _ = i2c.write_read_async(MCU_ADDR, [REG_ID_BKL], &mut buf).await; + buf[1] } const REG_ID_BK2: u8 = 0x0A; +pub async fn set_key_backlight(brightness: u8) { + let mut i2c = PERIPHERAL_BUS.get().lock().await; + let i2c = i2c.as_mut().unwrap(); -pub async fn key_backlight(i2c: &mut I2c<'static, I2C1, Async>, brightness: u8) { - i2c.write_read_async(MCU_ADDR, [REG_ID_BK2], &mut [brightness]) - .await - .unwrap(); + let _ = i2c + .write_read_async(MCU_ADDR, [REG_ID_BK2], &mut [brightness]) + .await; +} +pub async fn get_key_backlight() -> u8 { + let mut i2c = PERIPHERAL_BUS.get().lock().await; + let i2c = i2c.as_mut().unwrap(); + + let mut buf = [0_u8; 2]; + + let _ = i2c.write_read_async(MCU_ADDR, [REG_ID_BK2], &mut buf).await; + buf[1] +} + +const REG_ID_BAT: u8 = 0x0b; +pub async fn get_battery() -> u8 { + let mut i2c = PERIPHERAL_BUS.get().lock().await; + let i2c = i2c.as_mut().unwrap(); + + let mut buf = [0_u8; 2]; + + let _ = i2c.write_read_async(MCU_ADDR, [REG_ID_BAT], &mut buf).await; + + buf[1] }