2 Commits

Author SHA1 Message Date
49b6a99ea8 dont use mutex on framebuffer 2025-09-11 23:39:47 -06:00
718bcd6b5b WIP fixing deadlocks in kernel 2025-09-11 17:36:38 -06:00
15 changed files with 261 additions and 815 deletions

212
Cargo.lock generated
View File

@@ -18,7 +18,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"abi_sys", "abi_sys",
"embassy-time 0.5.0", "embassy-time 0.5.0",
"embedded-graphics 0.8.1", "embedded-graphics",
"shared", "shared",
"spin", "spin",
"talc", "talc",
@@ -28,7 +28,7 @@ dependencies = [
name = "abi_sys" name = "abi_sys"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"embedded-graphics 0.8.1", "embedded-graphics",
"shared", "shared",
] ]
@@ -77,12 +77,6 @@ dependencies = [
"term 1.1.0", "term 1.1.0",
] ]
[[package]]
name = "assign-resources"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "840ad5d907de7448d88a3f22b4a7b5d326c6eb3deeb9f94cfaaec7354a80b305"
[[package]] [[package]]
name = "atomic-polyfill" name = "atomic-polyfill"
version = "1.0.3" version = "1.0.3"
@@ -226,7 +220,7 @@ name = "calculator"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"abi", "abi",
"embedded-graphics 0.8.1", "embedded-graphics",
] ]
[[package]] [[package]]
@@ -502,7 +496,7 @@ checksum = "8578db196d74db92efdd5ebc546736dac1685499ee245b22eff92fa5e4b57945"
dependencies = [ dependencies = [
"embassy-futures", "embassy-futures",
"embassy-hal-internal 0.3.0", "embassy-hal-internal 0.3.0",
"embassy-sync 0.7.2", "embassy-sync 0.7.0",
"embassy-time 0.4.0", "embassy-time 0.4.0",
"embedded-hal 0.2.7", "embedded-hal 0.2.7",
"embedded-hal 1.0.0", "embedded-hal 1.0.0",
@@ -512,42 +506,24 @@ dependencies = [
"nb 1.1.0", "nb 1.1.0",
] ]
[[package]]
name = "embassy-embedded-hal"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "554e3e840696f54b4c9afcf28a0f24da431c927f4151040020416e7393d6d0d8"
dependencies = [
"embassy-futures",
"embassy-hal-internal 0.3.0",
"embassy-sync 0.7.2",
"embedded-hal 0.2.7",
"embedded-hal 1.0.0",
"embedded-hal-async",
"embedded-storage",
"embedded-storage-async",
"nb 1.1.0",
]
[[package]] [[package]]
name = "embassy-executor" name = "embassy-executor"
version = "0.9.1" version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06070468370195e0e86f241c8e5004356d696590a678d47d6676795b2e439c6b" checksum = "90327bcc66333a507f89ecc4e2d911b265c45f5c9bc241f98eee076752d35ac6"
dependencies = [ dependencies = [
"cortex-m", "cortex-m",
"critical-section", "critical-section",
"defmt 1.0.1", "defmt 0.3.100",
"document-features", "document-features",
"embassy-executor-macros", "embassy-executor-macros",
"embassy-executor-timer-queue",
] ]
[[package]] [[package]]
name = "embassy-executor-macros" name = "embassy-executor-macros"
version = "0.7.0" version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfdddc3a04226828316bf31393b6903ee162238576b1584ee2669af215d55472" checksum = "3577b1e9446f61381179a330fc5324b01d511624c55f25e3c66c9e3c626dbecf"
dependencies = [ dependencies = [
"darling", "darling",
"proc-macro2", "proc-macro2",
@@ -555,17 +531,11 @@ dependencies = [
"syn 2.0.104", "syn 2.0.104",
] ]
[[package]]
name = "embassy-executor-timer-queue"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fc328bf943af66b80b98755db9106bf7e7471b0cf47dc8559cd9a6be504cc9c"
[[package]] [[package]]
name = "embassy-futures" name = "embassy-futures"
version = "0.1.2" version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc2d050bdc5c21e0862a89256ed8029ae6c290a93aecefc73084b3002cdebb01" checksum = "1f878075b9794c1e4ac788c95b728f26aa6366d32eeb10c7051389f898f7d067"
[[package]] [[package]]
name = "embassy-hal-internal" name = "embassy-hal-internal"
@@ -575,6 +545,7 @@ checksum = "0ef3bac31ec146321248a169e9c7b5799f1e0b3829c7a9b324cb4600a7438f59"
dependencies = [ dependencies = [
"cortex-m", "cortex-m",
"critical-section", "critical-section",
"defmt 0.3.100",
"num-traits", "num-traits",
] ]
@@ -584,9 +555,6 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95285007a91b619dc9f26ea8f55452aa6c60f7115a4edc05085cd2bd3127cd7a" checksum = "95285007a91b619dc9f26ea8f55452aa6c60f7115a4edc05085cd2bd3127cd7a"
dependencies = [ dependencies = [
"cortex-m",
"critical-section",
"defmt 1.0.1",
"num-traits", "num-traits",
] ]
@@ -598,13 +566,13 @@ checksum = "524eb3c489760508f71360112bca70f6e53173e6fe48fc5f0efd0f5ab217751d"
[[package]] [[package]]
name = "embassy-net-driver-channel" name = "embassy-net-driver-channel"
version = "0.3.2" version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7b2739fbcf6cd206ae08779c7d709087b16577d255f2ea4a45bc4bbbf305b3f" checksum = "25a567ab50319d866ad5e6c583ed665ba9b07865389644d3d82e45bf1497c934"
dependencies = [ dependencies = [
"embassy-futures", "embassy-futures",
"embassy-net-driver", "embassy-net-driver",
"embassy-sync 0.7.2", "embassy-sync 0.7.0",
] ]
[[package]] [[package]]
@@ -619,12 +587,12 @@ dependencies = [
"cortex-m-rt", "cortex-m-rt",
"critical-section", "critical-section",
"document-features", "document-features",
"embassy-embedded-hal 0.3.1", "embassy-embedded-hal",
"embassy-futures", "embassy-futures",
"embassy-hal-internal 0.2.0", "embassy-hal-internal 0.2.0",
"embassy-sync 0.6.2", "embassy-sync 0.6.2",
"embassy-time 0.4.0", "embassy-time 0.4.0",
"embassy-usb-driver 0.1.1", "embassy-usb-driver",
"embedded-hal 0.2.7", "embedded-hal 0.2.7",
"embedded-hal 1.0.0", "embedded-hal 1.0.0",
"embedded-hal-async", "embedded-hal-async",
@@ -637,7 +605,7 @@ dependencies = [
"nb 1.1.0", "nb 1.1.0",
"pio 0.2.1", "pio 0.2.1",
"pio-proc 0.2.2", "pio-proc 0.2.2",
"rand_core 0.6.4", "rand_core",
"rp-pac", "rp-pac",
"rp2040-boot2", "rp2040-boot2",
"sha2-const-stable", "sha2-const-stable",
@@ -646,25 +614,25 @@ dependencies = [
[[package]] [[package]]
name = "embassy-rp" name = "embassy-rp"
version = "0.8.0" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a284935af0a869de3fa14af74b5f932389dd66d7048012f1083b06f38d05399" checksum = "d1a063d8baccdc5c7752840f4c7931f17bcd7de1ffe1efa2109e68113fe42612"
dependencies = [ dependencies = [
"atomic-polyfill", "atomic-polyfill",
"cfg-if", "cfg-if",
"cortex-m", "cortex-m",
"cortex-m-rt", "cortex-m-rt",
"critical-section", "critical-section",
"defmt 1.0.1", "defmt 0.3.100",
"document-features", "document-features",
"embassy-embedded-hal 0.5.0", "embassy-embedded-hal",
"embassy-futures", "embassy-futures",
"embassy-hal-internal 0.3.0", "embassy-hal-internal 0.2.0",
"embassy-sync 0.7.2", "embassy-sync 0.6.2",
"embassy-time 0.5.0", "embassy-time 0.4.0",
"embassy-time-driver", "embassy-time-driver",
"embassy-time-queue-utils", "embassy-time-queue-utils",
"embassy-usb-driver 0.2.0", "embassy-usb-driver",
"embedded-hal 0.2.7", "embedded-hal 0.2.7",
"embedded-hal 1.0.0", "embedded-hal 1.0.0",
"embedded-hal-async", "embedded-hal-async",
@@ -676,8 +644,7 @@ dependencies = [
"fixed", "fixed",
"nb 1.1.0", "nb 1.1.0",
"pio 0.3.0", "pio 0.3.0",
"rand_core 0.6.4", "rand_core",
"rand_core 0.9.3",
"rp-pac", "rp-pac",
"rp2040-boot2", "rp2040-boot2",
"sha2-const-stable", "sha2-const-stable",
@@ -700,16 +667,16 @@ dependencies = [
[[package]] [[package]]
name = "embassy-sync" name = "embassy-sync"
version = "0.7.2" version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73974a3edbd0bd286759b3d483540f0ebef705919a5f56f4fc7709066f71689b" checksum = "cef1a8a1ea892f9b656de0295532ac5d8067e9830d49ec75076291fd6066b136"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"critical-section", "critical-section",
"defmt 1.0.1", "defmt 1.0.1",
"embedded-io-async", "embedded-io-async",
"futures-core",
"futures-sink", "futures-sink",
"futures-util",
"heapless", "heapless",
] ]
@@ -721,8 +688,10 @@ checksum = "f820157f198ada183ad62e0a66f554c610cdcd1a9f27d4b316358103ced7a1f8"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"critical-section", "critical-section",
"defmt 0.3.100",
"document-features", "document-features",
"embassy-time-driver", "embassy-time-driver",
"embassy-time-queue-utils",
"embedded-hal 0.2.7", "embedded-hal 0.2.7",
"embedded-hal 1.0.0", "embedded-hal 1.0.0",
"embedded-hal-async", "embedded-hal-async",
@@ -737,10 +706,8 @@ checksum = "f4fa65b9284d974dad7a23bb72835c4ec85c0b540d86af7fc4098c88cff51d65"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"critical-section", "critical-section",
"defmt 1.0.1",
"document-features", "document-features",
"embassy-time-driver", "embassy-time-driver",
"embassy-time-queue-utils",
"embedded-hal 0.2.7", "embedded-hal 0.2.7",
"embedded-hal 1.0.0", "embedded-hal 1.0.0",
"embedded-hal-async", "embedded-hal-async",
@@ -758,25 +725,24 @@ dependencies = [
[[package]] [[package]]
name = "embassy-time-queue-utils" name = "embassy-time-queue-utils"
version = "0.3.0" version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80e2ee86063bd028a420a5fb5898c18c87a8898026da1d4c852af2c443d0a454" checksum = "dc55c748d16908a65b166d09ce976575fb8852cf60ccd06174092b41064d8f83"
dependencies = [ dependencies = [
"embassy-executor-timer-queue", "embassy-executor",
"heapless", "heapless",
] ]
[[package]] [[package]]
name = "embassy-usb" name = "embassy-usb"
version = "0.5.1" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc4462e48b19a4f401a11901bdd981aab80c6a826608016a0bdc73cbbab31954" checksum = "6e651b9b7b47b514e6e6d1940a6e2e300891a2c33641917130643602a0cb6386"
dependencies = [ dependencies = [
"embassy-futures", "embassy-futures",
"embassy-net-driver-channel", "embassy-net-driver-channel",
"embassy-sync 0.7.2", "embassy-sync 0.6.2",
"embassy-usb-driver 0.2.0", "embassy-usb-driver",
"embedded-io-async",
"heapless", "heapless",
"ssmarshal", "ssmarshal",
"usbd-hid", "usbd-hid",
@@ -787,33 +753,11 @@ name = "embassy-usb-driver"
version = "0.1.1" version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "340c5ce591ef58c6449e43f51d2c53efe1bf0bb6a40cbf80afa0d259c7d52c76" checksum = "340c5ce591ef58c6449e43f51d2c53efe1bf0bb6a40cbf80afa0d259c7d52c76"
dependencies = [
"embedded-io-async",
]
[[package]]
name = "embassy-usb-driver"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17119855ccc2d1f7470a39756b12068454ae27a3eabb037d940b5c03d9c77b7a"
dependencies = [ dependencies = [
"defmt 1.0.1", "defmt 1.0.1",
"embedded-io-async", "embedded-io-async",
] ]
[[package]]
name = "embedded-graphics"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "750082c65094fbcc4baf9ba31583ce9a8bb7f52cadfb96f6164b1bc7f922f32b"
dependencies = [
"az",
"byteorder",
"embedded-graphics-core 0.3.3",
"float-cmp 0.8.0",
"micromath 1.1.1",
]
[[package]] [[package]]
name = "embedded-graphics" name = "embedded-graphics"
version = "0.8.1" version = "0.8.1"
@@ -823,19 +767,9 @@ dependencies = [
"az", "az",
"byteorder", "byteorder",
"defmt 0.3.100", "defmt 0.3.100",
"embedded-graphics-core 0.4.0", "embedded-graphics-core",
"float-cmp 0.9.0", "float-cmp",
"micromath 2.1.0", "micromath",
]
[[package]]
name = "embedded-graphics-core"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8b1239db5f3eeb7e33e35bd10bd014e7b2537b17e071f726a09351431337cfa"
dependencies = [
"az",
"byteorder",
] ]
[[package]] [[package]]
@@ -916,7 +850,7 @@ version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a90553247f2b05c59ac7894ea13d830636c2b1203fa03bff400eddbd1fa9f52" checksum = "9a90553247f2b05c59ac7894ea13d830636c2b1203fa03bff400eddbd1fa9f52"
dependencies = [ dependencies = [
"embedded-graphics 0.8.1", "embedded-graphics",
"embedded-layout-macros", "embedded-layout-macros",
] ]
@@ -944,16 +878,6 @@ dependencies = [
"heapless", "heapless",
] ]
[[package]]
name = "embedded-snake"
version = "0.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af598ad20b839c26b95be615a94619a069303ec776a58aef6dc0e86cf7eabbb8"
dependencies = [
"embedded-graphics 0.7.1",
"rand_core 0.6.4",
]
[[package]] [[package]]
name = "embedded-storage" name = "embedded-storage"
version = "0.3.1" version = "0.3.1"
@@ -976,7 +900,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "005680edc0d075af5e02d5788ca291737bd9aba7fc404ae031cc9dfa715e5f7d" checksum = "005680edc0d075af5e02d5788ca291737bd9aba7fc404ae031cc9dfa715e5f7d"
dependencies = [ dependencies = [
"az", "az",
"embedded-graphics 0.8.1", "embedded-graphics",
"object-chain", "object-chain",
] ]
@@ -1025,15 +949,6 @@ version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
[[package]]
name = "float-cmp"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1267f4ac4f343772758f7b1bdcbe767c218bbab93bb432acbf5162bbf85a6c4"
dependencies = [
"num-traits",
]
[[package]] [[package]]
name = "float-cmp" name = "float-cmp"
version = "0.9.0" version = "0.9.0"
@@ -1288,7 +1203,6 @@ name = "kernel"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"abi_sys", "abi_sys",
"assign-resources",
"bitflags 2.9.1", "bitflags 2.9.1",
"bt-hci", "bt-hci",
"cortex-m", "cortex-m",
@@ -1297,16 +1211,15 @@ dependencies = [
"cyw43-pio", "cyw43-pio",
"defmt 0.3.100", "defmt 0.3.100",
"defmt-rtt", "defmt-rtt",
"embassy-embedded-hal 0.3.1", "embassy-embedded-hal",
"embassy-executor", "embassy-executor",
"embassy-futures", "embassy-futures",
"embassy-rp 0.8.0", "embassy-rp 0.4.0",
"embassy-sync 0.7.2", "embassy-sync 0.7.0",
"embassy-time 0.5.0", "embassy-time 0.4.0",
"embassy-usb", "embassy-usb",
"embedded-graphics 0.8.1", "embedded-graphics",
"embedded-hal 0.2.7", "embedded-hal 0.2.7",
"embedded-hal 1.0.0",
"embedded-hal-async", "embedded-hal-async",
"embedded-hal-bus", "embedded-hal-bus",
"embedded-layout", "embedded-layout",
@@ -1438,12 +1351,6 @@ version = "2.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
[[package]]
name = "micromath"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc4010833aea396656c2f91ee704d51a6f1329ec2ab56ffd00bfd56f7481ea94"
[[package]] [[package]]
name = "micromath" name = "micromath"
version = "2.1.0" version = "2.1.0"
@@ -1804,12 +1711,6 @@ version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
[[package]]
name = "rand_core"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
[[package]] [[package]]
name = "redox_syscall" name = "redox_syscall"
version = "0.5.13" version = "0.5.13"
@@ -2018,16 +1919,6 @@ dependencies = [
"rgb", "rgb",
] ]
[[package]]
name = "snake"
version = "0.1.0"
dependencies = [
"abi",
"embedded-graphics 0.8.1",
"embedded-snake",
"rand_core 0.6.4",
]
[[package]] [[package]]
name = "spin" name = "spin"
version = "0.10.0" version = "0.10.0"
@@ -2050,10 +1941,9 @@ dependencies = [
[[package]] [[package]]
name = "st7365p-lcd" name = "st7365p-lcd"
version = "0.11.0" version = "0.11.0"
source = "git+https://github.com/legitcamper/st7365p-lcd-rs?rev=1d15123929fa7ef73d5d6aead7faf1bba50ce915#1d15123929fa7ef73d5d6aead7faf1bba50ce915"
dependencies = [ dependencies = [
"bitvec", "bitvec",
"embedded-graphics-core 0.4.0", "embedded-graphics-core",
"embedded-hal 1.0.0", "embedded-hal 1.0.0",
"embedded-hal-async", "embedded-hal-async",
"heapless", "heapless",
@@ -2221,7 +2111,7 @@ dependencies = [
"embedded-io", "embedded-io",
"futures", "futures",
"heapless", "heapless",
"rand_core 0.6.4", "rand_core",
"static_cell", "static_cell",
"trouble-host-macros", "trouble-host-macros",
"zerocopy", "zerocopy",

View File

@@ -1,7 +1,7 @@
#![no_std] #![no_std]
use abi_sys::draw_iter; use abi_sys::draw_iter;
pub use abi_sys::{get_key, print, sleep}; pub use abi_sys::{get_key, print};
pub use embassy_time; pub use embassy_time;
pub use shared::keyboard::{KeyCode, KeyEvent, KeyState, Modifiers}; pub use shared::keyboard::{KeyCode, KeyEvent, KeyState, Modifiers};
use talc::*; use talc::*;

View File

@@ -21,13 +21,12 @@ pub static mut CALL_ABI_TABLE: [usize; CallAbiTable::COUNT] = [0; CallAbiTable::
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum CallAbiTable { pub enum CallAbiTable {
Print = 0, Print = 0,
Sleep = 1, DrawIter = 1,
DrawIter = 2, GetKey = 2,
GetKey = 3,
} }
impl CallAbiTable { impl CallAbiTable {
pub const COUNT: usize = 4; pub const COUNT: usize = 3;
} }
pub type PrintAbi = extern "Rust" fn(msg: &str); pub type PrintAbi = extern "Rust" fn(msg: &str);
@@ -40,16 +39,6 @@ pub fn print(msg: &str) {
} }
} }
pub type SleepAbi = extern "Rust" fn(ms: u64);
pub fn sleep(ms: u64) {
unsafe {
let ptr = CALL_ABI_TABLE[CallAbiTable::Sleep as usize];
let f: SleepAbi = core::mem::transmute(ptr);
f(ms);
}
}
pub type DrawIterAbi = extern "Rust" fn(pixels: &[Pixel<Rgb565>]); pub type DrawIterAbi = extern "Rust" fn(pixels: &[Pixel<Rgb565>]);
pub fn draw_iter(pixels: &[Pixel<Rgb565>]) { pub fn draw_iter(pixels: &[Pixel<Rgb565>]) {

View File

@@ -31,20 +31,20 @@ defmt = [
] ]
[dependencies] [dependencies]
embassy-executor = { version = "0.9", features = [ embassy-executor = { version = "0.7", features = [
"arch-cortex-m", "arch-cortex-m",
"executor-interrupt", "executor-interrupt",
"executor-thread", "executor-thread",
"nightly", "nightly",
] } ] }
embassy-rp = { version = "0.8.0", features = [ embassy-rp = { version = "0.4.0", features = [
"critical-section-impl", "critical-section-impl",
"unstable-pac", "unstable-pac",
"time-driver", "time-driver",
] } ] }
embassy-usb = "0.5.1" embassy-usb = "0.4.0"
embassy-futures = "0.1.2" embassy-futures = "0.1.1"
embassy-time = { version = "0.5.0", features = ["generic-queue-8"] } embassy-time = { version = "0.4.0", features = ["generic-queue-8"] }
embassy-embedded-hal = "0.3.1" embassy-embedded-hal = "0.3.1"
embassy-sync = { version = "0.7" } embassy-sync = { version = "0.7" }
trouble-host = { version = "0.1", features = [ trouble-host = { version = "0.1", features = [
@@ -60,19 +60,18 @@ cyw43-pio = { version = "0.3.0", optional = true }
embedded-hal-bus = { version = "0.3.0", features = ["async"] } embedded-hal-bus = { version = "0.3.0", features = ["async"] }
embedded-hal = "0.2.7" embedded-hal = "0.2.7"
embedded-hal_2 = { package = "embedded-hal", version = "1.0.0" }
embedded-hal-async = "1.0.0" embedded-hal-async = "1.0.0"
cortex-m = { version = "0.7.7" } cortex-m = { version = "0.7.7" }
cortex-m-rt = "0.7.5" cortex-m-rt = "0.7.5"
panic-probe = "0.3" panic-probe = "0.3"
portable-atomic = { version = "1.11", features = ["critical-section"] } portable-atomic = { version = "1.11", features = ["critical-section"] }
assign-resources = "0.5.0"
defmt = { version = "0.3", optional = true } defmt = { version = "0.3", optional = true }
defmt-rtt = "0.4.2" defmt-rtt = "0.4.2"
embedded-sdmmc = { version = "0.9", default-features = false } embedded-sdmmc = { version = "0.9", default-features = false }
st7365p-lcd = { git = "https://github.com/legitcamper/st7365p-lcd-rs", rev = "1d15123929fa7ef73d5d6aead7faf1bba50ce915" } # async branch # st7365p-lcd = { git = "https://github.com/legitcamper/st7365p-lcd-rs", rev = "87abf450404865dcb535292e9e1a6a2457fd4599" } # async branch
st7365p-lcd = { path = "../../ST7365P-lcd-rs" } # async branch
embedded-graphics = { version = "0.8.1" } embedded-graphics = { version = "0.8.1" }
embedded-text = "0.7.2" embedded-text = "0.7.2"
embedded-layout = "0.4.2" embedded-layout = "0.4.2"

View File

@@ -1,11 +1,8 @@
use core::{pin::Pin, time::Duration}; use core::pin::Pin;
use abi_sys::{DrawIterAbi, GetKeyAbi, Pixel, PrintAbi, SleepAbi}; use abi_sys::{DrawIterAbi, GetKeyAbi, Pixel, PrintAbi};
use alloc::boxed::Box; use alloc::boxed::Box;
use defmt::info; use defmt::info;
use embassy_futures::block_on;
use embassy_rp::clocks::clk_sys_freq;
use embassy_time::Timer;
use embedded_graphics::{ use embedded_graphics::{
Drawable, Drawable,
draw_target::DrawTarget, draw_target::DrawTarget,
@@ -15,11 +12,10 @@ use embedded_graphics::{
}; };
use shared::keyboard::KeyEvent; use shared::keyboard::KeyEvent;
use crate::{KEY_CACHE, display::FRAMEBUFFER}; use crate::{KEY_CACHE, display::framebuffer_mut};
// ensure the abi and the kernel fn signatures are the same // ensure the abi and the kernel fn signatures are the same
const _: PrintAbi = print; const _: PrintAbi = print;
const _: SleepAbi = sleep;
const _: DrawIterAbi = draw_iter; const _: DrawIterAbi = draw_iter;
const _: GetKeyAbi = get_key; const _: GetKeyAbi = get_key;
@@ -27,18 +23,10 @@ pub extern "Rust" fn print(msg: &str) {
defmt::info!("{:?}", msg); defmt::info!("{:?}", msg);
} }
pub extern "Rust" fn sleep(ms: u64) {
let cycles_per_ms = clk_sys_freq() / 1000;
for _ in 0..ms {
for _ in 0..cycles_per_ms {
cortex_m::asm::nop();
}
}
}
// TODO: maybe return result // TODO: maybe return result
pub extern "Rust" fn draw_iter(pixels: &[Pixel<Rgb565>]) { pub extern "Rust" fn draw_iter(pixels: &[Pixel<Rgb565>]) {
unsafe { FRAMEBUFFER.draw_iter(pixels.iter().copied()).unwrap() } let fb = framebuffer_mut();
fb.draw_iter(pixels.iter().copied()).unwrap();
} }
pub extern "Rust" fn get_key() -> Option<KeyEvent> { pub extern "Rust" fn get_key() -> Option<KeyEvent> {

View File

@@ -1,18 +1,13 @@
use crate::framebuffer::AtomicFrameBuffer;
use embassy_rp::{ use embassy_rp::{
Peri,
gpio::{Level, Output}, gpio::{Level, Output},
peripherals::{PIN_13, PIN_14, PIN_15, SPI1}, peripherals::{PIN_13, PIN_14, PIN_15, SPI1},
spi::{Async, Spi}, spi::{Async, Spi},
}; };
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, mutex::Mutex};
use embassy_time::{Delay, Timer}; use embassy_time::{Delay, Timer};
use embedded_graphics::{
draw_target::DrawTarget,
pixelcolor::{Rgb565, RgbColor},
prelude::Dimensions,
};
use embedded_hal_bus::spi::ExclusiveDevice; use embedded_hal_bus::spi::ExclusiveDevice;
use st7365p_lcd::ST7365P; use st7365p_lcd::{FrameBuffer, ST7365P};
use static_cell::StaticCell;
type DISPLAY = ST7365P< type DISPLAY = ST7365P<
ExclusiveDevice<Spi<'static, SPI1, Async>, Output<'static>, Delay>, ExclusiveDevice<Spi<'static, SPI1, Async>, Output<'static>, Delay>,
@@ -24,13 +19,18 @@ type DISPLAY = ST7365P<
pub const SCREEN_WIDTH: usize = 320; pub const SCREEN_WIDTH: usize = 320;
pub const SCREEN_HEIGHT: usize = 320; pub const SCREEN_HEIGHT: usize = 320;
pub static mut FRAMEBUFFER: AtomicFrameBuffer = AtomicFrameBuffer::new(); type FB = FrameBuffer<SCREEN_WIDTH, SCREEN_HEIGHT, { SCREEN_WIDTH * SCREEN_HEIGHT }>;
static mut FRAMEBUFFER: Option<FB> = None;
pub fn framebuffer_mut() -> &'static mut FB {
unsafe { FRAMEBUFFER.as_mut().unwrap() }
}
pub async fn init_display( pub async fn init_display(
spi: Spi<'static, SPI1, Async>, spi: Spi<'static, SPI1, Async>,
cs: Peri<'static, PIN_13>, cs: PIN_13,
data: Peri<'static, PIN_14>, data: PIN_14,
reset: Peri<'static, PIN_15>, reset: PIN_15,
) -> DISPLAY { ) -> DISPLAY {
let spi_device = ExclusiveDevice::new(spi, Output::new(cs, Level::Low), Delay).unwrap(); let spi_device = ExclusiveDevice::new(spi, Output::new(cs, Level::Low), Delay).unwrap();
let mut display = ST7365P::new( let mut display = ST7365P::new(
@@ -41,30 +41,20 @@ pub async fn init_display(
true, true,
Delay, Delay,
); );
display.init().await.unwrap(); display.init().await.unwrap();
display.set_custom_orientation(0x40).await.unwrap(); display.set_custom_orientation(0x40).await.unwrap();
unsafe { FRAMEBUFFER.draw(&mut display).await.unwrap() } unsafe { FRAMEBUFFER.replace(FrameBuffer::new()) };
display.draw(framebuffer_mut()).await.unwrap();
display.set_on().await.unwrap(); display.set_on().await.unwrap();
display display
} }
pub fn clear_fb() {
let bounds = unsafe { FRAMEBUFFER.bounding_box() };
unsafe {
let _ = FRAMEBUFFER.fill_solid(&bounds, Rgb565::BLACK);
}
}
pub async fn display_handler(mut display: DISPLAY) { pub async fn display_handler(mut display: DISPLAY) {
let fb = framebuffer_mut();
loop { loop {
unsafe { display.partial_draw_batched(fb).await.unwrap();
FRAMEBUFFER embassy_time::Timer::after_millis(32).await; // 30 fps
.partial_draw_batched(&mut display)
.await
.unwrap()
}
Timer::after_millis(32).await; // 30 fps
} }
} }

View File

@@ -53,7 +53,6 @@ pub async unsafe fn load_binary(name: &ShortFileName) -> Result<EntryFn, &str> {
// MUST MATCH ABI EXACTLY // MUST MATCH ABI EXACTLY
let entries: &[(CallAbiTable, usize)] = &[ let entries: &[(CallAbiTable, usize)] = &[
(CallAbiTable::Print, abi::print as usize), (CallAbiTable::Print, abi::print as usize),
(CallAbiTable::Sleep, abi::sleep as usize),
(CallAbiTable::DrawIter, abi::draw_iter as usize), (CallAbiTable::DrawIter, abi::draw_iter as usize),
(CallAbiTable::GetKey, abi::get_key as usize), (CallAbiTable::GetKey, abi::get_key as usize),
]; ];

View File

@@ -1,432 +0,0 @@
use crate::display::{SCREEN_HEIGHT, SCREEN_WIDTH};
use core::sync::atomic::{AtomicBool, Ordering};
use embassy_sync::lazy_lock::LazyLock;
use embedded_graphics::{
draw_target::DrawTarget,
pixelcolor::{
Rgb565,
raw::{RawData, RawU16},
},
prelude::*,
primitives::Rectangle,
};
use embedded_hal_2::digital::OutputPin;
use embedded_hal_async::{delay::DelayNs, spi::SpiDevice};
use heapless::Vec;
use st7365p_lcd::{FrameBuffer, ST7365P};
pub const TILE_SIZE: usize = 16; // 16x16 tile
pub const TILE_COUNT: usize = (SCREEN_WIDTH / TILE_SIZE) * (SCREEN_HEIGHT / TILE_SIZE); // 400 tiles
// Group of tiles for batching
pub const MAX_META_TILES: usize = SCREEN_WIDTH / TILE_SIZE; // max number of meta tiles in buffer
type MetaTileVec = heapless::Vec<Rectangle, { TILE_COUNT / MAX_META_TILES }>;
const SIZE: usize = SCREEN_HEIGHT * SCREEN_WIDTH;
static mut BUFFER: [u16; SIZE] = [0; SIZE];
static mut DIRTY_TILES: LazyLock<Vec<AtomicBool, TILE_COUNT>> = LazyLock::new(|| {
let mut tiles = Vec::new();
for _ in 0..TILE_COUNT {
tiles.push(AtomicBool::new(true)).unwrap();
}
tiles
});
#[allow(dead_code)]
pub struct AtomicFrameBuffer;
impl AtomicFrameBuffer {
pub const fn new() -> Self {
Self
}
fn mark_tiles_dirty(&mut self, rect: Rectangle) {
let tiles_x = (SCREEN_WIDTH + TILE_SIZE - 1) / TILE_SIZE;
let start_tx = (rect.top_left.x as usize) / TILE_SIZE;
let end_tx = ((rect.top_left.x + rect.size.width as i32 - 1) as usize) / TILE_SIZE;
let start_ty = (rect.top_left.y as usize) / TILE_SIZE;
let end_ty = ((rect.top_left.y + rect.size.height as i32 - 1) as usize) / TILE_SIZE;
for ty in start_ty..=end_ty {
for tx in start_tx..=end_tx {
let tile_idx = ty * tiles_x + tx;
unsafe { DIRTY_TILES.get_mut()[tile_idx].store(true, Ordering::Relaxed) };
}
}
}
fn set_pixel(&mut self, x: u16, y: u16, color: u16) -> Result<(), ()> {
unsafe { BUFFER[(y as usize * SCREEN_WIDTH) + x as usize] = color };
Ok(())
}
fn set_pixels_buffered<P: IntoIterator<Item = u16>>(
&mut self,
sx: u16,
sy: u16,
ex: u16,
ey: u16,
colors: P,
) -> Result<(), ()> {
if sx >= self.size().width as u16 - 1
|| ex >= self.size().width as u16 - 1
|| sy >= self.size().height as u16 - 1
|| ey >= self.size().height as u16 - 1
{
return Err(()); // Bounds check
}
let mut color_iter = colors.into_iter();
for y in sy..=ey {
for x in sx..=ex {
if let Some(color) = color_iter.next() {
unsafe { BUFFER[(y as usize * SCREEN_WIDTH) + x as usize] = color };
} else {
return Err(()); // Not enough data
}
}
}
// Optional: check that we consumed *exactly* the right amount
if color_iter.next().is_some() {
return Err(()); // Too much data
}
Ok(())
}
// walk the dirty tiles and mark groups of tiles(meta-tiles) for batched updates
fn find_meta_tiles(&mut self, tiles_x: usize, tiles_y: usize) -> MetaTileVec {
let mut meta_tiles: MetaTileVec = Vec::new();
for ty in 0..tiles_y {
let mut tx = 0;
while tx < tiles_x {
let idx = ty * tiles_x + tx;
if !unsafe { DIRTY_TILES.get()[idx].load(Ordering::Acquire) } {
tx += 1;
continue;
}
// Start meta-tile at this tile
let mut width_tiles = 1;
let height_tiles = 1;
// Grow horizontally, but keep under MAX_TILES_PER_METATILE
while tx + width_tiles < tiles_x
&& unsafe {
DIRTY_TILES.get()[ty * tiles_x + tx + width_tiles].load(Ordering::Relaxed)
}
&& (width_tiles + height_tiles) <= MAX_META_TILES
{
width_tiles += 1;
}
// TODO: for simplicity, skipped vertical growth
for x_off in 0..width_tiles {
unsafe {
DIRTY_TILES.get()[ty * tiles_x + tx + x_off]
.store(false, Ordering::Release);
};
}
// new meta-tile pos
let rect = Rectangle::new(
Point::new((tx * TILE_SIZE) as i32, (ty * TILE_SIZE) as i32),
Size::new(
(width_tiles * TILE_SIZE) as u32,
(height_tiles * TILE_SIZE) as u32,
),
);
if meta_tiles.push(rect).is_err() {
return meta_tiles;
};
tx += width_tiles;
}
}
meta_tiles
}
/// Sends the entire framebuffer to the display
pub async fn draw<SPI, DC, RST, DELAY: DelayNs>(
&mut self,
display: &mut ST7365P<SPI, DC, RST, DELAY>,
) -> Result<(), ()>
where
SPI: SpiDevice,
DC: OutputPin,
RST: OutputPin,
{
display
.set_pixels_buffered(
0,
0,
self.size().width as u16 - 1,
self.size().height as u16 - 1,
unsafe { &BUFFER },
)
.await?;
unsafe {
for tile in DIRTY_TILES.get_mut().iter() {
tile.store(false, Ordering::Release);
}
};
Ok(())
}
/// Sends only dirty tiles (16x16px) individually to the display without batching
pub async fn partial_draw<SPI, DC, RST, DELAY: DelayNs>(
&mut self,
display: &mut ST7365P<SPI, DC, RST, DELAY>,
) -> Result<(), ()>
where
SPI: SpiDevice,
DC: OutputPin,
RST: OutputPin,
{
if unsafe { DIRTY_TILES.get().iter().any(|p| p.load(Ordering::Acquire)) } {
let tiles_x = (SCREEN_WIDTH + TILE_SIZE - 1) / TILE_SIZE;
let tiles_y = (SCREEN_HEIGHT + TILE_SIZE - 1) / TILE_SIZE;
let mut tile_buffer = [0u16; TILE_SIZE * TILE_SIZE];
for ty in 0..tiles_y {
for tx in 0..tiles_x {
if unsafe { !DIRTY_TILES.get()[ty * tiles_x + tx].load(Ordering::Acquire) } {
continue;
}
let x = tx * TILE_SIZE;
let y = ty * TILE_SIZE;
// Copy pixels for the tile into tile_buffer
for row in 0..TILE_SIZE {
for col in 0..TILE_SIZE {
let actual_x = x + col;
let actual_y = y + row;
if actual_x < SCREEN_WIDTH && actual_y < SCREEN_HEIGHT {
let idx = actual_y * SCREEN_WIDTH + actual_x;
tile_buffer[row * TILE_SIZE + col] = unsafe { BUFFER[idx] };
} else {
// Out of bounds, fill with zero (or background)
tile_buffer[row * TILE_SIZE + col] = 0;
}
}
}
// Send the tile's pixel data to the display
display
.set_pixels_buffered(
x as u16,
y as u16,
(x + TILE_SIZE - 1).min(SCREEN_WIDTH - 1) as u16,
(y + TILE_SIZE - 1).min(SCREEN_HEIGHT - 1) as u16,
&tile_buffer,
)
.await?;
// Mark tile as clean
unsafe {
DIRTY_TILES.get_mut()[ty * tiles_x + tx].store(false, Ordering::Release)
};
}
}
}
Ok(())
}
/// Sends only dirty tiles (16x16px) in batches to the display
pub async fn partial_draw_batched<SPI, DC, RST, DELAY>(
&mut self,
display: &mut ST7365P<SPI, DC, RST, DELAY>,
) -> Result<(), ()>
where
SPI: SpiDevice,
DC: OutputPin,
RST: OutputPin,
DELAY: DelayNs,
{
if unsafe { DIRTY_TILES.get().iter().any(|p| p.load(Ordering::Acquire)) } {
let tiles_x = (SCREEN_WIDTH + TILE_SIZE - 1) / TILE_SIZE;
let tiles_y = (SCREEN_HEIGHT + TILE_SIZE - 1) / TILE_SIZE;
let meta_tiles = self.find_meta_tiles(tiles_x, tiles_y);
// buffer for copying meta tiles before sending to display
let mut pixel_buffer: heapless::Vec<u16, { MAX_META_TILES * TILE_SIZE * TILE_SIZE }> =
Vec::new();
for rect in meta_tiles {
let rect_width = rect.size.width as usize;
let rect_height = rect.size.height as usize;
let rect_x = rect.top_left.x as usize;
let rect_y = rect.top_left.y as usize;
pixel_buffer.clear();
for row in 0..rect_height {
let y = rect_y + row;
let start = y * SCREEN_WIDTH + rect_x;
let end = start + rect_width;
// Safe: we guarantee buffer will not exceed MAX_META_TILE_PIXELS
pixel_buffer
.extend_from_slice(unsafe { &BUFFER[start..end] })
.unwrap();
}
display
.set_pixels_buffered(
rect_x as u16,
rect_y as u16,
(rect_x + rect_width - 1) as u16,
(rect_y + rect_height - 1) as u16,
&pixel_buffer,
)
.await?;
// walk the meta-tile and set as clean
let start_tx = rect_x / TILE_SIZE;
let start_ty = rect_y / TILE_SIZE;
let end_tx = (rect_x + rect_width - 1) / TILE_SIZE;
let end_ty = (rect_y + rect_height - 1) / TILE_SIZE;
for ty in start_ty..=end_ty {
for tx in start_tx..=end_tx {
let tile_idx = ty * tiles_x + tx;
unsafe { DIRTY_TILES.get_mut()[tile_idx].store(false, Ordering::Release) };
}
}
}
}
Ok(())
}
}
impl DrawTarget for AtomicFrameBuffer {
type Error = ();
type Color = Rgb565;
fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
where
I: IntoIterator<Item = Pixel<Self::Color>>,
{
let mut dirty_rect: Option<Rectangle> = None;
for Pixel(coord, color) in pixels {
if coord.x >= 0 && coord.y >= 0 {
let x = coord.x as i32;
let y = coord.y as i32;
if (x as usize) < SCREEN_WIDTH && (y as usize) < SCREEN_HEIGHT {
unsafe {
BUFFER[(y as usize) * SCREEN_WIDTH + (x as usize)] =
RawU16::from(color).into_inner()
};
if let Some(ref mut rect) = dirty_rect {
rect.top_left.x = rect.top_left.x.min(x);
rect.top_left.y = rect.top_left.y.min(y);
let max_x = (rect.top_left.x + rect.size.width as i32 - 1).max(x);
let max_y = (rect.top_left.y + rect.size.height as i32 - 1).max(y);
rect.size.width = (max_x - rect.top_left.x + 1) as u32;
rect.size.height = (max_y - rect.top_left.y + 1) as u32;
} else {
dirty_rect = Some(Rectangle::new(Point::new(x, y), Size::new(1, 1)));
}
}
}
}
if let Some(rect) = dirty_rect {
self.mark_tiles_dirty(rect);
}
Ok(())
}
fn fill_contiguous<I>(&mut self, area: &Rectangle, colors: I) -> Result<(), Self::Error>
where
I: IntoIterator<Item = Self::Color>,
{
let drawable_area = area.intersection(&Rectangle::new(Point::zero(), self.size()));
if drawable_area.size != Size::zero() {
// We assume that `colors` iterator is in row-major order for the original `area`
// So we must skip rows/pixels that are clipped
let area_width = area.size.width;
let area_height = area.size.height;
let mut colors = colors.into_iter();
for y in 0..area_height {
for x in 0..area_width {
let p = area.top_left + Point::new(x as i32, y as i32);
if drawable_area.contains(p) {
if let Some(color) = colors.next() {
self.set_pixel(
p.x as u16,
p.y as u16,
RawU16::from(color).into_inner(),
)?;
} else {
break;
}
} else {
// Still need to consume the color even if not used!
let _ = colors.next();
}
}
}
self.mark_tiles_dirty(*area);
}
Ok(())
}
fn fill_solid(&mut self, area: &Rectangle, color: Self::Color) -> Result<(), Self::Error> {
self.fill_contiguous(
area,
core::iter::repeat(color).take((self.size().width * self.size().height) as usize),
)
}
fn clear(&mut self, color: Self::Color) -> Result<(), Self::Error> {
self.set_pixels_buffered(
0,
0,
self.size().width as u16 - 1,
self.size().height as u16 - 1,
core::iter::repeat(RawU16::from(color).into_inner())
.take((self.size().width * self.size().height) as usize),
)?;
unsafe {
for tile in DIRTY_TILES.get_mut().iter() {
tile.store(true, Ordering::Relaxed);
}
}
Ok(())
}
}
impl OriginDimensions for AtomicFrameBuffer {
fn size(&self) -> Size {
Size::new(SCREEN_WIDTH as u32, SCREEN_HEIGHT as u32)
}
}

View File

@@ -10,7 +10,6 @@ extern crate alloc;
mod abi; mod abi;
mod display; mod display;
mod elf; mod elf;
mod framebuffer;
mod peripherals; mod peripherals;
mod scsi; mod scsi;
mod storage; mod storage;
@@ -19,8 +18,7 @@ mod usb;
mod utils; mod utils;
use crate::{ use crate::{
display::{FRAMEBUFFER, clear_fb, display_handler, init_display}, display::{display_handler, framebuffer_mut, init_display},
elf::load_binary,
peripherals::{ peripherals::{
conf_peripherals, conf_peripherals,
keyboard::{KeyCode, KeyState, read_keyboard_fifo}, keyboard::{KeyCode, KeyState, read_keyboard_fifo},
@@ -29,16 +27,11 @@ use crate::{
ui::{SELECTIONS, ui_handler}, ui::{SELECTIONS, ui_handler},
usb::usb_handler, usb::usb_handler,
}; };
use abi_sys::EntryFn; use abi_sys::{EntryFn, Rgb565, RgbColor};
use {defmt_rtt as _, panic_probe as _};
use assign_resources::assign_resources;
use defmt::unwrap; use defmt::unwrap;
use embassy_executor::{Executor, Spawner}; use embassy_executor::{Executor, Spawner};
use embassy_futures::join::{join, join3, join4, join5}; use embassy_futures::join::{join, join3, join4, join5};
use embassy_rp::{ use embassy_rp::{
Peri,
gpio::{Input, Level, Output, Pull}, gpio::{Input, Level, Output, Pull},
i2c::{self, I2c}, i2c::{self, I2c},
multicore::{Stack, spawn_core1}, multicore::{Stack, spawn_core1},
@@ -53,12 +46,14 @@ use embassy_sync::{
blocking_mutex::raw::CriticalSectionRawMutex, channel::Channel, mutex::Mutex, signal::Signal, blocking_mutex::raw::CriticalSectionRawMutex, channel::Channel, mutex::Mutex, signal::Signal,
}; };
use embassy_time::{Delay, Timer}; use embassy_time::{Delay, Timer};
use embedded_graphics::draw_target::DrawTarget;
use embedded_hal_bus::spi::ExclusiveDevice; use embedded_hal_bus::spi::ExclusiveDevice;
use embedded_sdmmc::SdCard as SdmmcSdCard; use embedded_sdmmc::SdCard as SdmmcSdCard;
use heapless::spsc::Queue; use heapless::spsc::Queue;
use shared::keyboard::KeyEvent; use shared::keyboard::KeyEvent;
use static_cell::StaticCell; use static_cell::StaticCell;
use talc::*; use talc::*;
use {defmt_rtt as _, panic_probe as _};
embassy_rp::bind_interrupts!(struct Irqs { embassy_rp::bind_interrupts!(struct Irqs {
I2C1_IRQ => i2c::InterruptHandler<I2C1>; I2C1_IRQ => i2c::InterruptHandler<I2C1>;
@@ -79,7 +74,7 @@ static ALLOCATOR: Talck<spin::Mutex<()>, ClaimOnOom> =
static TASK_STATE: Mutex<CriticalSectionRawMutex, TaskState> = Mutex::new(TaskState::Ui); static TASK_STATE: Mutex<CriticalSectionRawMutex, TaskState> = Mutex::new(TaskState::Ui);
static TASK_STATE_CHANGED: Signal<CriticalSectionRawMutex, ()> = Signal::new(); static TASK_STATE_CHANGED: Signal<CriticalSectionRawMutex, ()> = Signal::new();
#[derive(Copy, Clone, PartialEq)] #[derive(Copy, Clone)]
enum TaskState { enum TaskState {
Ui, Ui,
Kernel, Kernel,
@@ -135,54 +130,61 @@ async fn userland_task() {
let recv = BINARY_CH.receiver(); let recv = BINARY_CH.receiver();
loop { loop {
let entry = recv.receive().await; let entry = recv.receive().await;
defmt::info!("Got Entry"); defmt::info!("got bin");
// disable kernel ui // disable kernel ui
{ {
let mut state = TASK_STATE.lock().await; let mut state = TASK_STATE.lock().await;
*state = TaskState::Kernel; *state = TaskState::Kernel;
TASK_STATE_CHANGED.signal(());
} }
// clear_fb(); {
let fb = framebuffer_mut();
fb.clear(Rgb565::BLACK).unwrap();
}
defmt::info!("Executing Binary"); defmt::info!("running entry");
entry().await; entry().await;
// enable kernel ui // enable kernel ui
{ {
let mut state = TASK_STATE.lock().await; let mut state = TASK_STATE.lock().await;
*state = TaskState::Ui; *state = TaskState::Ui;
TASK_STATE_CHANGED.signal(());
} }
} }
} }
struct Display { struct Display {
spi: Peri<'static, SPI1>, spi: SPI1,
clk: Peri<'static, PIN_10>, clk: PIN_10,
mosi: Peri<'static, PIN_11>, mosi: PIN_11,
miso: Peri<'static, PIN_12>, miso: PIN_12,
dma1: Peri<'static, DMA_CH0>, dma1: DMA_CH0,
dma2: Peri<'static, DMA_CH1>, dma2: DMA_CH1,
cs: Peri<'static, PIN_13>, cs: PIN_13,
data: Peri<'static, PIN_14>, data: PIN_14,
reset: Peri<'static, PIN_15>, reset: PIN_15,
} }
struct Sd { struct Sd {
spi: Peri<'static, SPI0>, spi: SPI0,
clk: Peri<'static, PIN_18>, clk: PIN_18,
mosi: Peri<'static, PIN_19>, mosi: PIN_19,
miso: Peri<'static, PIN_16>, miso: PIN_16,
cs: Peri<'static, PIN_17>, cs: PIN_17,
det: Peri<'static, PIN_22>, det: PIN_22,
} }
struct Mcu { struct Mcu {
i2c: Peri<'static, I2C1>, i2c: I2C1,
clk: Peri<'static, PIN_7>, clk: PIN_7,
data: Peri<'static, PIN_6>, data: PIN_6,
} }
#[embassy_executor::task] #[embassy_executor::task]
async fn kernel_task(display: Display, sd: Sd, mcu: Mcu, usb: Peri<'static, USB>) { async fn kernel_task(display: Display, sd: Sd, mcu: Mcu, usb: USB) {
// MCU i2c bus for peripherals // MCU i2c bus for peripherals
let mut config = i2c::Config::default(); let mut config = i2c::Config::default();
config.frequency = 400_000; config.frequency = 400_000;
@@ -242,8 +244,8 @@ async fn kernel_task(display: Display, sd: Sd, mcu: Mcu, usb: Peri<'static, USB>
SDCARD.get().lock().await.replace(SdCard::new(sdcard, det)); SDCARD.get().lock().await.replace(SdCard::new(sdcard, det));
}; };
let usb = embassy_rp_usb::Driver::new(usb, Irqs); // let usb = embassy_rp_usb::Driver::new(usb, Irqs);
let usb_fut = usb_handler(usb); // let usb_fut = usb_handler(usb);
let key_abi_fut = async { let key_abi_fut = async {
loop { loop {
@@ -252,17 +254,15 @@ async fn kernel_task(display: Display, sd: Sd, mcu: Mcu, usb: Peri<'static, USB>
} }
}; };
join5(display_fut, ui_fut, usb_fut, binary_search_fut, key_abi_fut).await; join4(display_fut, ui_fut, binary_search_fut, key_abi_fut).await;
} }
static mut KEY_CACHE: Queue<KeyEvent, 32> = Queue::new(); static mut KEY_CACHE: Queue<KeyEvent, 32> = Queue::new();
async fn get_keys() { async fn get_keys() {
if let Some(event) = read_keyboard_fifo().await { if let Some(event) = read_keyboard_fifo().await {
if let KeyState::Pressed = event.state {
unsafe { unsafe {
let _ = KEY_CACHE.enqueue(event); let _ = KEY_CACHE.enqueue(event);
} }
} }
} }
}

View File

@@ -5,9 +5,7 @@ use embassy_rp::{
i2c::{Async, I2c}, i2c::{Async, I2c},
peripherals::I2C1, peripherals::I2C1,
}; };
use embassy_sync::{ use embassy_sync::{blocking_mutex::raw::NoopRawMutex, lazy_lock::LazyLock, mutex::Mutex};
blocking_mutex::raw::CriticalSectionRawMutex, lazy_lock::LazyLock, mutex::Mutex,
};
use embassy_time::Timer; use embassy_time::Timer;
pub mod keyboard; pub mod keyboard;
@@ -17,7 +15,7 @@ use crate::peripherals::keyboard::{configure_keyboard, read_keyboard_fifo};
const MCU_ADDR: u8 = 0x1F; const MCU_ADDR: u8 = 0x1F;
type I2CBUS = I2c<'static, I2C1, Async>; type I2CBUS = I2c<'static, I2C1, Async>;
pub static PERIPHERAL_BUS: LazyLock<Mutex<CriticalSectionRawMutex, Option<I2CBUS>>> = pub static PERIPHERAL_BUS: LazyLock<Mutex<NoopRawMutex, Option<I2CBUS>>> =
LazyLock::new(|| Mutex::new(None)); LazyLock::new(|| Mutex::new(None));
const REG_ID_VER: u8 = 0x01; const REG_ID_VER: u8 = 0x01;

View File

@@ -8,25 +8,30 @@ use heapless::Vec;
mod scsi_types; mod scsi_types;
use scsi_types::*; use scsi_types::*;
use crate::storage::{SDCARD, SdCard}; use crate::storage::SdCard;
const BULK_ENDPOINT_PACKET_SIZE: usize = 64; const BULK_ENDPOINT_PACKET_SIZE: usize = 64;
pub struct MassStorageClass<'d, D: Driver<'d>> { pub struct MassStorageClass<'d, 's, D: Driver<'d>> {
sdcard: &'s SdCard,
bulk_out: D::EndpointOut, bulk_out: D::EndpointOut,
bulk_in: D::EndpointIn, bulk_in: D::EndpointIn,
} }
impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, D> { impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, 's, D> {
pub fn new(builder: &mut Builder<'d, D>) -> Self { pub fn new(builder: &mut Builder<'d, D>, sdcard: &'s SdCard) -> Self {
let mut function = builder.function(0x08, SUBCLASS_SCSI, 0x50); // Mass Storage class let mut function = builder.function(0x08, SUBCLASS_SCSI, 0x50); // Mass Storage class
let mut interface = function.interface(); let mut interface = function.interface();
let mut alt = interface.alt_setting(0x08, SUBCLASS_SCSI, 0x50, None); let mut alt = interface.alt_setting(0x08, SUBCLASS_SCSI, 0x50, None);
let bulk_out = alt.endpoint_bulk_out(None, BULK_ENDPOINT_PACKET_SIZE as u16); let bulk_out = alt.endpoint_bulk_out(BULK_ENDPOINT_PACKET_SIZE as u16);
let bulk_in = alt.endpoint_bulk_in(None, BULK_ENDPOINT_PACKET_SIZE as u16); let bulk_in = alt.endpoint_bulk_in(BULK_ENDPOINT_PACKET_SIZE as u16);
Self { bulk_out, bulk_in } Self {
bulk_out,
bulk_in,
sdcard,
}
} }
pub async fn poll(&mut self) { pub async fn poll(&mut self) {
@@ -134,9 +139,7 @@ impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, D> {
self.bulk_in.write(&response[..len]).await.map_err(|_| ()) self.bulk_in.write(&response[..len]).await.map_err(|_| ())
} }
ScsiCommand::TestUnitReady => { ScsiCommand::TestUnitReady => {
let guard = SDCARD.get().lock().await; if self.sdcard.is_attached() {
let sdcard = guard.as_ref().unwrap();
if sdcard.is_attached() {
Ok(()) Ok(())
} else { } else {
Err(()) Err(())
@@ -182,11 +185,8 @@ impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, D> {
self.bulk_in.write(&response[..len]).await.map_err(|_| ()) self.bulk_in.write(&response[..len]).await.map_err(|_| ())
} }
ScsiCommand::ReadCapacity10 => { ScsiCommand::ReadCapacity10 => {
let guard = SDCARD.get().lock().await;
let sdcard = guard.as_ref().unwrap();
let block_size = SdCard::BLOCK_SIZE as u64; let block_size = SdCard::BLOCK_SIZE as u64;
let total_blocks = sdcard.size() / block_size; let total_blocks = self.sdcard.size() / block_size;
let last_lba = total_blocks.checked_sub(1).unwrap_or(0); let last_lba = total_blocks.checked_sub(1).unwrap_or(0);
@@ -196,11 +196,8 @@ impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, D> {
self.bulk_in.write(&response).await.map_err(|_| ()) self.bulk_in.write(&response).await.map_err(|_| ())
} }
ScsiCommand::ReadCapacity16 { alloc_len } => { ScsiCommand::ReadCapacity16 { alloc_len } => {
let guard = SDCARD.get().lock().await;
let sdcard = guard.as_ref().unwrap();
let block_size = SdCard::BLOCK_SIZE as u64; let block_size = SdCard::BLOCK_SIZE as u64;
let total_blocks = sdcard.size() / block_size; let total_blocks = self.sdcard.size() / block_size;
let last_lba = total_blocks.checked_sub(1).unwrap_or(0); let last_lba = total_blocks.checked_sub(1).unwrap_or(0);
@@ -212,12 +209,9 @@ impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, D> {
self.bulk_in.write(&response[..len]).await.map_err(|_| ()) self.bulk_in.write(&response[..len]).await.map_err(|_| ())
} }
ScsiCommand::Read { lba, len } => { ScsiCommand::Read { lba, len } => {
let guard = SDCARD.get().lock().await;
let sdcard = guard.as_ref().unwrap();
for i in 0..len { for i in 0..len {
let block_idx = BlockIdx(lba as u32 + i as u32); let block_idx = BlockIdx(lba as u32 + i as u32);
sdcard.read_blocks(&mut block, block_idx)?; self.sdcard.read_blocks(&mut block, block_idx)?;
for chunk in block[0].contents.chunks(BULK_ENDPOINT_PACKET_SIZE.into()) { for chunk in block[0].contents.chunks(BULK_ENDPOINT_PACKET_SIZE.into()) {
self.bulk_in.write(chunk).await.map_err(|_| ())?; self.bulk_in.write(chunk).await.map_err(|_| ())?;
} }
@@ -225,9 +219,6 @@ impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, D> {
Ok(()) Ok(())
} }
ScsiCommand::Write { lba, len } => { ScsiCommand::Write { lba, len } => {
let guard = SDCARD.get().lock().await;
let sdcard = guard.as_ref().unwrap();
for i in 0..len { for i in 0..len {
let block_idx = BlockIdx(lba as u32 + i as u32); let block_idx = BlockIdx(lba as u32 + i as u32);
for chunk in block[0] for chunk in block[0]
@@ -236,16 +227,13 @@ impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, D> {
{ {
self.bulk_out.read(chunk).await.map_err(|_| ())?; self.bulk_out.read(chunk).await.map_err(|_| ())?;
} }
sdcard.write_blocks(&mut block, block_idx)?; self.sdcard.write_blocks(&mut block, block_idx)?;
} }
Ok(()) Ok(())
} }
ScsiCommand::ReadFormatCapacities { alloc_len } => { ScsiCommand::ReadFormatCapacities { alloc_len } => {
let guard = SDCARD.get().lock().await;
let sdcard = guard.as_ref().unwrap();
let block_size = SdCard::BLOCK_SIZE as u32; let block_size = SdCard::BLOCK_SIZE as u32;
let num_blocks = (sdcard.size() / block_size as u64) as u32; let num_blocks = (self.sdcard.size() / block_size as u64) as u32;
let mut response = [0u8; 12]; let mut response = [0u8; 12];

View File

@@ -3,7 +3,7 @@ use core::str::FromStr;
use embassy_rp::gpio::{Input, Output}; use embassy_rp::gpio::{Input, Output};
use embassy_rp::peripherals::SPI0; use embassy_rp::peripherals::SPI0;
use embassy_rp::spi::{Blocking, Spi}; use embassy_rp::spi::{Blocking, Spi};
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::raw::NoopRawMutex;
use embassy_sync::lazy_lock::LazyLock; use embassy_sync::lazy_lock::LazyLock;
use embassy_sync::mutex::Mutex; use embassy_sync::mutex::Mutex;
use embassy_time::Delay; use embassy_time::Delay;
@@ -25,7 +25,7 @@ type Vol<'a> = Volume<'a, SD, DummyTimeSource, MAX_DIRS, MAX_FILES, MAX_VOLUMES>
type Dir<'a> = Directory<'a, SD, DummyTimeSource, MAX_DIRS, MAX_FILES, MAX_VOLUMES>; type Dir<'a> = Directory<'a, SD, DummyTimeSource, MAX_DIRS, MAX_FILES, MAX_VOLUMES>;
pub type File<'a> = SdFile<'a, SD, DummyTimeSource, MAX_DIRS, MAX_FILES, MAX_VOLUMES>; pub type File<'a> = SdFile<'a, SD, DummyTimeSource, MAX_DIRS, MAX_FILES, MAX_VOLUMES>;
pub static SDCARD: LazyLock<Mutex<CriticalSectionRawMutex, Option<SdCard>>> = pub static SDCARD: LazyLock<Mutex<NoopRawMutex, Option<SdCard>>> =
LazyLock::new(|| Mutex::new(None)); LazyLock::new(|| Mutex::new(None));
pub struct DummyTimeSource {} pub struct DummyTimeSource {}

View File

@@ -1,25 +1,40 @@
use crate::{ use crate::{
BINARY_CH, TASK_STATE, TaskState, BINARY_CH, TASK_STATE, TaskState,
display::{FRAMEBUFFER, SCREEN_HEIGHT, SCREEN_WIDTH}, display::{SCREEN_HEIGHT, SCREEN_WIDTH, framebuffer_mut},
elf::load_binary, elf::load_binary,
format, format,
peripherals::keyboard, peripherals::keyboard,
storage::FileName, storage::FileName,
usb::RESTART_USB,
}; };
use alloc::{string::String, vec::Vec}; use alloc::{string::String, vec::Vec};
use core::{fmt::Debug, str::FromStr, sync::atomic::Ordering}; use core::{fmt::Debug, str::FromStr, sync::atomic::Ordering};
use defmt::info;
use embassy_rp::{
gpio::{Level, Output},
peripherals::{PIN_13, PIN_14, PIN_15, SPI1},
spi::{Async, Spi},
};
use embassy_sync::{ use embassy_sync::{
blocking_mutex::raw::{CriticalSectionRawMutex, ThreadModeRawMutex}, blocking_mutex::raw::{CriticalSectionRawMutex, ThreadModeRawMutex},
mutex::Mutex, mutex::Mutex,
signal::Signal,
}; };
use embassy_time::{Delay, Timer};
use embedded_graphics::{ use embedded_graphics::{
Drawable, Drawable,
mono_font::{MonoTextStyle, ascii::FONT_9X15}, draw_target::DrawTarget,
mono_font::{
MonoTextStyle,
ascii::{FONT_6X9, FONT_6X10, FONT_9X15, FONT_10X20},
},
pixelcolor::Rgb565, pixelcolor::Rgb565,
prelude::{Dimensions, Point, RgbColor, Size}, prelude::{Dimensions, Point, Primitive, RgbColor, Size},
primitives::Rectangle, primitives::{PrimitiveStyle, Rectangle, StyledDrawable},
text::Text, text::Text,
}; };
use embedded_hal_async::spi::SpiDevice;
use embedded_hal_bus::spi::{ExclusiveDevice, NoDelay};
use embedded_layout::{ use embedded_layout::{
align::{horizontal, vertical}, align::{horizontal, vertical},
layout::linear::LinearLayout, layout::linear::LinearLayout,
@@ -32,38 +47,51 @@ use shared::keyboard::{KeyCode, KeyState};
pub static SELECTIONS: Mutex<CriticalSectionRawMutex, SelectionList> = pub static SELECTIONS: Mutex<CriticalSectionRawMutex, SelectionList> =
Mutex::new(SelectionList::new()); Mutex::new(SelectionList::new());
pub async fn run_selected() {
info!("Getting selections lock");
let selections = SELECTIONS.lock().await;
info!("Got selections lock");
let selection = selections.selections[selections.current_selection as usize - 1].clone();
let entry = unsafe { load_binary(&selection.short_name).await.unwrap() };
info!("loaded binary");
BINARY_CH.send(entry).await;
info!("sent bin");
}
pub async fn ui_handler() { pub async fn ui_handler() {
loop { loop {
if let TaskState::Ui = *TASK_STATE.lock().await { let state = *TASK_STATE.lock().await;
if let TaskState::Ui = state {
let mut redraw = false;
if let Some(event) = keyboard::read_keyboard_fifo().await { if let Some(event) = keyboard::read_keyboard_fifo().await {
if let KeyState::Pressed = event.state { if event.state == KeyState::Pressed {
match event.key { match event.key {
KeyCode::JoyUp => { KeyCode::JoyUp => {
let mut selections = SELECTIONS.lock().await; let mut selections = SELECTIONS.lock().await;
selections.up(); selections.up();
redraw = true;
} }
KeyCode::JoyDown => { KeyCode::JoyDown => {
let mut selections = SELECTIONS.lock().await; let mut selections = SELECTIONS.lock().await;
selections.down(); selections.down();
redraw = true;
} }
KeyCode::Enter | KeyCode::JoyRight => { KeyCode::Enter | KeyCode::JoyRight => run_selected().await,
let selections = SELECTIONS.lock().await; _ => {}
let selection = selections.selections
[selections.current_selection as usize - 1]
.clone();
let entry =
unsafe { load_binary(&selection.short_name).await.unwrap() };
BINARY_CH.send(entry).await;
}
_ => (),
} }
} }
} }
{
let mut selections = SELECTIONS.lock().await;
redraw |= selections.take_changed();
}
if redraw {
draw_selection().await; draw_selection().await;
} else { }
embassy_time::Timer::after_millis(50).await;
} }
} }
} }
@@ -74,8 +102,9 @@ async fn draw_selection() {
guard.selections.clone() guard.selections.clone()
}; };
let fb = framebuffer_mut();
let text_style = MonoTextStyle::new(&FONT_9X15, Rgb565::WHITE); let text_style = MonoTextStyle::new(&FONT_9X15, Rgb565::WHITE);
let display_area = unsafe { FRAMEBUFFER.bounding_box() }; let display_area = fb.bounding_box();
const NO_BINS: &str = "No Programs found on SD Card. Ensure programs end with '.bin', and are located in the root directory"; const NO_BINS: &str = "No Programs found on SD Card. Ensure programs end with '.bin', and are located in the root directory";
let no_bins = String::from_str(NO_BINS).unwrap(); let no_bins = String::from_str(NO_BINS).unwrap();
@@ -89,14 +118,13 @@ async fn draw_selection() {
), ),
text_style, text_style,
) )
.draw(unsafe { &mut FRAMEBUFFER }) .draw(fb)
.unwrap(); .unwrap();
} else { } else {
let mut file_names = file_names.iter(); let mut file_names = file_names.iter();
let Some(first) = file_names.next() else { let Some(first) = file_names.next() else {
Text::new(NO_BINS, Point::zero(), text_style) Text::new("No Programs found on SD Card\nEnsure programs end with '.bin',\nand are located in the root directory",
.draw(unsafe { &mut FRAMEBUFFER }) Point::zero(), text_style).draw(fb).unwrap();
.unwrap();
return; return;
}; };
@@ -115,15 +143,16 @@ async fn draw_selection() {
.with_alignment(horizontal::Center) .with_alignment(horizontal::Center)
.arrange() .arrange()
.align_to(&display_area, horizontal::Center, vertical::Center) .align_to(&display_area, horizontal::Center, vertical::Center)
.draw(unsafe { &mut FRAMEBUFFER }) .draw(fb)
.unwrap(); .unwrap();
} };
} }
#[derive(Clone)] #[derive(Clone)]
pub struct SelectionList { pub struct SelectionList {
current_selection: u16, current_selection: u16,
pub selections: Vec<FileName>, pub selections: Vec<FileName>,
has_changed: bool,
} }
impl SelectionList { impl SelectionList {
@@ -131,6 +160,7 @@ impl SelectionList {
Self { Self {
selections: Vec::new(), selections: Vec::new(),
current_selection: 0, current_selection: 0,
has_changed: true,
} }
} }
@@ -149,4 +179,10 @@ impl SelectionList {
self.current_selection -= 1 self.current_selection -= 1
} }
} }
pub fn take_changed(&mut self) -> bool {
let changed = self.has_changed;
self.has_changed = false;
changed
}
} }

View File

@@ -1,10 +1,20 @@
use crate::{TASK_STATE, TASK_STATE_CHANGED, TaskState, scsi::MassStorageClass}; use core::sync::atomic::Ordering;
use crate::{
scsi::MassStorageClass,
storage::{SDCARD, SdCard},
};
use embassy_futures::{ use embassy_futures::{
join::join, join::join,
select::{select, select3}, select::{select, select3},
}; };
use embassy_rp::{peripherals::USB, usb::Driver}; use embassy_rp::{peripherals::USB, usb::Driver};
use embassy_sync::{blocking_mutex::raw::ThreadModeRawMutex, signal::Signal};
use embassy_usb::{Builder, Config}; use embassy_usb::{Builder, Config};
use portable_atomic::AtomicBool;
pub static RESTART_USB: Signal<ThreadModeRawMutex, ()> = Signal::new();
pub static ENABLE_SCSI: AtomicBool = AtomicBool::new(false);
pub async fn usb_handler(driver: Driver<'static, USB>) { pub async fn usb_handler(driver: Driver<'static, USB>) {
let mut config = Config::new(0xc0de, 0xbabe); let mut config = Config::new(0xc0de, 0xbabe);
@@ -27,17 +37,27 @@ pub async fn usb_handler(driver: Driver<'static, USB>) {
&mut control_buf, &mut control_buf,
); );
let mut scsi = MassStorageClass::new(&mut builder); let lock = SDCARD.get().lock().await;
let sdcard = lock.as_ref().unwrap();
let mut scsi = MassStorageClass::new(&mut builder, &sdcard);
let mut usb = builder.build(); let mut usb = builder.build();
loop { loop {
defmt::info!("in: {}", *TASK_STATE.lock().await as u32); select3(
if *TASK_STATE.lock().await == TaskState::Ui { async {
defmt::info!("running scsi and usb"); loop {
select(join(usb.run(), scsi.poll()), TASK_STATE_CHANGED.wait()).await; RESTART_USB.wait().await;
} else { return;
defmt::info!("not in ui state"); }
TASK_STATE_CHANGED.wait().await; },
} usb.run(),
async {
if ENABLE_SCSI.load(Ordering::Acquire) {
scsi.poll().await
}
},
)
.await;
} }
} }

View File

@@ -2,7 +2,7 @@
#![no_main] #![no_main]
extern crate alloc; extern crate alloc;
use abi::{KeyCode, display::Display, embassy_time, get_key, print, sleep}; use abi::{KeyCode, display::Display, embassy_time, get_key, print};
use alloc::{boxed::Box, string::String, vec}; use alloc::{boxed::Box, string::String, vec};
use core::{panic::PanicInfo, pin::Pin}; use core::{panic::PanicInfo, pin::Pin};
use embedded_graphics::{ use embedded_graphics::{
@@ -10,8 +10,7 @@ use embedded_graphics::{
geometry::{Dimensions, Point}, geometry::{Dimensions, Point},
mono_font::{MonoTextStyle, ascii::FONT_6X10}, mono_font::{MonoTextStyle, ascii::FONT_6X10},
pixelcolor::Rgb565, pixelcolor::Rgb565,
prelude::{Primitive, RgbColor, Size}, prelude::RgbColor,
primitives::{PrimitiveStyle, Rectangle},
text::{Alignment, Text}, text::{Alignment, Text},
}; };
@@ -26,49 +25,31 @@ pub async fn main() {
let character_style = MonoTextStyle::new(&FONT_6X10, Rgb565::RED); let character_style = MonoTextStyle::new(&FONT_6X10, Rgb565::RED);
let mut text = vec!['T', 'y', 'p', 'e']; let mut text = vec!['H', 'E', 'L', 'L', 'O'];
let mut dirty = true;
let mut last_bounds: Option<Rectangle> = None;
loop { // loop {
if dirty { Text::with_alignment(
if let Some(bounds) = last_bounds { &text.iter().cloned().collect::<String>(),
Rectangle::new(bounds.top_left, bounds.size) display.bounding_box().center() + Point::new(0, 15),
.into_styled(PrimitiveStyle::with_fill(Rgb565::BLACK))
.draw(&mut display)
.unwrap();
}
let text = text.iter().cloned().collect::<String>();
let aligned_text = Text::with_alignment(
&text,
display.bounding_box().center(),
character_style, character_style,
Alignment::Center, Alignment::Center,
); )
last_bounds = Some(aligned_text.bounding_box()); .draw(&mut display)
.unwrap();
aligned_text.draw(&mut display).unwrap();
dirty = false;
}
if let Some(event) = get_key() { if let Some(event) = get_key() {
dirty = true; print("User got event");
match event.key { match event.key {
KeyCode::Char(ch) => { KeyCode::Char(ch) => {
text.push(ch); text.push(ch);
} }
KeyCode::Del => {
text.clear();
}
KeyCode::Backspace => { KeyCode::Backspace => {
text.pop(); text.pop();
} }
KeyCode::Esc => return,
_ => (), _ => (),
} }
} }
} // }
} }
#[unsafe(no_mangle)] #[unsafe(no_mangle)]