mirror of
https://github.com/LegitCamper/picocalc-os-rs.git
synced 2025-12-28 00:05:28 +00:00
Compare commits
2 Commits
fix-fb
...
userland-a
| Author | SHA1 | Date | |
|---|---|---|---|
| 49b6a99ea8 | |||
| 718bcd6b5b |
212
Cargo.lock
generated
212
Cargo.lock
generated
@@ -18,7 +18,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"abi_sys",
|
||||
"embassy-time 0.5.0",
|
||||
"embedded-graphics 0.8.1",
|
||||
"embedded-graphics",
|
||||
"shared",
|
||||
"spin",
|
||||
"talc",
|
||||
@@ -28,7 +28,7 @@ dependencies = [
|
||||
name = "abi_sys"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"embedded-graphics 0.8.1",
|
||||
"embedded-graphics",
|
||||
"shared",
|
||||
]
|
||||
|
||||
@@ -77,12 +77,6 @@ dependencies = [
|
||||
"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]]
|
||||
name = "atomic-polyfill"
|
||||
version = "1.0.3"
|
||||
@@ -226,7 +220,7 @@ name = "calculator"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"abi",
|
||||
"embedded-graphics 0.8.1",
|
||||
"embedded-graphics",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -502,7 +496,7 @@ checksum = "8578db196d74db92efdd5ebc546736dac1685499ee245b22eff92fa5e4b57945"
|
||||
dependencies = [
|
||||
"embassy-futures",
|
||||
"embassy-hal-internal 0.3.0",
|
||||
"embassy-sync 0.7.2",
|
||||
"embassy-sync 0.7.0",
|
||||
"embassy-time 0.4.0",
|
||||
"embedded-hal 0.2.7",
|
||||
"embedded-hal 1.0.0",
|
||||
@@ -512,42 +506,24 @@ dependencies = [
|
||||
"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]]
|
||||
name = "embassy-executor"
|
||||
version = "0.9.1"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06070468370195e0e86f241c8e5004356d696590a678d47d6676795b2e439c6b"
|
||||
checksum = "90327bcc66333a507f89ecc4e2d911b265c45f5c9bc241f98eee076752d35ac6"
|
||||
dependencies = [
|
||||
"cortex-m",
|
||||
"critical-section",
|
||||
"defmt 1.0.1",
|
||||
"defmt 0.3.100",
|
||||
"document-features",
|
||||
"embassy-executor-macros",
|
||||
"embassy-executor-timer-queue",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "embassy-executor-macros"
|
||||
version = "0.7.0"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dfdddc3a04226828316bf31393b6903ee162238576b1584ee2669af215d55472"
|
||||
checksum = "3577b1e9446f61381179a330fc5324b01d511624c55f25e3c66c9e3c626dbecf"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
@@ -555,17 +531,11 @@ dependencies = [
|
||||
"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]]
|
||||
name = "embassy-futures"
|
||||
version = "0.1.2"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc2d050bdc5c21e0862a89256ed8029ae6c290a93aecefc73084b3002cdebb01"
|
||||
checksum = "1f878075b9794c1e4ac788c95b728f26aa6366d32eeb10c7051389f898f7d067"
|
||||
|
||||
[[package]]
|
||||
name = "embassy-hal-internal"
|
||||
@@ -575,6 +545,7 @@ checksum = "0ef3bac31ec146321248a169e9c7b5799f1e0b3829c7a9b324cb4600a7438f59"
|
||||
dependencies = [
|
||||
"cortex-m",
|
||||
"critical-section",
|
||||
"defmt 0.3.100",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
@@ -584,9 +555,6 @@ version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95285007a91b619dc9f26ea8f55452aa6c60f7115a4edc05085cd2bd3127cd7a"
|
||||
dependencies = [
|
||||
"cortex-m",
|
||||
"critical-section",
|
||||
"defmt 1.0.1",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
@@ -598,13 +566,13 @@ checksum = "524eb3c489760508f71360112bca70f6e53173e6fe48fc5f0efd0f5ab217751d"
|
||||
|
||||
[[package]]
|
||||
name = "embassy-net-driver-channel"
|
||||
version = "0.3.2"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7b2739fbcf6cd206ae08779c7d709087b16577d255f2ea4a45bc4bbbf305b3f"
|
||||
checksum = "25a567ab50319d866ad5e6c583ed665ba9b07865389644d3d82e45bf1497c934"
|
||||
dependencies = [
|
||||
"embassy-futures",
|
||||
"embassy-net-driver",
|
||||
"embassy-sync 0.7.2",
|
||||
"embassy-sync 0.7.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -619,12 +587,12 @@ dependencies = [
|
||||
"cortex-m-rt",
|
||||
"critical-section",
|
||||
"document-features",
|
||||
"embassy-embedded-hal 0.3.1",
|
||||
"embassy-embedded-hal",
|
||||
"embassy-futures",
|
||||
"embassy-hal-internal 0.2.0",
|
||||
"embassy-sync 0.6.2",
|
||||
"embassy-time 0.4.0",
|
||||
"embassy-usb-driver 0.1.1",
|
||||
"embassy-usb-driver",
|
||||
"embedded-hal 0.2.7",
|
||||
"embedded-hal 1.0.0",
|
||||
"embedded-hal-async",
|
||||
@@ -637,7 +605,7 @@ dependencies = [
|
||||
"nb 1.1.0",
|
||||
"pio 0.2.1",
|
||||
"pio-proc 0.2.2",
|
||||
"rand_core 0.6.4",
|
||||
"rand_core",
|
||||
"rp-pac",
|
||||
"rp2040-boot2",
|
||||
"sha2-const-stable",
|
||||
@@ -646,25 +614,25 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "embassy-rp"
|
||||
version = "0.8.0"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a284935af0a869de3fa14af74b5f932389dd66d7048012f1083b06f38d05399"
|
||||
checksum = "d1a063d8baccdc5c7752840f4c7931f17bcd7de1ffe1efa2109e68113fe42612"
|
||||
dependencies = [
|
||||
"atomic-polyfill",
|
||||
"cfg-if",
|
||||
"cortex-m",
|
||||
"cortex-m-rt",
|
||||
"critical-section",
|
||||
"defmt 1.0.1",
|
||||
"defmt 0.3.100",
|
||||
"document-features",
|
||||
"embassy-embedded-hal 0.5.0",
|
||||
"embassy-embedded-hal",
|
||||
"embassy-futures",
|
||||
"embassy-hal-internal 0.3.0",
|
||||
"embassy-sync 0.7.2",
|
||||
"embassy-time 0.5.0",
|
||||
"embassy-hal-internal 0.2.0",
|
||||
"embassy-sync 0.6.2",
|
||||
"embassy-time 0.4.0",
|
||||
"embassy-time-driver",
|
||||
"embassy-time-queue-utils",
|
||||
"embassy-usb-driver 0.2.0",
|
||||
"embassy-usb-driver",
|
||||
"embedded-hal 0.2.7",
|
||||
"embedded-hal 1.0.0",
|
||||
"embedded-hal-async",
|
||||
@@ -676,8 +644,7 @@ dependencies = [
|
||||
"fixed",
|
||||
"nb 1.1.0",
|
||||
"pio 0.3.0",
|
||||
"rand_core 0.6.4",
|
||||
"rand_core 0.9.3",
|
||||
"rand_core",
|
||||
"rp-pac",
|
||||
"rp2040-boot2",
|
||||
"sha2-const-stable",
|
||||
@@ -700,16 +667,16 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "embassy-sync"
|
||||
version = "0.7.2"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73974a3edbd0bd286759b3d483540f0ebef705919a5f56f4fc7709066f71689b"
|
||||
checksum = "cef1a8a1ea892f9b656de0295532ac5d8067e9830d49ec75076291fd6066b136"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"critical-section",
|
||||
"defmt 1.0.1",
|
||||
"embedded-io-async",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"futures-util",
|
||||
"heapless",
|
||||
]
|
||||
|
||||
@@ -721,8 +688,10 @@ checksum = "f820157f198ada183ad62e0a66f554c610cdcd1a9f27d4b316358103ced7a1f8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"critical-section",
|
||||
"defmt 0.3.100",
|
||||
"document-features",
|
||||
"embassy-time-driver",
|
||||
"embassy-time-queue-utils",
|
||||
"embedded-hal 0.2.7",
|
||||
"embedded-hal 1.0.0",
|
||||
"embedded-hal-async",
|
||||
@@ -737,10 +706,8 @@ checksum = "f4fa65b9284d974dad7a23bb72835c4ec85c0b540d86af7fc4098c88cff51d65"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"critical-section",
|
||||
"defmt 1.0.1",
|
||||
"document-features",
|
||||
"embassy-time-driver",
|
||||
"embassy-time-queue-utils",
|
||||
"embedded-hal 0.2.7",
|
||||
"embedded-hal 1.0.0",
|
||||
"embedded-hal-async",
|
||||
@@ -758,25 +725,24 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "embassy-time-queue-utils"
|
||||
version = "0.3.0"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "80e2ee86063bd028a420a5fb5898c18c87a8898026da1d4c852af2c443d0a454"
|
||||
checksum = "dc55c748d16908a65b166d09ce976575fb8852cf60ccd06174092b41064d8f83"
|
||||
dependencies = [
|
||||
"embassy-executor-timer-queue",
|
||||
"embassy-executor",
|
||||
"heapless",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "embassy-usb"
|
||||
version = "0.5.1"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc4462e48b19a4f401a11901bdd981aab80c6a826608016a0bdc73cbbab31954"
|
||||
checksum = "6e651b9b7b47b514e6e6d1940a6e2e300891a2c33641917130643602a0cb6386"
|
||||
dependencies = [
|
||||
"embassy-futures",
|
||||
"embassy-net-driver-channel",
|
||||
"embassy-sync 0.7.2",
|
||||
"embassy-usb-driver 0.2.0",
|
||||
"embedded-io-async",
|
||||
"embassy-sync 0.6.2",
|
||||
"embassy-usb-driver",
|
||||
"heapless",
|
||||
"ssmarshal",
|
||||
"usbd-hid",
|
||||
@@ -787,33 +753,11 @@ name = "embassy-usb-driver"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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 = [
|
||||
"defmt 1.0.1",
|
||||
"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]]
|
||||
name = "embedded-graphics"
|
||||
version = "0.8.1"
|
||||
@@ -823,19 +767,9 @@ dependencies = [
|
||||
"az",
|
||||
"byteorder",
|
||||
"defmt 0.3.100",
|
||||
"embedded-graphics-core 0.4.0",
|
||||
"float-cmp 0.9.0",
|
||||
"micromath 2.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "embedded-graphics-core"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8b1239db5f3eeb7e33e35bd10bd014e7b2537b17e071f726a09351431337cfa"
|
||||
dependencies = [
|
||||
"az",
|
||||
"byteorder",
|
||||
"embedded-graphics-core",
|
||||
"float-cmp",
|
||||
"micromath",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -916,7 +850,7 @@ version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a90553247f2b05c59ac7894ea13d830636c2b1203fa03bff400eddbd1fa9f52"
|
||||
dependencies = [
|
||||
"embedded-graphics 0.8.1",
|
||||
"embedded-graphics",
|
||||
"embedded-layout-macros",
|
||||
]
|
||||
|
||||
@@ -944,16 +878,6 @@ dependencies = [
|
||||
"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]]
|
||||
name = "embedded-storage"
|
||||
version = "0.3.1"
|
||||
@@ -976,7 +900,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "005680edc0d075af5e02d5788ca291737bd9aba7fc404ae031cc9dfa715e5f7d"
|
||||
dependencies = [
|
||||
"az",
|
||||
"embedded-graphics 0.8.1",
|
||||
"embedded-graphics",
|
||||
"object-chain",
|
||||
]
|
||||
|
||||
@@ -1025,15 +949,6 @@ version = "0.5.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "float-cmp"
|
||||
version = "0.9.0"
|
||||
@@ -1288,7 +1203,6 @@ name = "kernel"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"abi_sys",
|
||||
"assign-resources",
|
||||
"bitflags 2.9.1",
|
||||
"bt-hci",
|
||||
"cortex-m",
|
||||
@@ -1297,16 +1211,15 @@ dependencies = [
|
||||
"cyw43-pio",
|
||||
"defmt 0.3.100",
|
||||
"defmt-rtt",
|
||||
"embassy-embedded-hal 0.3.1",
|
||||
"embassy-embedded-hal",
|
||||
"embassy-executor",
|
||||
"embassy-futures",
|
||||
"embassy-rp 0.8.0",
|
||||
"embassy-sync 0.7.2",
|
||||
"embassy-time 0.5.0",
|
||||
"embassy-rp 0.4.0",
|
||||
"embassy-sync 0.7.0",
|
||||
"embassy-time 0.4.0",
|
||||
"embassy-usb",
|
||||
"embedded-graphics 0.8.1",
|
||||
"embedded-graphics",
|
||||
"embedded-hal 0.2.7",
|
||||
"embedded-hal 1.0.0",
|
||||
"embedded-hal-async",
|
||||
"embedded-hal-bus",
|
||||
"embedded-layout",
|
||||
@@ -1438,12 +1351,6 @@ version = "2.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
|
||||
|
||||
[[package]]
|
||||
name = "micromath"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc4010833aea396656c2f91ee704d51a6f1329ec2ab56ffd00bfd56f7481ea94"
|
||||
|
||||
[[package]]
|
||||
name = "micromath"
|
||||
version = "2.1.0"
|
||||
@@ -1804,12 +1711,6 @@ version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.13"
|
||||
@@ -2018,16 +1919,6 @@ dependencies = [
|
||||
"rgb",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "snake"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"abi",
|
||||
"embedded-graphics 0.8.1",
|
||||
"embedded-snake",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.10.0"
|
||||
@@ -2050,10 +1941,9 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "st7365p-lcd"
|
||||
version = "0.11.0"
|
||||
source = "git+https://github.com/legitcamper/st7365p-lcd-rs?rev=1d15123929fa7ef73d5d6aead7faf1bba50ce915#1d15123929fa7ef73d5d6aead7faf1bba50ce915"
|
||||
dependencies = [
|
||||
"bitvec",
|
||||
"embedded-graphics-core 0.4.0",
|
||||
"embedded-graphics-core",
|
||||
"embedded-hal 1.0.0",
|
||||
"embedded-hal-async",
|
||||
"heapless",
|
||||
@@ -2221,7 +2111,7 @@ dependencies = [
|
||||
"embedded-io",
|
||||
"futures",
|
||||
"heapless",
|
||||
"rand_core 0.6.4",
|
||||
"rand_core",
|
||||
"static_cell",
|
||||
"trouble-host-macros",
|
||||
"zerocopy",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#![no_std]
|
||||
|
||||
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 shared::keyboard::{KeyCode, KeyEvent, KeyState, Modifiers};
|
||||
use talc::*;
|
||||
|
||||
@@ -21,13 +21,12 @@ pub static mut CALL_ABI_TABLE: [usize; CallAbiTable::COUNT] = [0; CallAbiTable::
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum CallAbiTable {
|
||||
Print = 0,
|
||||
Sleep = 1,
|
||||
DrawIter = 2,
|
||||
GetKey = 3,
|
||||
DrawIter = 1,
|
||||
GetKey = 2,
|
||||
}
|
||||
|
||||
impl CallAbiTable {
|
||||
pub const COUNT: usize = 4;
|
||||
pub const COUNT: usize = 3;
|
||||
}
|
||||
|
||||
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 fn draw_iter(pixels: &[Pixel<Rgb565>]) {
|
||||
|
||||
@@ -31,20 +31,20 @@ defmt = [
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
embassy-executor = { version = "0.9", features = [
|
||||
embassy-executor = { version = "0.7", features = [
|
||||
"arch-cortex-m",
|
||||
"executor-interrupt",
|
||||
"executor-thread",
|
||||
"nightly",
|
||||
] }
|
||||
embassy-rp = { version = "0.8.0", features = [
|
||||
embassy-rp = { version = "0.4.0", features = [
|
||||
"critical-section-impl",
|
||||
"unstable-pac",
|
||||
"time-driver",
|
||||
] }
|
||||
embassy-usb = "0.5.1"
|
||||
embassy-futures = "0.1.2"
|
||||
embassy-time = { version = "0.5.0", features = ["generic-queue-8"] }
|
||||
embassy-usb = "0.4.0"
|
||||
embassy-futures = "0.1.1"
|
||||
embassy-time = { version = "0.4.0", features = ["generic-queue-8"] }
|
||||
embassy-embedded-hal = "0.3.1"
|
||||
embassy-sync = { version = "0.7" }
|
||||
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 = "0.2.7"
|
||||
embedded-hal_2 = { package = "embedded-hal", version = "1.0.0" }
|
||||
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"] }
|
||||
assign-resources = "0.5.0"
|
||||
|
||||
defmt = { version = "0.3", optional = true }
|
||||
defmt-rtt = "0.4.2"
|
||||
|
||||
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-text = "0.7.2"
|
||||
embedded-layout = "0.4.2"
|
||||
|
||||
@@ -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 defmt::info;
|
||||
use embassy_futures::block_on;
|
||||
use embassy_rp::clocks::clk_sys_freq;
|
||||
use embassy_time::Timer;
|
||||
use embedded_graphics::{
|
||||
Drawable,
|
||||
draw_target::DrawTarget,
|
||||
@@ -15,11 +12,10 @@ use embedded_graphics::{
|
||||
};
|
||||
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
|
||||
const _: PrintAbi = print;
|
||||
const _: SleepAbi = sleep;
|
||||
const _: DrawIterAbi = draw_iter;
|
||||
const _: GetKeyAbi = get_key;
|
||||
|
||||
@@ -27,18 +23,10 @@ pub extern "Rust" fn print(msg: &str) {
|
||||
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
|
||||
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> {
|
||||
|
||||
@@ -1,18 +1,13 @@
|
||||
use crate::framebuffer::AtomicFrameBuffer;
|
||||
use embassy_rp::{
|
||||
Peri,
|
||||
gpio::{Level, Output},
|
||||
peripherals::{PIN_13, PIN_14, PIN_15, SPI1},
|
||||
spi::{Async, Spi},
|
||||
};
|
||||
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, mutex::Mutex};
|
||||
use embassy_time::{Delay, Timer};
|
||||
use embedded_graphics::{
|
||||
draw_target::DrawTarget,
|
||||
pixelcolor::{Rgb565, RgbColor},
|
||||
prelude::Dimensions,
|
||||
};
|
||||
use embedded_hal_bus::spi::ExclusiveDevice;
|
||||
use st7365p_lcd::ST7365P;
|
||||
use st7365p_lcd::{FrameBuffer, ST7365P};
|
||||
use static_cell::StaticCell;
|
||||
|
||||
type DISPLAY = ST7365P<
|
||||
ExclusiveDevice<Spi<'static, SPI1, Async>, Output<'static>, Delay>,
|
||||
@@ -24,13 +19,18 @@ type DISPLAY = ST7365P<
|
||||
pub const SCREEN_WIDTH: 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(
|
||||
spi: Spi<'static, SPI1, Async>,
|
||||
cs: Peri<'static, PIN_13>,
|
||||
data: Peri<'static, PIN_14>,
|
||||
reset: Peri<'static, PIN_15>,
|
||||
cs: PIN_13,
|
||||
data: PIN_14,
|
||||
reset: PIN_15,
|
||||
) -> DISPLAY {
|
||||
let spi_device = ExclusiveDevice::new(spi, Output::new(cs, Level::Low), Delay).unwrap();
|
||||
let mut display = ST7365P::new(
|
||||
@@ -41,30 +41,20 @@ pub async fn init_display(
|
||||
true,
|
||||
Delay,
|
||||
);
|
||||
|
||||
display.init().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
|
||||
}
|
||||
|
||||
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) {
|
||||
let fb = framebuffer_mut();
|
||||
loop {
|
||||
unsafe {
|
||||
FRAMEBUFFER
|
||||
.partial_draw_batched(&mut display)
|
||||
.await
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
Timer::after_millis(32).await; // 30 fps
|
||||
display.partial_draw_batched(fb).await.unwrap();
|
||||
embassy_time::Timer::after_millis(32).await; // 30 fps
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,6 @@ pub async unsafe fn load_binary(name: &ShortFileName) -> Result<EntryFn, &str> {
|
||||
// MUST MATCH ABI EXACTLY
|
||||
let entries: &[(CallAbiTable, usize)] = &[
|
||||
(CallAbiTable::Print, abi::print as usize),
|
||||
(CallAbiTable::Sleep, abi::sleep as usize),
|
||||
(CallAbiTable::DrawIter, abi::draw_iter as usize),
|
||||
(CallAbiTable::GetKey, abi::get_key as usize),
|
||||
];
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,6 @@ extern crate alloc;
|
||||
mod abi;
|
||||
mod display;
|
||||
mod elf;
|
||||
mod framebuffer;
|
||||
mod peripherals;
|
||||
mod scsi;
|
||||
mod storage;
|
||||
@@ -19,8 +18,7 @@ mod usb;
|
||||
mod utils;
|
||||
|
||||
use crate::{
|
||||
display::{FRAMEBUFFER, clear_fb, display_handler, init_display},
|
||||
elf::load_binary,
|
||||
display::{display_handler, framebuffer_mut, init_display},
|
||||
peripherals::{
|
||||
conf_peripherals,
|
||||
keyboard::{KeyCode, KeyState, read_keyboard_fifo},
|
||||
@@ -29,16 +27,11 @@ use crate::{
|
||||
ui::{SELECTIONS, ui_handler},
|
||||
usb::usb_handler,
|
||||
};
|
||||
use abi_sys::EntryFn;
|
||||
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
use assign_resources::assign_resources;
|
||||
use abi_sys::{EntryFn, Rgb565, RgbColor};
|
||||
use defmt::unwrap;
|
||||
use embassy_executor::{Executor, Spawner};
|
||||
use embassy_futures::join::{join, join3, join4, join5};
|
||||
use embassy_rp::{
|
||||
Peri,
|
||||
gpio::{Input, Level, Output, Pull},
|
||||
i2c::{self, I2c},
|
||||
multicore::{Stack, spawn_core1},
|
||||
@@ -53,12 +46,14 @@ use embassy_sync::{
|
||||
blocking_mutex::raw::CriticalSectionRawMutex, channel::Channel, mutex::Mutex, signal::Signal,
|
||||
};
|
||||
use embassy_time::{Delay, Timer};
|
||||
use embedded_graphics::draw_target::DrawTarget;
|
||||
use embedded_hal_bus::spi::ExclusiveDevice;
|
||||
use embedded_sdmmc::SdCard as SdmmcSdCard;
|
||||
use heapless::spsc::Queue;
|
||||
use shared::keyboard::KeyEvent;
|
||||
use static_cell::StaticCell;
|
||||
use talc::*;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
embassy_rp::bind_interrupts!(struct Irqs {
|
||||
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_CHANGED: Signal<CriticalSectionRawMutex, ()> = Signal::new();
|
||||
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
#[derive(Copy, Clone)]
|
||||
enum TaskState {
|
||||
Ui,
|
||||
Kernel,
|
||||
@@ -135,54 +130,61 @@ async fn userland_task() {
|
||||
let recv = BINARY_CH.receiver();
|
||||
loop {
|
||||
let entry = recv.receive().await;
|
||||
defmt::info!("Got Entry");
|
||||
defmt::info!("got bin");
|
||||
|
||||
// disable kernel ui
|
||||
{
|
||||
let mut state = TASK_STATE.lock().await;
|
||||
*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;
|
||||
|
||||
// enable kernel ui
|
||||
{
|
||||
let mut state = TASK_STATE.lock().await;
|
||||
*state = TaskState::Ui;
|
||||
TASK_STATE_CHANGED.signal(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Display {
|
||||
spi: Peri<'static, SPI1>,
|
||||
clk: Peri<'static, PIN_10>,
|
||||
mosi: Peri<'static, PIN_11>,
|
||||
miso: Peri<'static, PIN_12>,
|
||||
dma1: Peri<'static, DMA_CH0>,
|
||||
dma2: Peri<'static, DMA_CH1>,
|
||||
cs: Peri<'static, PIN_13>,
|
||||
data: Peri<'static, PIN_14>,
|
||||
reset: Peri<'static, PIN_15>,
|
||||
spi: SPI1,
|
||||
clk: PIN_10,
|
||||
mosi: PIN_11,
|
||||
miso: PIN_12,
|
||||
dma1: DMA_CH0,
|
||||
dma2: DMA_CH1,
|
||||
cs: PIN_13,
|
||||
data: PIN_14,
|
||||
reset: PIN_15,
|
||||
}
|
||||
|
||||
struct Sd {
|
||||
spi: Peri<'static, SPI0>,
|
||||
clk: Peri<'static, PIN_18>,
|
||||
mosi: Peri<'static, PIN_19>,
|
||||
miso: Peri<'static, PIN_16>,
|
||||
cs: Peri<'static, PIN_17>,
|
||||
det: Peri<'static, PIN_22>,
|
||||
spi: SPI0,
|
||||
clk: PIN_18,
|
||||
mosi: PIN_19,
|
||||
miso: PIN_16,
|
||||
cs: PIN_17,
|
||||
det: PIN_22,
|
||||
}
|
||||
|
||||
struct Mcu {
|
||||
i2c: Peri<'static, I2C1>,
|
||||
clk: Peri<'static, PIN_7>,
|
||||
data: Peri<'static, PIN_6>,
|
||||
i2c: I2C1,
|
||||
clk: PIN_7,
|
||||
data: PIN_6,
|
||||
}
|
||||
|
||||
#[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
|
||||
let mut config = i2c::Config::default();
|
||||
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));
|
||||
};
|
||||
|
||||
let usb = embassy_rp_usb::Driver::new(usb, Irqs);
|
||||
let usb_fut = usb_handler(usb);
|
||||
// let usb = embassy_rp_usb::Driver::new(usb, Irqs);
|
||||
// let usb_fut = usb_handler(usb);
|
||||
|
||||
let key_abi_fut = async {
|
||||
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();
|
||||
|
||||
async fn get_keys() {
|
||||
if let Some(event) = read_keyboard_fifo().await {
|
||||
if let KeyState::Pressed = event.state {
|
||||
unsafe {
|
||||
let _ = KEY_CACHE.enqueue(event);
|
||||
}
|
||||
unsafe {
|
||||
let _ = KEY_CACHE.enqueue(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,7 @@ use embassy_rp::{
|
||||
i2c::{Async, I2c},
|
||||
peripherals::I2C1,
|
||||
};
|
||||
use embassy_sync::{
|
||||
blocking_mutex::raw::CriticalSectionRawMutex, lazy_lock::LazyLock, mutex::Mutex,
|
||||
};
|
||||
use embassy_sync::{blocking_mutex::raw::NoopRawMutex, lazy_lock::LazyLock, mutex::Mutex};
|
||||
use embassy_time::Timer;
|
||||
|
||||
pub mod keyboard;
|
||||
@@ -17,7 +15,7 @@ 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<Mutex<CriticalSectionRawMutex, Option<I2CBUS>>> =
|
||||
pub static PERIPHERAL_BUS: LazyLock<Mutex<NoopRawMutex, Option<I2CBUS>>> =
|
||||
LazyLock::new(|| Mutex::new(None));
|
||||
|
||||
const REG_ID_VER: u8 = 0x01;
|
||||
|
||||
@@ -8,25 +8,30 @@ use heapless::Vec;
|
||||
mod scsi_types;
|
||||
use scsi_types::*;
|
||||
|
||||
use crate::storage::{SDCARD, SdCard};
|
||||
use crate::storage::SdCard;
|
||||
|
||||
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_in: D::EndpointIn,
|
||||
}
|
||||
|
||||
impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, D> {
|
||||
pub fn new(builder: &mut Builder<'d, D>) -> Self {
|
||||
impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, 's, D> {
|
||||
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 interface = function.interface();
|
||||
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_in = alt.endpoint_bulk_in(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(BULK_ENDPOINT_PACKET_SIZE as u16);
|
||||
|
||||
Self { bulk_out, bulk_in }
|
||||
Self {
|
||||
bulk_out,
|
||||
bulk_in,
|
||||
sdcard,
|
||||
}
|
||||
}
|
||||
|
||||
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(|_| ())
|
||||
}
|
||||
ScsiCommand::TestUnitReady => {
|
||||
let guard = SDCARD.get().lock().await;
|
||||
let sdcard = guard.as_ref().unwrap();
|
||||
if sdcard.is_attached() {
|
||||
if self.sdcard.is_attached() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(())
|
||||
@@ -182,11 +185,8 @@ impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, D> {
|
||||
self.bulk_in.write(&response[..len]).await.map_err(|_| ())
|
||||
}
|
||||
ScsiCommand::ReadCapacity10 => {
|
||||
let guard = SDCARD.get().lock().await;
|
||||
let sdcard = guard.as_ref().unwrap();
|
||||
|
||||
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);
|
||||
|
||||
@@ -196,11 +196,8 @@ impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, D> {
|
||||
self.bulk_in.write(&response).await.map_err(|_| ())
|
||||
}
|
||||
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 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);
|
||||
|
||||
@@ -212,12 +209,9 @@ impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, D> {
|
||||
self.bulk_in.write(&response[..len]).await.map_err(|_| ())
|
||||
}
|
||||
ScsiCommand::Read { lba, len } => {
|
||||
let guard = SDCARD.get().lock().await;
|
||||
let sdcard = guard.as_ref().unwrap();
|
||||
|
||||
for i in 0..len {
|
||||
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()) {
|
||||
self.bulk_in.write(chunk).await.map_err(|_| ())?;
|
||||
}
|
||||
@@ -225,9 +219,6 @@ impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, D> {
|
||||
Ok(())
|
||||
}
|
||||
ScsiCommand::Write { lba, len } => {
|
||||
let guard = SDCARD.get().lock().await;
|
||||
let sdcard = guard.as_ref().unwrap();
|
||||
|
||||
for i in 0..len {
|
||||
let block_idx = BlockIdx(lba as u32 + i as u32);
|
||||
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(|_| ())?;
|
||||
}
|
||||
sdcard.write_blocks(&mut block, block_idx)?;
|
||||
self.sdcard.write_blocks(&mut block, block_idx)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
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 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];
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ use core::str::FromStr;
|
||||
use embassy_rp::gpio::{Input, Output};
|
||||
use embassy_rp::peripherals::SPI0;
|
||||
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::mutex::Mutex;
|
||||
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>;
|
||||
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));
|
||||
|
||||
pub struct DummyTimeSource {}
|
||||
|
||||
@@ -1,25 +1,40 @@
|
||||
use crate::{
|
||||
BINARY_CH, TASK_STATE, TaskState,
|
||||
display::{FRAMEBUFFER, SCREEN_HEIGHT, SCREEN_WIDTH},
|
||||
display::{SCREEN_HEIGHT, SCREEN_WIDTH, framebuffer_mut},
|
||||
elf::load_binary,
|
||||
format,
|
||||
peripherals::keyboard,
|
||||
storage::FileName,
|
||||
usb::RESTART_USB,
|
||||
};
|
||||
use alloc::{string::String, vec::Vec};
|
||||
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::{
|
||||
blocking_mutex::raw::{CriticalSectionRawMutex, ThreadModeRawMutex},
|
||||
mutex::Mutex,
|
||||
signal::Signal,
|
||||
};
|
||||
use embassy_time::{Delay, Timer};
|
||||
use embedded_graphics::{
|
||||
Drawable,
|
||||
mono_font::{MonoTextStyle, ascii::FONT_9X15},
|
||||
draw_target::DrawTarget,
|
||||
mono_font::{
|
||||
MonoTextStyle,
|
||||
ascii::{FONT_6X9, FONT_6X10, FONT_9X15, FONT_10X20},
|
||||
},
|
||||
pixelcolor::Rgb565,
|
||||
prelude::{Dimensions, Point, RgbColor, Size},
|
||||
primitives::Rectangle,
|
||||
prelude::{Dimensions, Point, Primitive, RgbColor, Size},
|
||||
primitives::{PrimitiveStyle, Rectangle, StyledDrawable},
|
||||
text::Text,
|
||||
};
|
||||
use embedded_hal_async::spi::SpiDevice;
|
||||
use embedded_hal_bus::spi::{ExclusiveDevice, NoDelay};
|
||||
use embedded_layout::{
|
||||
align::{horizontal, vertical},
|
||||
layout::linear::LinearLayout,
|
||||
@@ -32,38 +47,51 @@ use shared::keyboard::{KeyCode, KeyState};
|
||||
pub static SELECTIONS: Mutex<CriticalSectionRawMutex, SelectionList> =
|
||||
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() {
|
||||
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 KeyState::Pressed = event.state {
|
||||
if event.state == KeyState::Pressed {
|
||||
match event.key {
|
||||
KeyCode::JoyUp => {
|
||||
let mut selections = SELECTIONS.lock().await;
|
||||
selections.up();
|
||||
redraw = true;
|
||||
}
|
||||
KeyCode::JoyDown => {
|
||||
let mut selections = SELECTIONS.lock().await;
|
||||
selections.down();
|
||||
redraw = true;
|
||||
}
|
||||
KeyCode::Enter | KeyCode::JoyRight => {
|
||||
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;
|
||||
}
|
||||
_ => (),
|
||||
KeyCode::Enter | KeyCode::JoyRight => run_selected().await,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
draw_selection().await;
|
||||
} else {
|
||||
embassy_time::Timer::after_millis(50).await;
|
||||
{
|
||||
let mut selections = SELECTIONS.lock().await;
|
||||
redraw |= selections.take_changed();
|
||||
}
|
||||
|
||||
if redraw {
|
||||
draw_selection().await;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -74,8 +102,9 @@ async fn draw_selection() {
|
||||
guard.selections.clone()
|
||||
};
|
||||
|
||||
let fb = framebuffer_mut();
|
||||
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";
|
||||
let no_bins = String::from_str(NO_BINS).unwrap();
|
||||
@@ -89,14 +118,13 @@ async fn draw_selection() {
|
||||
),
|
||||
text_style,
|
||||
)
|
||||
.draw(unsafe { &mut FRAMEBUFFER })
|
||||
.draw(fb)
|
||||
.unwrap();
|
||||
} else {
|
||||
let mut file_names = file_names.iter();
|
||||
let Some(first) = file_names.next() else {
|
||||
Text::new(NO_BINS, Point::zero(), text_style)
|
||||
.draw(unsafe { &mut FRAMEBUFFER })
|
||||
.unwrap();
|
||||
Text::new("No Programs found on SD Card\nEnsure programs end with '.bin',\nand are located in the root directory",
|
||||
Point::zero(), text_style).draw(fb).unwrap();
|
||||
|
||||
return;
|
||||
};
|
||||
@@ -115,15 +143,16 @@ async fn draw_selection() {
|
||||
.with_alignment(horizontal::Center)
|
||||
.arrange()
|
||||
.align_to(&display_area, horizontal::Center, vertical::Center)
|
||||
.draw(unsafe { &mut FRAMEBUFFER })
|
||||
.draw(fb)
|
||||
.unwrap();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SelectionList {
|
||||
current_selection: u16,
|
||||
pub selections: Vec<FileName>,
|
||||
has_changed: bool,
|
||||
}
|
||||
|
||||
impl SelectionList {
|
||||
@@ -131,6 +160,7 @@ impl SelectionList {
|
||||
Self {
|
||||
selections: Vec::new(),
|
||||
current_selection: 0,
|
||||
has_changed: true,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,4 +179,10 @@ impl SelectionList {
|
||||
self.current_selection -= 1
|
||||
}
|
||||
}
|
||||
|
||||
pub fn take_changed(&mut self) -> bool {
|
||||
let changed = self.has_changed;
|
||||
self.has_changed = false;
|
||||
changed
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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::{
|
||||
join::join,
|
||||
select::{select, select3},
|
||||
};
|
||||
use embassy_rp::{peripherals::USB, usb::Driver};
|
||||
use embassy_sync::{blocking_mutex::raw::ThreadModeRawMutex, signal::Signal};
|
||||
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>) {
|
||||
let mut config = Config::new(0xc0de, 0xbabe);
|
||||
@@ -27,17 +37,27 @@ pub async fn usb_handler(driver: Driver<'static, USB>) {
|
||||
&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();
|
||||
|
||||
loop {
|
||||
defmt::info!("in: {}", *TASK_STATE.lock().await as u32);
|
||||
if *TASK_STATE.lock().await == TaskState::Ui {
|
||||
defmt::info!("running scsi and usb");
|
||||
select(join(usb.run(), scsi.poll()), TASK_STATE_CHANGED.wait()).await;
|
||||
} else {
|
||||
defmt::info!("not in ui state");
|
||||
TASK_STATE_CHANGED.wait().await;
|
||||
}
|
||||
select3(
|
||||
async {
|
||||
loop {
|
||||
RESTART_USB.wait().await;
|
||||
return;
|
||||
}
|
||||
},
|
||||
usb.run(),
|
||||
async {
|
||||
if ENABLE_SCSI.load(Ordering::Acquire) {
|
||||
scsi.poll().await
|
||||
}
|
||||
},
|
||||
)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#![no_main]
|
||||
|
||||
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 core::{panic::PanicInfo, pin::Pin};
|
||||
use embedded_graphics::{
|
||||
@@ -10,8 +10,7 @@ use embedded_graphics::{
|
||||
geometry::{Dimensions, Point},
|
||||
mono_font::{MonoTextStyle, ascii::FONT_6X10},
|
||||
pixelcolor::Rgb565,
|
||||
prelude::{Primitive, RgbColor, Size},
|
||||
primitives::{PrimitiveStyle, Rectangle},
|
||||
prelude::RgbColor,
|
||||
text::{Alignment, Text},
|
||||
};
|
||||
|
||||
@@ -26,49 +25,31 @@ pub async fn main() {
|
||||
|
||||
let character_style = MonoTextStyle::new(&FONT_6X10, Rgb565::RED);
|
||||
|
||||
let mut text = vec!['T', 'y', 'p', 'e'];
|
||||
let mut dirty = true;
|
||||
let mut last_bounds: Option<Rectangle> = None;
|
||||
let mut text = vec!['H', 'E', 'L', 'L', 'O'];
|
||||
|
||||
loop {
|
||||
if dirty {
|
||||
if let Some(bounds) = last_bounds {
|
||||
Rectangle::new(bounds.top_left, bounds.size)
|
||||
.into_styled(PrimitiveStyle::with_fill(Rgb565::BLACK))
|
||||
.draw(&mut display)
|
||||
.unwrap();
|
||||
// loop {
|
||||
Text::with_alignment(
|
||||
&text.iter().cloned().collect::<String>(),
|
||||
display.bounding_box().center() + Point::new(0, 15),
|
||||
character_style,
|
||||
Alignment::Center,
|
||||
)
|
||||
.draw(&mut display)
|
||||
.unwrap();
|
||||
|
||||
if let Some(event) = get_key() {
|
||||
print("User got event");
|
||||
match event.key {
|
||||
KeyCode::Char(ch) => {
|
||||
text.push(ch);
|
||||
}
|
||||
|
||||
let text = text.iter().cloned().collect::<String>();
|
||||
let aligned_text = Text::with_alignment(
|
||||
&text,
|
||||
display.bounding_box().center(),
|
||||
character_style,
|
||||
Alignment::Center,
|
||||
);
|
||||
last_bounds = Some(aligned_text.bounding_box());
|
||||
|
||||
aligned_text.draw(&mut display).unwrap();
|
||||
dirty = false;
|
||||
}
|
||||
|
||||
if let Some(event) = get_key() {
|
||||
dirty = true;
|
||||
match event.key {
|
||||
KeyCode::Char(ch) => {
|
||||
text.push(ch);
|
||||
}
|
||||
KeyCode::Del => {
|
||||
text.clear();
|
||||
}
|
||||
KeyCode::Backspace => {
|
||||
text.pop();
|
||||
}
|
||||
KeyCode::Esc => return,
|
||||
_ => (),
|
||||
KeyCode::Backspace => {
|
||||
text.pop();
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
|
||||
Reference in New Issue
Block a user