diff --git a/Cargo.lock b/Cargo.lock index 13db5ac..dc4cf18 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12,6 +12,13 @@ dependencies = [ "regex", ] +[[package]] +name = "abi" +version = "0.1.0" +dependencies = [ + "shared", +] + [[package]] name = "aho-corasick" version = "1.1.3" @@ -192,6 +199,10 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "calculator" +version = "0.1.0" + [[package]] name = "cfg-if" version = "1.0.1" @@ -1159,9 +1170,9 @@ checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" [[package]] name = "libredox" -version = "0.1.4" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1580801010e535496706ba011c15f8532df6b42297d2e471fec38ceadd8c0638" +checksum = "4488594b9328dee448adb906d8b126d9b7deb7cf5c22161ee591610bb1be83c0" dependencies = [ "bitflags 2.9.1", "libc", @@ -1356,6 +1367,7 @@ checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" name = "picocalc-os-rs" version = "0.1.0" dependencies = [ + "abi", "bitflags 2.9.1", "bt-hci", "cortex-m", @@ -1378,6 +1390,7 @@ dependencies = [ "heapless", "panic-probe", "portable-atomic", + "shared", "spin", "st7365p-lcd", "static_cell", @@ -1726,6 +1739,14 @@ dependencies = [ "keccak", ] +[[package]] +name = "shared" +version = "0.1.0" +dependencies = [ + "bitflags 2.9.1", + "defmt 1.0.1", +] + [[package]] name = "siphasher" version = "1.0.1" diff --git a/Cargo.toml b/Cargo.toml index 6477884..e58fa93 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,6 @@ -[package] -name = "picocalc-os-rs" -version = "0.1.0" -edition = "2024" +[workspace] +resolver = "3" +members = ["kernel", "abi", "shared", "user-apps/calculator"] [profile.release] debug = 2 @@ -9,72 +8,3 @@ debug = 2 [profile.dev] lto = true opt-level = "z" - -[features] -default = ["rp235x", "defmt"] -rp2040 = ["embassy-rp/rp2040"] -rp235x = ["embassy-rp/rp235xb"] -trouble = ["dep:bt-hci", "dep:cyw43", "dep:cyw43-pio", "dep:trouble-host"] -defmt = [ - "dep:defmt", - "panic-probe/print-defmt", - "embassy-executor/defmt", - "embassy-time/defmt", - "embassy-time/defmt-timestamp-uptime", - "embassy-rp/defmt", - "embassy-sync/defmt", - "embedded-graphics/defmt", - "embedded-sdmmc/defmt-log", - # "bt-hci/defmt", - # "cyw43/defmt", - # "cyw43-pio/defmt", -] - -[dependencies] -embassy-executor = { version = "0.7", features = [ - "arch-cortex-m", - "executor-interrupt", - "executor-thread", - "nightly", -] } -embassy-rp = { version = "0.4.0", features = [ - "critical-section-impl", - "unstable-pac", - "time-driver", - "binary-info", -] } -embassy-futures = "0.1.1" -embassy-time = "0.4.0" -embassy-embedded-hal = "0.3.0" -embassy-sync = { version = "0.7" } -trouble-host = { version = "0.1", features = [ - "derive", - "scan", -], optional = true } -bt-hci = { version = "0.2", default-features = false, optional = true } -cyw43 = { version = "0.3.0", features = [ - "firmware-logs", - "bluetooth", -], optional = true } -cyw43-pio = { version = "0.3.0", optional = true } - -embedded-hal-bus = { version = "0.3.0", features = ["async"] } -embedded-hal = "0.2.7" -embedded-hal-async = "1.0.0" -cortex-m = { version = "0.7.7" } -cortex-m-rt = "0.7.5" -panic-probe = "0.3" -portable-atomic = { version = "1.11", features = ["critical-section"] } - -defmt = { version = "0.3", optional = true } -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", branch = "async" } - -static_cell = "2.1.1" -bitflags = "2.9.1" -talc = "4.4.3" -spin = "0.10.0" -heapless = "0.8.0" diff --git a/abi/Cargo.toml b/abi/Cargo.toml new file mode 100644 index 0000000..80cc90d --- /dev/null +++ b/abi/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "abi" +version = "0.1.0" +edition = "2024" + +[dependencies] +shared = { path = "../shared" } diff --git a/abi/src/lib.rs b/abi/src/lib.rs new file mode 100644 index 0000000..0411192 --- /dev/null +++ b/abi/src/lib.rs @@ -0,0 +1,9 @@ +#![no_std] + +use core::ffi::c_void; +use shared::keyboard::{KeyCode, KeyEvent, KeyState, Modifiers}; + +#[repr(C)] +pub enum Syscall { + DrawPixels { x: u32, y: u32, color: u32 }, +} diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml new file mode 100644 index 0000000..61fe107 --- /dev/null +++ b/kernel/Cargo.toml @@ -0,0 +1,83 @@ +[package] +name = "picocalc-os-rs" +version = "0.1.0" +edition = "2024" + +[[bin]] +name = "picocalc-os-rs" +path = "src/main.rs" +test = false +doctest = false +bench = false + +[features] +default = ["rp235x", "defmt"] +rp2040 = ["embassy-rp/rp2040"] +rp235x = ["embassy-rp/rp235xb"] +trouble = ["dep:bt-hci", "dep:cyw43", "dep:cyw43-pio", "dep:trouble-host"] +defmt = [ + "dep:defmt", + "panic-probe/print-defmt", + "embassy-executor/defmt", + "embassy-time/defmt", + "embassy-time/defmt-timestamp-uptime", + "embassy-rp/defmt", + "embassy-sync/defmt", + "embedded-graphics/defmt", + "embedded-sdmmc/defmt-log", + # "bt-hci/defmt", + # "cyw43/defmt", + # "cyw43-pio/defmt", +] + +[dependencies] +embassy-executor = { version = "0.7", features = [ + "arch-cortex-m", + "executor-interrupt", + "executor-thread", + "nightly", +] } +embassy-rp = { version = "0.4.0", features = [ + "critical-section-impl", + "unstable-pac", + "time-driver", + "binary-info", +] } +embassy-futures = "0.1.1" +embassy-time = "0.4.0" +embassy-embedded-hal = "0.3.0" +embassy-sync = { version = "0.7" } +trouble-host = { version = "0.1", features = [ + "derive", + "scan", +], optional = true } +bt-hci = { version = "0.2", default-features = false, optional = true } +cyw43 = { version = "0.3.0", features = [ + "firmware-logs", + "bluetooth", +], optional = true } +cyw43-pio = { version = "0.3.0", optional = true } + +embedded-hal-bus = { version = "0.3.0", features = ["async"] } +embedded-hal = "0.2.7" +embedded-hal-async = "1.0.0" +cortex-m = { version = "0.7.7" } +cortex-m-rt = "0.7.5" +panic-probe = "0.3" +portable-atomic = { version = "1.11", features = ["critical-section"] } + +defmt = { version = "0.3", optional = true } +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", branch = "async" } + +shared = { path = "../shared" } +abi = { path = "../abi" } + +static_cell = "2.1.1" +bitflags = "2.9.1" +talc = "4.4.3" +spin = "0.10.0" +heapless = "0.8.0" diff --git a/build.rs b/kernel/build.rs similarity index 96% rename from build.rs rename to kernel/build.rs index 30691aa..e0ded4a 100644 --- a/build.rs +++ b/kernel/build.rs @@ -19,7 +19,7 @@ fn main() { let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); File::create(out.join("memory.x")) .unwrap() - .write_all(include_bytes!("memory.x")) + .write_all(include_bytes!("../memory.x")) .unwrap(); println!("cargo:rustc-link-search={}", out.display()); diff --git a/src/display.rs b/kernel/src/display.rs similarity index 100% rename from src/display.rs rename to kernel/src/display.rs diff --git a/src/main.rs b/kernel/src/main.rs similarity index 87% rename from src/main.rs rename to kernel/src/main.rs index e754b93..80184e9 100644 --- a/src/main.rs +++ b/kernel/src/main.rs @@ -1,7 +1,7 @@ #![feature(impl_trait_in_assoc_type)] #![feature(ascii_char)] -#![no_std] -#![no_main] +#![cfg_attr(not(test), no_std)] +#![cfg_attr(not(test), no_main)] use crate::{ display::DISPLAY_SIGNAL, @@ -80,3 +80,16 @@ async fn main(_spawner: Spawner) { ) .await; } + +use abi::Syscall; + +#[no_mangle] +pub extern "C" fn syscall_dispatch(call: *const Syscall) -> usize { + let call = unsafe { &*call }; + match call { + Syscall::DrawPixel { x, y, color } => { + draw_pixel(*x, *y, *color); + 0 + } + } +} diff --git a/kernel/src/peripherals/keyboard.rs b/kernel/src/peripherals/keyboard.rs new file mode 100644 index 0000000..a9ef605 --- /dev/null +++ b/kernel/src/peripherals/keyboard.rs @@ -0,0 +1,59 @@ +use crate::peripherals::PERIPHERAL_BUS; +pub use shared::keyboard::{KeyCode, KeyEvent, KeyState, Modifiers}; + +const REG_ID_KEY: u8 = 0x04; +const REG_ID_FIF: u8 = 0x09; + +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() -> Option { + let mut i2c = PERIPHERAL_BUS.get().lock().await; + let i2c = i2c.as_mut().unwrap(); + + let mut key_status = [0_u8; 1]; + + if i2c + .write_read_async(super::MCU_ADDR, [REG_ID_KEY], &mut key_status) + .await + .is_ok() + { + 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 { + let mut event = [0_u8; 2]; + + if i2c + .write_read_async(super::MCU_ADDR, [REG_ID_FIF], &mut event) + .await + .is_ok() + { + return Some(KeyEvent { + state: KeyState::from(event[0]), + key: KeyCode::from(event[1]), + mods: Modifiers::NONE, + }); + } + } + } + None +} + +const REG_ID_DEB: u8 = 0x06; +const REG_ID_FRQ: u8 = 0x07; + +pub async fn configure_keyboard(debounce: u8, poll_freq: u8) { + let mut i2c = PERIPHERAL_BUS.get().lock().await; + let i2c = i2c.as_mut().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; +} diff --git a/src/peripherals/mod.rs b/kernel/src/peripherals/mod.rs similarity index 100% rename from src/peripherals/mod.rs rename to kernel/src/peripherals/mod.rs diff --git a/shared/Cargo.toml b/shared/Cargo.toml new file mode 100644 index 0000000..4ceba1e --- /dev/null +++ b/shared/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "shared" +version = "0.1.0" +edition = "2024" + +[features] +defmt = ["dep:defmt"] + +[dependencies] +bitflags = "2.9.1" +defmt = { version = "1.0.1", optional = true } diff --git a/shared/src/lib.rs b/shared/src/lib.rs new file mode 100644 index 0000000..3823869 --- /dev/null +++ b/shared/src/lib.rs @@ -0,0 +1,142 @@ +#![no_std] + +pub mod keyboard { + 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; + } + } + + #[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 = 1, + Hold = 2, + Released = 3, + } + + impl From for KeyState { + fn from(value: u8) -> Self { + match value { + 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(C)] + #[repr(u8)] + pub enum KeyCode { + JoyUp = 0x01, + JoyDown = 0x02, + JoyLeft = 0x03, + JoyRight = 0x04, + JoyCenter = 0x05, + BtnLeft1 = 0x06, + BtnRight1 = 0x07, + BtnLeft2 = 0x11, + BtnRight2 = 0x12, + Backspace = 0x08, + Tab = 0x09, + Enter = 0x0A, + ModAlt = 0xA1, + ModShiftLeft = 0xA2, + ModShiftRight = 0xA3, + ModSym = 0xA4, + ModCtrl = 0xA5, + Esc = 0xB1, + Left = 0xB4, + Up = 0xB5, + Down = 0xB6, + Right = 0xB7, + Break = 0xD0, + Insert = 0xD1, + Home = 0xD2, + Del = 0xD4, + End = 0xD5, + PageUp = 0xD6, + PageDown = 0xD7, + CapsLock = 0xC1, + F1 = 0x81, + F2 = 0x82, + F3 = 0x83, + F4 = 0x84, + F5 = 0x85, + F6 = 0x86, + F7 = 0x87, + F8 = 0x88, + F9 = 0x89, + F10 = 0x90, + Char(char), + Unknown(u8), + } + + impl From for KeyCode { + fn from(value: u8) -> Self { + match value { + 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/keyboard.rs b/src/peripherals/keyboard.rs deleted file mode 100644 index 208a335..0000000 --- a/src/peripherals/keyboard.rs +++ /dev/null @@ -1,197 +0,0 @@ - -use crate::peripherals::PERIPHERAL_BUS; - -const REG_ID_KEY: u8 = 0x04; -const REG_ID_FIF: u8 = 0x09; - -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() -> Option { - let mut i2c = PERIPHERAL_BUS.get().lock().await; - let i2c = i2c.as_mut().unwrap(); - - let mut key_status = [0_u8; 1]; - - if i2c - .write_read_async(super::MCU_ADDR, [REG_ID_KEY], &mut key_status) - .await - .is_ok() - { - 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 { - let mut event = [0_u8; 2]; - - if i2c - .write_read_async(super::MCU_ADDR, [REG_ID_FIF], &mut event) - .await - .is_ok() - { - return Some(KeyEvent { - state: KeyState::from(event[0]), - key: KeyCode::from(event[1]), - mods: Modifiers::NONE, - }); - } - } - } - None -} - -const REG_ID_DEB: u8 = 0x06; -const REG_ID_FRQ: u8 = 0x07; - -pub async fn configure_keyboard(debounce: u8, poll_freq: u8) { - let mut i2c = PERIPHERAL_BUS.get().lock().await; - let i2c = i2c.as_mut().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; - } -} - -#[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 = 1, - Hold = 2, - Released = 3, -} - -impl From for KeyState { - fn from(value: u8) -> Self { - match value { - 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 { - JoyUp = 0x01, - JoyDown = 0x02, - JoyLeft = 0x03, - JoyRight = 0x04, - JoyCenter = 0x05, - BtnLeft1 = 0x06, - BtnRight1 = 0x07, - BtnLeft2 = 0x11, - BtnRight2 = 0x12, - Backspace = 0x08, - Tab = 0x09, - Enter = 0x0A, - ModAlt = 0xA1, - ModShiftLeft = 0xA2, - ModShiftRight = 0xA3, - ModSym = 0xA4, - ModCtrl = 0xA5, - Esc = 0xB1, - Left = 0xB4, - Up = 0xB5, - Down = 0xB6, - Right = 0xB7, - Break = 0xD0, - Insert = 0xD1, - Home = 0xD2, - Del = 0xD4, - End = 0xD5, - PageUp = 0xD6, - PageDown = 0xD7, - CapsLock = 0xC1, - F1 = 0x81, - F2 = 0x82, - F3 = 0x83, - F4 = 0x84, - F5 = 0x85, - F6 = 0x86, - F7 = 0x87, - F8 = 0x88, - F9 = 0x89, - F10 = 0x90, - Char(char), - Unknown(u8), -} - -impl From for KeyCode { - fn from(value: u8) -> Self { - match value { - 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/user-apps/calculator/Cargo.toml b/user-apps/calculator/Cargo.toml new file mode 100644 index 0000000..ed5cba5 --- /dev/null +++ b/user-apps/calculator/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "calculator" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/user-apps/calculator/src/main.rs b/user-apps/calculator/src/main.rs new file mode 100644 index 0000000..e7a11a9 --- /dev/null +++ b/user-apps/calculator/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +}