Compare commits
15 commits
bounce_buf
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
18d8443891 | ||
|
|
014b099986 | ||
|
|
a24774c925 | ||
|
|
d555c908a2 | ||
|
|
c7e0ec45ca | ||
|
|
8a99905a84 | ||
|
|
c3f58178fc | ||
|
|
e0b0aded7b | ||
|
|
76ed47d687 | ||
|
|
3e52243efe | ||
|
|
bf5957a8bf | ||
|
|
682522d556 | ||
|
|
6f42bf7a7b | ||
|
|
3b291669ca | ||
|
|
07efc876f3 |
229
firmware/Cargo.lock
generated
229
firmware/Cargo.lock
generated
|
|
@ -26,16 +26,17 @@ dependencies = [
|
||||||
"embedded-storage-async",
|
"embedded-storage-async",
|
||||||
"embuild",
|
"embuild",
|
||||||
"enumset",
|
"enumset",
|
||||||
"esp-alloc",
|
"esp-alloc 0.9.0 (git+https://github.com/esp-rs/esp-hal?rev=ee6e26f2fefa4da2168c95839bf618e1ecc22cc1)",
|
||||||
"esp-backtrace",
|
"esp-backtrace",
|
||||||
"esp-bootloader-esp-idf",
|
"esp-bootloader-esp-idf",
|
||||||
"esp-hal",
|
"esp-hal",
|
||||||
|
"esp-hal-bounce-buffers",
|
||||||
"esp-metadata-generated 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"esp-metadata-generated 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"esp-println",
|
"esp-println",
|
||||||
"esp-radio",
|
"esp-radio",
|
||||||
"esp-rtos",
|
"esp-rtos",
|
||||||
"esp-storage",
|
"esp-storage",
|
||||||
"esp-sync",
|
"esp-sync 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"gix",
|
"gix",
|
||||||
"hex",
|
"hex",
|
||||||
"hmac",
|
"hmac",
|
||||||
|
|
@ -2036,13 +2037,30 @@ checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "esp-alloc"
|
name = "esp-alloc"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "641e43d6a60244429117ef2fa7a47182120c7561336ea01f6fb08d634f46bae1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"allocator-api2 0.3.1",
|
"allocator-api2 0.3.1",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"document-features",
|
"document-features",
|
||||||
"enumset",
|
"enumset",
|
||||||
"esp-config",
|
"esp-config 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"esp-sync",
|
"esp-sync 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"linked_list_allocator",
|
||||||
|
"rlsf",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "esp-alloc"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "git+https://github.com/esp-rs/esp-hal?rev=ee6e26f2fefa4da2168c95839bf618e1ecc22cc1#ee6e26f2fefa4da2168c95839bf618e1ecc22cc1"
|
||||||
|
dependencies = [
|
||||||
|
"allocator-api2 0.3.1",
|
||||||
|
"cfg-if",
|
||||||
|
"document-features",
|
||||||
|
"enumset",
|
||||||
|
"esp-config 0.6.1 (git+https://github.com/esp-rs/esp-hal?rev=ee6e26f2fefa4da2168c95839bf618e1ecc22cc1)",
|
||||||
|
"esp-sync 0.1.1 (git+https://github.com/esp-rs/esp-hal?rev=ee6e26f2fefa4da2168c95839bf618e1ecc22cc1)",
|
||||||
"linked_list_allocator",
|
"linked_list_allocator",
|
||||||
"rlsf",
|
"rlsf",
|
||||||
]
|
]
|
||||||
|
|
@ -2050,28 +2068,31 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "esp-backtrace"
|
name = "esp-backtrace"
|
||||||
version = "0.18.1"
|
version = "0.18.1"
|
||||||
|
source = "git+https://github.com/Limeth/esp-hal.git?rev=114977583886be4ed866ad7b7c6f16865148e899#114977583886be4ed866ad7b7c6f16865148e899"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"document-features",
|
"document-features",
|
||||||
"esp-config",
|
"esp-config 0.6.1 (git+https://github.com/Limeth/esp-hal.git?rev=114977583886be4ed866ad7b7c6f16865148e899)",
|
||||||
"esp-metadata-generated 0.3.0",
|
"esp-metadata-generated 0.3.0 (git+https://github.com/Limeth/esp-hal.git?rev=114977583886be4ed866ad7b7c6f16865148e899)",
|
||||||
"esp-println",
|
"esp-println",
|
||||||
"heapless 0.9.2",
|
"heapless 0.9.2",
|
||||||
"riscv",
|
"riscv",
|
||||||
"semihosting",
|
"semihosting",
|
||||||
"xtensa-lx",
|
"xtensa-lx 0.13.0 (git+https://github.com/Limeth/esp-hal.git?rev=114977583886be4ed866ad7b7c6f16865148e899)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "esp-bootloader-esp-idf"
|
name = "esp-bootloader-esp-idf"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "02a56964ab5479ac20c9cf76fa3b0d3f2233b20b5d8554e81ef5d65f63c20567"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"document-features",
|
"document-features",
|
||||||
"embedded-storage",
|
"embedded-storage",
|
||||||
"esp-config",
|
"esp-config 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"esp-hal-procmacros",
|
"esp-hal-procmacros",
|
||||||
"esp-metadata-generated 0.3.0",
|
"esp-metadata-generated 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"esp-rom-sys",
|
"esp-rom-sys",
|
||||||
"jiff",
|
"jiff",
|
||||||
"log",
|
"log",
|
||||||
|
|
@ -2081,9 +2102,35 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "esp-config"
|
name = "esp-config"
|
||||||
version = "0.6.1"
|
version = "0.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "102871054f8dd98202177b9890cb4b71d0c6fe1f1413b7a379a8e0841fc2473c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"document-features",
|
"document-features",
|
||||||
"esp-metadata-generated 0.3.0",
|
"esp-metadata-generated 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"serde",
|
||||||
|
"serde_yaml",
|
||||||
|
"somni-expr",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "esp-config"
|
||||||
|
version = "0.6.1"
|
||||||
|
source = "git+https://github.com/Limeth/esp-hal.git?rev=114977583886be4ed866ad7b7c6f16865148e899#114977583886be4ed866ad7b7c6f16865148e899"
|
||||||
|
dependencies = [
|
||||||
|
"document-features",
|
||||||
|
"esp-metadata-generated 0.3.0 (git+https://github.com/Limeth/esp-hal.git?rev=114977583886be4ed866ad7b7c6f16865148e899)",
|
||||||
|
"serde",
|
||||||
|
"serde_yaml",
|
||||||
|
"somni-expr",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "esp-config"
|
||||||
|
version = "0.6.1"
|
||||||
|
source = "git+https://github.com/esp-rs/esp-hal?rev=ee6e26f2fefa4da2168c95839bf618e1ecc22cc1#ee6e26f2fefa4da2168c95839bf618e1ecc22cc1"
|
||||||
|
dependencies = [
|
||||||
|
"document-features",
|
||||||
|
"esp-metadata-generated 0.3.0 (git+https://github.com/esp-rs/esp-hal?rev=ee6e26f2fefa4da2168c95839bf618e1ecc22cc1)",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
"somni-expr",
|
"somni-expr",
|
||||||
|
|
@ -2092,6 +2139,8 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "esp-hal"
|
name = "esp-hal"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "54786287c0a61ca0f78cb0c338a39427551d1be229103b4444591796c579e093"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitfield 0.19.4",
|
"bitfield 0.19.4",
|
||||||
"bitflags 2.10.0",
|
"bitflags 2.10.0",
|
||||||
|
|
@ -2114,12 +2163,12 @@ dependencies = [
|
||||||
"embedded-io-async 0.6.1",
|
"embedded-io-async 0.6.1",
|
||||||
"embedded-io-async 0.7.0",
|
"embedded-io-async 0.7.0",
|
||||||
"enumset",
|
"enumset",
|
||||||
"esp-config",
|
"esp-config 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"esp-hal-procmacros",
|
"esp-hal-procmacros",
|
||||||
"esp-metadata-generated 0.3.0",
|
"esp-metadata-generated 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"esp-riscv-rt",
|
"esp-riscv-rt",
|
||||||
"esp-rom-sys",
|
"esp-rom-sys",
|
||||||
"esp-sync",
|
"esp-sync 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"esp-synopsys-usb-otg",
|
"esp-synopsys-usb-otg",
|
||||||
"esp32",
|
"esp32",
|
||||||
"esp32c2",
|
"esp32c2",
|
||||||
|
|
@ -2139,13 +2188,25 @@ dependencies = [
|
||||||
"riscv",
|
"riscv",
|
||||||
"strum",
|
"strum",
|
||||||
"ufmt-write",
|
"ufmt-write",
|
||||||
"xtensa-lx",
|
"xtensa-lx 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"xtensa-lx-rt",
|
"xtensa-lx-rt",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "esp-hal-bounce-buffers"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"document-features",
|
||||||
|
"embassy-sync 0.7.2",
|
||||||
|
"esp-hal",
|
||||||
|
"ouroboros",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "esp-hal-procmacros"
|
name = "esp-hal-procmacros"
|
||||||
version = "0.21.0"
|
version = "0.21.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3e025a7a7a0affdb4ff913b5c4494aef96ee03d085bf83c27453ae3a71d50da6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"document-features",
|
"document-features",
|
||||||
"object",
|
"object",
|
||||||
|
|
@ -2156,36 +2217,45 @@ dependencies = [
|
||||||
"termcolor",
|
"termcolor",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "esp-metadata-generated"
|
|
||||||
version = "0.3.0"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "esp-metadata-generated"
|
name = "esp-metadata-generated"
|
||||||
version = "0.3.0"
|
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 = "9a93e39c8ad8d390d248dc7b9f4b59a873f313bf535218b8e2351356972399e3"
|
checksum = "9a93e39c8ad8d390d248dc7b9f4b59a873f313bf535218b8e2351356972399e3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "esp-metadata-generated"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "git+https://github.com/Limeth/esp-hal.git?rev=114977583886be4ed866ad7b7c6f16865148e899#114977583886be4ed866ad7b7c6f16865148e899"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "esp-metadata-generated"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "git+https://github.com/esp-rs/esp-hal?rev=ee6e26f2fefa4da2168c95839bf618e1ecc22cc1#ee6e26f2fefa4da2168c95839bf618e1ecc22cc1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "esp-phy"
|
name = "esp-phy"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6b1facf348e1e251517278fc0f5dc134e95e518251f5796cfbb532ca226a29bf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"document-features",
|
"document-features",
|
||||||
"esp-config",
|
"esp-config 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"esp-hal",
|
"esp-hal",
|
||||||
"esp-metadata-generated 0.3.0",
|
"esp-metadata-generated 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"esp-sync",
|
"esp-sync 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"esp-wifi-sys-esp32s3",
|
"esp-wifi-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "esp-println"
|
name = "esp-println"
|
||||||
version = "0.16.1"
|
version = "0.16.1"
|
||||||
|
source = "git+https://github.com/Limeth/esp-hal.git?rev=114977583886be4ed866ad7b7c6f16865148e899#114977583886be4ed866ad7b7c6f16865148e899"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"document-features",
|
"document-features",
|
||||||
"esp-metadata-generated 0.3.0",
|
"esp-metadata-generated 0.3.0 (git+https://github.com/Limeth/esp-hal.git?rev=114977583886be4ed866ad7b7c6f16865148e899)",
|
||||||
"esp-sync",
|
"esp-sync 0.1.1 (git+https://github.com/Limeth/esp-hal.git?rev=114977583886be4ed866ad7b7c6f16865148e899)",
|
||||||
"log",
|
"log",
|
||||||
"portable-atomic",
|
"portable-atomic",
|
||||||
]
|
]
|
||||||
|
|
@ -2193,6 +2263,8 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "esp-radio"
|
name = "esp-radio"
|
||||||
version = "0.17.0"
|
version = "0.17.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "684c4de2f8907b73c9b891fbda65286a86d34fced4b856f36a7896c211f2f265"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"allocator-api2 0.3.1",
|
"allocator-api2 0.3.1",
|
||||||
"bt-hci",
|
"bt-hci",
|
||||||
|
|
@ -2202,15 +2274,15 @@ dependencies = [
|
||||||
"embedded-io 0.7.1",
|
"embedded-io 0.7.1",
|
||||||
"embedded-io-async 0.6.1",
|
"embedded-io-async 0.6.1",
|
||||||
"embedded-io-async 0.7.0",
|
"embedded-io-async 0.7.0",
|
||||||
"esp-alloc",
|
"esp-alloc 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"esp-config",
|
"esp-config 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"esp-hal",
|
"esp-hal",
|
||||||
"esp-hal-procmacros",
|
"esp-hal-procmacros",
|
||||||
"esp-metadata-generated 0.3.0",
|
"esp-metadata-generated 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"esp-phy",
|
"esp-phy",
|
||||||
"esp-radio-rtos-driver",
|
"esp-radio-rtos-driver",
|
||||||
"esp-sync",
|
"esp-sync 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"esp-wifi-sys-esp32s3",
|
"esp-wifi-sys",
|
||||||
"heapless 0.9.2",
|
"heapless 0.9.2",
|
||||||
"instability",
|
"instability",
|
||||||
"num-derive",
|
"num-derive",
|
||||||
|
|
@ -2223,10 +2295,14 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "esp-radio-rtos-driver"
|
name = "esp-radio-rtos-driver"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "543bc31d1851afd062357e7810c1a9633f282fd3993583499a841ab497cbca6c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "esp-riscv-rt"
|
name = "esp-riscv-rt"
|
||||||
version = "0.13.0"
|
version = "0.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "502744a5b1e7268d27fd2a4e56ad45efe42ead517d6c517a6961540de949b0ee"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"document-features",
|
"document-features",
|
||||||
"riscv",
|
"riscv",
|
||||||
|
|
@ -2236,15 +2312,19 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "esp-rom-sys"
|
name = "esp-rom-sys"
|
||||||
version = "0.1.3"
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cd66cccc6dd2d13e9f33668a57717ab14a6d217180ec112e6be533de93e7ecbf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"document-features",
|
"document-features",
|
||||||
"esp-metadata-generated 0.3.0",
|
"esp-metadata-generated 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "esp-rtos"
|
name = "esp-rtos"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "162ec711c8d06e79c67b75d01595539e86b0aac209643af98ca87a12250428b3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"allocator-api2 0.3.1",
|
"allocator-api2 0.3.1",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
|
|
@ -2253,40 +2333,72 @@ dependencies = [
|
||||||
"embassy-sync 0.7.2",
|
"embassy-sync 0.7.2",
|
||||||
"embassy-time-driver",
|
"embassy-time-driver",
|
||||||
"embassy-time-queue-utils",
|
"embassy-time-queue-utils",
|
||||||
"esp-config",
|
"esp-config 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"esp-hal",
|
"esp-hal",
|
||||||
"esp-hal-procmacros",
|
"esp-hal-procmacros",
|
||||||
"esp-metadata-generated 0.3.0",
|
"esp-metadata-generated 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"esp-radio-rtos-driver",
|
"esp-radio-rtos-driver",
|
||||||
"esp-sync",
|
"esp-sync 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"portable-atomic",
|
"portable-atomic",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "esp-storage"
|
name = "esp-storage"
|
||||||
version = "0.8.1"
|
version = "0.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1495fc1f5549bdd840b52d9ceb201746200e1620d2636f46958c11e765623b80"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"document-features",
|
"document-features",
|
||||||
"embedded-storage",
|
"embedded-storage",
|
||||||
"esp-hal",
|
"esp-hal",
|
||||||
"esp-hal-procmacros",
|
"esp-hal-procmacros",
|
||||||
"esp-metadata-generated 0.3.0",
|
"esp-metadata-generated 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"esp-rom-sys",
|
"esp-rom-sys",
|
||||||
"esp-sync",
|
"esp-sync 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "esp-sync"
|
name = "esp-sync"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d44974639b4e88914f83fe60d2832c00276657d7d857628fdfc966cc7302e8a8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"document-features",
|
"document-features",
|
||||||
"embassy-sync 0.6.2",
|
"embassy-sync 0.6.2",
|
||||||
"embassy-sync 0.7.2",
|
"embassy-sync 0.7.2",
|
||||||
"esp-metadata-generated 0.3.0",
|
"esp-metadata-generated 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log",
|
"log",
|
||||||
"riscv",
|
"riscv",
|
||||||
"xtensa-lx",
|
"xtensa-lx 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "esp-sync"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "git+https://github.com/Limeth/esp-hal.git?rev=114977583886be4ed866ad7b7c6f16865148e899#114977583886be4ed866ad7b7c6f16865148e899"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"document-features",
|
||||||
|
"embassy-sync 0.6.2",
|
||||||
|
"embassy-sync 0.7.2",
|
||||||
|
"esp-metadata-generated 0.3.0 (git+https://github.com/Limeth/esp-hal.git?rev=114977583886be4ed866ad7b7c6f16865148e899)",
|
||||||
|
"riscv",
|
||||||
|
"xtensa-lx 0.13.0 (git+https://github.com/Limeth/esp-hal.git?rev=114977583886be4ed866ad7b7c6f16865148e899)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "esp-sync"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "git+https://github.com/esp-rs/esp-hal?rev=ee6e26f2fefa4da2168c95839bf618e1ecc22cc1#ee6e26f2fefa4da2168c95839bf618e1ecc22cc1"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"document-features",
|
||||||
|
"embassy-sync 0.6.2",
|
||||||
|
"embassy-sync 0.7.2",
|
||||||
|
"esp-metadata-generated 0.3.0 (git+https://github.com/esp-rs/esp-hal?rev=ee6e26f2fefa4da2168c95839bf618e1ecc22cc1)",
|
||||||
|
"riscv",
|
||||||
|
"xtensa-lx 0.13.0 (git+https://github.com/esp-rs/esp-hal?rev=ee6e26f2fefa4da2168c95839bf618e1ecc22cc1)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -2303,9 +2415,13 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "esp-wifi-sys-esp32s3"
|
name = "esp-wifi-sys"
|
||||||
version = "0.1.0"
|
version = "0.8.1"
|
||||||
source = "git+https://github.com/esp-rs/esp-wifi-sys?rev=7623c8d#7623c8d746b55cd8d9f7473359069aef381b7d3b"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "89b6544f6f0cb86169d1f93ba2101a8d50358a040c5043676ed86b793e09b12c"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "esp32"
|
name = "esp32"
|
||||||
|
|
@ -6875,6 +6991,7 @@ checksum = "a0f368519fc6c85fc1afdb769fb5a51123f6158013e143656e25a3485a0d401c"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "spectre-api-sys"
|
name = "spectre-api-sys"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
source = "git+c:/Users/Limeth/workspace/rust/spectre-api-sys#9e844eb056c3dfee8286ac21ec40fa689a8b8aa2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bindgen",
|
"bindgen",
|
||||||
"cc",
|
"cc",
|
||||||
|
|
@ -8468,6 +8585,24 @@ checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "xtensa-lx"
|
name = "xtensa-lx"
|
||||||
version = "0.13.0"
|
version = "0.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e012d667b0aa6d2592ace8ef145a98bff3e76cca7a644f4181ecd7a916ed289b"
|
||||||
|
dependencies = [
|
||||||
|
"critical-section",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "xtensa-lx"
|
||||||
|
version = "0.13.0"
|
||||||
|
source = "git+https://github.com/Limeth/esp-hal.git?rev=114977583886be4ed866ad7b7c6f16865148e899#114977583886be4ed866ad7b7c6f16865148e899"
|
||||||
|
dependencies = [
|
||||||
|
"critical-section",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "xtensa-lx"
|
||||||
|
version = "0.13.0"
|
||||||
|
source = "git+https://github.com/esp-rs/esp-hal?rev=ee6e26f2fefa4da2168c95839bf618e1ecc22cc1#ee6e26f2fefa4da2168c95839bf618e1ecc22cc1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"critical-section",
|
"critical-section",
|
||||||
]
|
]
|
||||||
|
|
@ -8475,15 +8610,19 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "xtensa-lx-rt"
|
name = "xtensa-lx-rt"
|
||||||
version = "0.21.0"
|
version = "0.21.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8709f037fb123fe7ff146d2bce86f9dc0dfc53045c016bfd9d703317b6502845"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"document-features",
|
"document-features",
|
||||||
"xtensa-lx",
|
"xtensa-lx 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"xtensa-lx-rt-proc-macros",
|
"xtensa-lx-rt-proc-macros",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "xtensa-lx-rt-proc-macros"
|
name = "xtensa-lx-rt-proc-macros"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "96fb42cd29c42f8744c74276e9f5bee7b06685bbe5b88df891516d72cb320450"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
@ -8800,3 +8939,11 @@ dependencies = [
|
||||||
"syn 2.0.114",
|
"syn 2.0.114",
|
||||||
"winnow",
|
"winnow",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[patch.unused]]
|
||||||
|
name = "i-slint-core"
|
||||||
|
version = "1.14.1"
|
||||||
|
|
||||||
|
[[patch.unused]]
|
||||||
|
name = "slint"
|
||||||
|
version = "1.14.1"
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,9 @@ rustflags = [
|
||||||
|
|
||||||
# Required to obtain backtraces on riscv (e.g. when using the "esp-backtrace" crate.)
|
# Required to obtain backtraces on riscv (e.g. when using the "esp-backtrace" crate.)
|
||||||
# "-C", "force-frame-pointers",
|
# "-C", "force-frame-pointers",
|
||||||
|
|
||||||
|
# Output linker map
|
||||||
|
# "-C", "link-arg=-Wl,-Map=target/linker.map"
|
||||||
]
|
]
|
||||||
|
|
||||||
[env] # These must be kept in sync with /.zed/settings.json
|
[env] # These must be kept in sync with /.zed/settings.json
|
||||||
|
|
@ -40,11 +43,11 @@ ACID_COMPOSE_LOCALE = "cs_CZ.UTF-8"
|
||||||
build-std = ["alloc", "core"]
|
build-std = ["alloc", "core"]
|
||||||
|
|
||||||
[patch.crates-io]
|
[patch.crates-io]
|
||||||
# esp-backtrace = { git = "https://github.com/Limeth/esp-hal.git", rev = "95d8c8b046e945e41294d5577528d0a1c4b03247" }
|
esp-backtrace = { git = "https://github.com/Limeth/esp-hal.git", rev = "114977583886be4ed866ad7b7c6f16865148e899" }
|
||||||
|
esp-println = { git = "https://github.com/Limeth/esp-hal.git", rev = "114977583886be4ed866ad7b7c6f16865148e899" }
|
||||||
# esp-hal = { git = "https://github.com/Limeth/esp-hal.git", rev = "95d8c8b046e945e41294d5577528d0a1c4b03247" }
|
# esp-hal = { git = "https://github.com/Limeth/esp-hal.git", rev = "95d8c8b046e945e41294d5577528d0a1c4b03247" }
|
||||||
# esp-storage = { git = "https://github.com/Limeth/esp-hal.git", rev = "95d8c8b046e945e41294d5577528d0a1c4b03247" }
|
# esp-storage = { git = "https://github.com/Limeth/esp-hal.git", rev = "95d8c8b046e945e41294d5577528d0a1c4b03247" }
|
||||||
# esp-alloc = { git = "https://github.com/Limeth/esp-hal.git", rev = "95d8c8b046e945e41294d5577528d0a1c4b03247" }
|
# esp-alloc = { git = "https://github.com/Limeth/esp-hal.git", rev = "95d8c8b046e945e41294d5577528d0a1c4b03247" }
|
||||||
# esp-println = { git = "https://github.com/Limeth/esp-hal.git", rev = "95d8c8b046e945e41294d5577528d0a1c4b03247" }
|
|
||||||
# esp-radio = { git = "https://github.com/Limeth/esp-hal.git", rev = "95d8c8b046e945e41294d5577528d0a1c4b03247" }
|
# esp-radio = { git = "https://github.com/Limeth/esp-hal.git", rev = "95d8c8b046e945e41294d5577528d0a1c4b03247" }
|
||||||
# esp-rtos = { git = "https://github.com/Limeth/esp-hal.git", rev = "95d8c8b046e945e41294d5577528d0a1c4b03247" }
|
# esp-rtos = { git = "https://github.com/Limeth/esp-hal.git", rev = "95d8c8b046e945e41294d5577528d0a1c4b03247" }
|
||||||
# esp-bootloader-esp-idf = { git = "https://github.com/Limeth/esp-hal.git", rev = "95d8c8b046e945e41294d5577528d0a1c4b03247" }
|
# esp-bootloader-esp-idf = { git = "https://github.com/Limeth/esp-hal.git", rev = "95d8c8b046e945e41294d5577528d0a1c4b03247" }
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ description = "Firmware for the ACID keyboard"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["usb-log", "limit-fps"]
|
default = ["usb-log", "limit-fps", "no-alloc-tracing"]
|
||||||
# Make RMK not to use USB
|
# Make RMK not to use USB
|
||||||
no-usb = ["rmk/_no_usb"]
|
no-usb = ["rmk/_no_usb"]
|
||||||
# Let RMK use BLE
|
# Let RMK use BLE
|
||||||
|
|
@ -30,6 +30,10 @@ develop-usb = ["limit-fps", "usb-log", "no-usb", "ble"]
|
||||||
probe = ["limit-fps", "rtt-log", "no-usb", "ble"]
|
probe = ["limit-fps", "rtt-log", "no-usb", "ble"]
|
||||||
# Formats the EKV database on boot.
|
# Formats the EKV database on boot.
|
||||||
format-db = []
|
format-db = []
|
||||||
|
# Avoid entering the critical section for the whole duration of printing a message to console.
|
||||||
|
racy-logging = []
|
||||||
|
# Global allocator tracing proxy
|
||||||
|
no-alloc-tracing = ["esp-alloc/global-allocator"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rmk = { version = "0.8.2", git = "https://github.com/Limeth/rmk", rev = "1661c55f5c21e7d80ea3f93255df483302c74b84", default-features = false, features = [
|
rmk = { version = "0.8.2", git = "https://github.com/Limeth/rmk", rev = "1661c55f5c21e7d80ea3f93255df483302c74b84", default-features = false, features = [
|
||||||
|
|
@ -49,7 +53,7 @@ esp-backtrace = { version = "0.18", default-features = false, features = [
|
||||||
] }
|
] }
|
||||||
esp-hal = { version = "1.0", features = ["esp32s3", "unstable", "psram", "log-04"] }
|
esp-hal = { version = "1.0", features = ["esp32s3", "unstable", "psram", "log-04"] }
|
||||||
esp-storage = { version = "0.8", features = ["esp32s3"] }
|
esp-storage = { version = "0.8", features = ["esp32s3"] }
|
||||||
esp-alloc = { version = "0.9", features = ["nightly"] }
|
esp-alloc = { version = "0.9", git = "https://github.com/esp-rs/esp-hal", rev = "ee6e26f2fefa4da2168c95839bf618e1ecc22cc1", default-features = false, features = ["esp32s3", "nightly", "compat"] }
|
||||||
esp-println = { version = "0.16", features = ["esp32s3", "log-04"] }
|
esp-println = { version = "0.16", features = ["esp32s3", "log-04"] }
|
||||||
esp-radio = { version = "0.17", features = ["esp32s3", "unstable", "ble"], optional = true }
|
esp-radio = { version = "0.17", features = ["esp32s3", "unstable", "ble"], optional = true }
|
||||||
esp-rtos = { version = "0.2", features = ["esp32s3", "esp-radio", "embassy"] }
|
esp-rtos = { version = "0.2", features = ["esp32s3", "esp-radio", "embassy"] }
|
||||||
|
|
@ -82,11 +86,12 @@ serde = { version = "1.0", default-features = false, features = ["derive"] }
|
||||||
# serde_with = { version = "3.16", default-features = false, features = ["alloc", "macros"] }
|
# serde_with = { version = "3.16", default-features = false, features = ["alloc", "macros"] }
|
||||||
serde_bytes = { version = "0.11.19", default-features = false, features = ["alloc"] }
|
serde_bytes = { version = "0.11.19", default-features = false, features = ["alloc"] }
|
||||||
chrono = { version = "0.4.43", default-features = false, features = ["alloc", "serde"] } # TODO: defmt
|
chrono = { version = "0.4.43", default-features = false, features = ["alloc", "serde"] } # TODO: defmt
|
||||||
tinyvec = { version = "1.10.0", default-features = false, features = ["alloc"] }
|
tinyvec = { version = "1.10.0", default-features = false, features = ["alloc", "latest_stable_rust"] }
|
||||||
esp-metadata-generated = { version = "0.3.0", features = ["esp32s3"] }
|
esp-metadata-generated = { version = "0.3.0", features = ["esp32s3"] }
|
||||||
hex = { version = "0.4.3", default-features = false, features = ["alloc"] }
|
hex = { version = "0.4.3", default-features = false, features = ["alloc"] }
|
||||||
indoc = "2.0.7"
|
indoc = "2.0.7"
|
||||||
ouroboros = "0.18.5"
|
ouroboros = "0.18.5"
|
||||||
|
esp-hal-bounce-buffers = { git = "https://forgejo.limeth.cz/limeth/esp-hal-bounce-buffers", rev = "8d3763a190368f476aed6d98777264c959bfdc2d", features = ["esp32s3"] }
|
||||||
|
|
||||||
# A fork of slint with patches for `allocator_api` support.
|
# A fork of slint with patches for `allocator_api` support.
|
||||||
# Don't forget to change `slint-build` in build dependencies, if this is changed.
|
# Don't forget to change `slint-build` in build dependencies, if this is changed.
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,6 @@ fn main() {
|
||||||
.map_err(|_| NotBuilt {
|
.map_err(|_| NotBuilt {
|
||||||
lib_build_dir: lib_build_dir_str.clone(),
|
lib_build_dir: lib_build_dir_str.clone(),
|
||||||
})?;
|
})?;
|
||||||
let lib_build_dir = lib_build_dir.display();
|
|
||||||
|
|
||||||
if !lib_library_path.is_file() {
|
if !lib_library_path.is_file() {
|
||||||
return Err(NotBuilt {
|
return Err(NotBuilt {
|
||||||
|
|
@ -89,9 +88,9 @@ fn main() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("cargo:rustc-link-search=native={lib_build_dir}");
|
println!("cargo:rustc-link-search=native={}", lib_build_dir.display());
|
||||||
println!("cargo:rustc-link-lib=static={library}");
|
println!("cargo:rustc-link-lib=static={library}");
|
||||||
println!("cargo:rerun-if-changed={lib_build_dir}/lib{library}.a");
|
println!("cargo:rerun-if-changed={}", lib_library_path.display());
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,11 +18,11 @@ impl embedded_io::ErrorType for Writer {
|
||||||
|
|
||||||
impl embedded_io::Write for Writer {
|
impl embedded_io::Write for Writer {
|
||||||
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
|
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
|
||||||
with_uart_tx(|_, uart| uart.write(buf))
|
with_uart_tx(|uart| uart.write(buf))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flush(&mut self) -> Result<(), Self::Error> {
|
fn flush(&mut self) -> Result<(), Self::Error> {
|
||||||
with_uart_tx(|_, uart| uart.flush())
|
with_uart_tx(|uart| uart.flush())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@ use esp_hal::rng::Trng;
|
||||||
use esp_storage::FlashStorage;
|
use esp_storage::FlashStorage;
|
||||||
use log::{debug, info};
|
use log::{debug, info};
|
||||||
|
|
||||||
|
use crate::ram::{PSRAM_ALLOCATOR, PsramAllocator};
|
||||||
|
|
||||||
pub type PartitionAcid =
|
pub type PartitionAcid =
|
||||||
Partition<'static, CriticalSectionRawMutex, BlockingAsync<FlashStorage<'static>>>;
|
Partition<'static, CriticalSectionRawMutex, BlockingAsync<FlashStorage<'static>>>;
|
||||||
|
|
||||||
|
|
@ -25,7 +27,7 @@ struct AlignedBuf<const N: usize>(pub [u8; N]);
|
||||||
|
|
||||||
pub struct EkvFlash<T> {
|
pub struct EkvFlash<T> {
|
||||||
flash: T,
|
flash: T,
|
||||||
buffer: Box<AlignedBuf<{ ekv::config::PAGE_SIZE }>>,
|
buffer: Box<AlignedBuf<{ ekv::config::PAGE_SIZE }>, PsramAllocator>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> EkvFlash<T> {
|
impl<T> EkvFlash<T> {
|
||||||
|
|
@ -34,7 +36,7 @@ impl<T> EkvFlash<T> {
|
||||||
flash,
|
flash,
|
||||||
buffer: {
|
buffer: {
|
||||||
// Allocate the buffer directly on the heap.
|
// Allocate the buffer directly on the heap.
|
||||||
let buffer = Box::new_zeroed();
|
let buffer = Box::new_zeroed_in(&PSRAM_ALLOCATOR);
|
||||||
unsafe { buffer.assume_init() }
|
unsafe { buffer.assume_init() }
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
256
firmware/acid-firmware/src/dpi.rs
Normal file
256
firmware/acid-firmware/src/dpi.rs
Normal file
|
|
@ -0,0 +1,256 @@
|
||||||
|
use alloc::{alloc::Global, boxed::Box, vec::Vec};
|
||||||
|
use embassy_time::Timer;
|
||||||
|
use esp_hal::{
|
||||||
|
Blocking,
|
||||||
|
dma::{BurstConfig, ExternalBurstConfig, InternalBurstConfig},
|
||||||
|
gpio::{Flex, Level, Output, OutputConfig},
|
||||||
|
lcd_cam::{LcdCam, lcd::dpi::Dpi},
|
||||||
|
ledc::{self, LSGlobalClkSource, Ledc, LowSpeed},
|
||||||
|
spi::master::AnySpi,
|
||||||
|
};
|
||||||
|
use esp_hal_bounce_buffers::{DmaBounce, Swapchain, SwapchainWriter, allocate_dma_buffer_in};
|
||||||
|
use i_slint_core::software_renderer::{Rgb565Pixel, TargetPixel};
|
||||||
|
use log::{error, info};
|
||||||
|
|
||||||
|
use crate::{DmaBounceController, PSRAM_ALLOCATOR, peripherals::st7701s::St7701s};
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub struct DisplayPeripherals {
|
||||||
|
pub DMA_CH2: esp_hal::peripherals::DMA_CH2<'static>,
|
||||||
|
pub LCD_CAM: esp_hal::peripherals::LCD_CAM<'static>,
|
||||||
|
pub LEDC: esp_hal::peripherals::LEDC<'static>,
|
||||||
|
pub GPIO0: Output<'static>,
|
||||||
|
pub GPIO1: esp_hal::peripherals::GPIO1<'static>,
|
||||||
|
pub GPIO2: esp_hal::peripherals::GPIO2<'static>,
|
||||||
|
pub GPIO3: esp_hal::peripherals::GPIO3<'static>,
|
||||||
|
pub GPIO4: esp_hal::peripherals::GPIO4<'static>,
|
||||||
|
#[cfg(not(feature = "alt-log"))]
|
||||||
|
pub GPIO5: esp_hal::peripherals::GPIO5<'static>,
|
||||||
|
pub GPIO6: esp_hal::peripherals::GPIO6<'static>,
|
||||||
|
#[cfg(not(feature = "alt-log"))]
|
||||||
|
pub GPIO12: esp_hal::peripherals::GPIO12<'static>,
|
||||||
|
pub GPIO13: esp_hal::peripherals::GPIO13<'static>,
|
||||||
|
pub GPIO14: esp_hal::peripherals::GPIO14<'static>,
|
||||||
|
pub GPIO15: esp_hal::peripherals::GPIO15<'static>,
|
||||||
|
pub GPIO16: esp_hal::peripherals::GPIO16<'static>,
|
||||||
|
pub GPIO21: esp_hal::peripherals::GPIO21<'static>,
|
||||||
|
pub GPIO34: esp_hal::peripherals::GPIO34<'static>,
|
||||||
|
pub GPIO35: esp_hal::peripherals::GPIO35<'static>,
|
||||||
|
pub GPIO36: esp_hal::peripherals::GPIO36<'static>,
|
||||||
|
pub GPIO37: esp_hal::peripherals::GPIO37<'static>,
|
||||||
|
pub GPIO38: esp_hal::peripherals::GPIO38<'static>,
|
||||||
|
pub GPIO39: esp_hal::peripherals::GPIO39<'static>,
|
||||||
|
pub GPIO40: esp_hal::peripherals::GPIO40<'static>,
|
||||||
|
pub GPIO41: esp_hal::peripherals::GPIO41<'static>,
|
||||||
|
pub GPIO42: esp_hal::peripherals::GPIO42<'static>,
|
||||||
|
pub GPIO43: esp_hal::peripherals::GPIO43<'static>,
|
||||||
|
pub GPIO44: esp_hal::peripherals::GPIO44<'static>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DisplayPeripherals {
|
||||||
|
pub async fn into_display(self) -> St7701s<'static, Blocking> {
|
||||||
|
let mut ledc = Ledc::new(self.LEDC);
|
||||||
|
ledc.set_global_slow_clock(LSGlobalClkSource::APBClk);
|
||||||
|
let bl_timer = ledc.timer::<LowSpeed>(ledc::timer::Number::Timer0);
|
||||||
|
let bl_channel = ledc.channel::<LowSpeed>(ledc::channel::Number::Channel0, self.GPIO21);
|
||||||
|
|
||||||
|
let sck = Output::new(self.GPIO36, Level::High, OutputConfig::default());
|
||||||
|
let mosi = Flex::new(self.GPIO35);
|
||||||
|
let cs = Output::new(self.GPIO6, Level::High, OutputConfig::default());
|
||||||
|
|
||||||
|
let lcd = LcdCam::new(self.LCD_CAM).lcd;
|
||||||
|
#[allow(unused_mut)]
|
||||||
|
let mut unconfigured_dpi = Dpi::new(lcd, self.DMA_CH2, Default::default())
|
||||||
|
.unwrap()
|
||||||
|
.with_de(self.GPIO37)
|
||||||
|
.with_pclk(self.GPIO34)
|
||||||
|
.with_hsync(self.GPIO44)
|
||||||
|
.with_vsync(self.GPIO43)
|
||||||
|
// Blue
|
||||||
|
.with_data0(self.GPIO38)
|
||||||
|
.with_data1(self.GPIO39)
|
||||||
|
.with_data2(self.GPIO40)
|
||||||
|
.with_data3(self.GPIO41)
|
||||||
|
.with_data4(self.GPIO42)
|
||||||
|
// Green
|
||||||
|
.with_data7(self.GPIO13)
|
||||||
|
.with_data8(self.GPIO14)
|
||||||
|
.with_data9(self.GPIO15)
|
||||||
|
.with_data10(self.GPIO16)
|
||||||
|
// Red
|
||||||
|
.with_data11(self.GPIO0)
|
||||||
|
.with_data12(self.GPIO1)
|
||||||
|
.with_data13(self.GPIO2)
|
||||||
|
.with_data14(self.GPIO3)
|
||||||
|
.with_data15(self.GPIO4);
|
||||||
|
|
||||||
|
#[cfg(not(feature = "alt-log"))]
|
||||||
|
{
|
||||||
|
unconfigured_dpi = unconfigured_dpi
|
||||||
|
// Green
|
||||||
|
.with_data5(peripherals.GPIO5)
|
||||||
|
.with_data6(peripherals.GPIO12);
|
||||||
|
}
|
||||||
|
|
||||||
|
let st7701s = St7701s::new(sck, mosi, cs, unconfigured_dpi, bl_timer, bl_channel).await;
|
||||||
|
info!("ST7701S-based LCD display initialized!");
|
||||||
|
st7701s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Rename or get rid of.
|
||||||
|
pub struct Framebuffer {
|
||||||
|
pub width: u32,
|
||||||
|
pub height: u32,
|
||||||
|
pub swapchain: Option<SwapchainWriter>,
|
||||||
|
pub bounce_buffers: Option<DmaBounce>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Framebuffer {
|
||||||
|
pub fn new(
|
||||||
|
channel: esp_hal::peripherals::DMA_CH0<'static>,
|
||||||
|
peripheral_src: AnySpi<'static>,
|
||||||
|
peripheral_dst: Dpi<'static, Blocking>,
|
||||||
|
burst_config: BurstConfig,
|
||||||
|
front_porch_pixels: u32,
|
||||||
|
width_pixels: u32,
|
||||||
|
height_pixels: u32,
|
||||||
|
rows_per_window: usize,
|
||||||
|
cyclic: bool,
|
||||||
|
) -> Self {
|
||||||
|
const BYTES_PER_PIXEL: usize = core::mem::size_of::<u16>();
|
||||||
|
let buffer_size = width_pixels as usize * height_pixels as usize * BYTES_PER_PIXEL;
|
||||||
|
let framebuffers = [
|
||||||
|
Box::leak(allocate_dma_buffer_in(
|
||||||
|
buffer_size,
|
||||||
|
burst_config,
|
||||||
|
&PSRAM_ALLOCATOR,
|
||||||
|
)),
|
||||||
|
Box::leak(allocate_dma_buffer_in(
|
||||||
|
buffer_size,
|
||||||
|
burst_config,
|
||||||
|
&PSRAM_ALLOCATOR,
|
||||||
|
)),
|
||||||
|
];
|
||||||
|
let (swapchain_reader, swapchain_writer) = Swapchain { framebuffers }.into_reader_writer();
|
||||||
|
let bounce_buffers = DmaBounce::new(
|
||||||
|
Global,
|
||||||
|
channel,
|
||||||
|
peripheral_src,
|
||||||
|
peripheral_dst,
|
||||||
|
swapchain_reader,
|
||||||
|
front_porch_pixels as usize * BYTES_PER_PIXEL,
|
||||||
|
width_pixels as usize * BYTES_PER_PIXEL,
|
||||||
|
rows_per_window,
|
||||||
|
burst_config,
|
||||||
|
cyclic,
|
||||||
|
);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
width: width_pixels,
|
||||||
|
height: height_pixels,
|
||||||
|
swapchain: Some(swapchain_writer),
|
||||||
|
bounce_buffers: Some(bounce_buffers),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub async fn test_bounce_buffers(
|
||||||
|
channel: esp_hal::peripherals::DMA_CH0<'static>,
|
||||||
|
peripheral: esp_hal::peripherals::SPI2<'static>,
|
||||||
|
display_peripherals: DisplayPeripherals,
|
||||||
|
) {
|
||||||
|
error!("TEST BOUNCE BUFFERS SECTION ENTERED");
|
||||||
|
|
||||||
|
const BYTES_PER_PIXEL: usize = core::mem::size_of::<u16>();
|
||||||
|
// Assume highest burst config setting.
|
||||||
|
const EXTERNAL_BURST_CONFIG: ExternalBurstConfig = ExternalBurstConfig::Size32;
|
||||||
|
const ALIGNMENT_PIXELS: usize = EXTERNAL_BURST_CONFIG as usize / BYTES_PER_PIXEL;
|
||||||
|
// The total number of pixels demanded by the DPI, per row.
|
||||||
|
const WIDTH_TOTAL_PIXELS: usize = 368;
|
||||||
|
// The total number of rows demanded by the DPI, per frame.
|
||||||
|
const HEIGHT_PIXELS: usize = 960;
|
||||||
|
// The number of unused pixels at the start of the row.
|
||||||
|
const FRONT_PORCH_ACTUAL_PIXELS: usize = 120;
|
||||||
|
// The number of actually visible pixels, per row.
|
||||||
|
const WIDTH_VISIBLE_PIXELS: usize = 240;
|
||||||
|
// The number of pixels not stored in a bounce buffer, per row.
|
||||||
|
// This many arbitrary pixels are sent to the DPI.
|
||||||
|
const FRONT_PORCH_SKIPPED_PIXELS: usize =
|
||||||
|
(FRONT_PORCH_ACTUAL_PIXELS / ALIGNMENT_PIXELS) * ALIGNMENT_PIXELS;
|
||||||
|
const WIDTH_STORED_PIXELS: usize = WIDTH_TOTAL_PIXELS - FRONT_PORCH_SKIPPED_PIXELS;
|
||||||
|
const VISIBLE_OFFSET_IN_BUFFER_PIXELS: usize =
|
||||||
|
FRONT_PORCH_ACTUAL_PIXELS - FRONT_PORCH_SKIPPED_PIXELS;
|
||||||
|
const ROWS_PER_WINDOW: usize = 16;
|
||||||
|
let burst_config = BurstConfig {
|
||||||
|
internal_memory: InternalBurstConfig::Enabled,
|
||||||
|
external_memory: EXTERNAL_BURST_CONFIG,
|
||||||
|
};
|
||||||
|
let (swapchain_reader, mut swapchain_writer) = Swapchain {
|
||||||
|
framebuffers: [
|
||||||
|
Box::leak(allocate_dma_buffer_in(
|
||||||
|
HEIGHT_PIXELS * WIDTH_STORED_PIXELS * BYTES_PER_PIXEL,
|
||||||
|
burst_config,
|
||||||
|
&PSRAM_ALLOCATOR,
|
||||||
|
)),
|
||||||
|
Box::leak(allocate_dma_buffer_in(
|
||||||
|
HEIGHT_PIXELS * WIDTH_STORED_PIXELS * BYTES_PER_PIXEL,
|
||||||
|
burst_config,
|
||||||
|
&PSRAM_ALLOCATOR,
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
}
|
||||||
|
.into_reader_writer();
|
||||||
|
|
||||||
|
{
|
||||||
|
let write_guard = &mut swapchain_writer.write();
|
||||||
|
let buffer_src = bytemuck::cast_slice_mut::<u8, Rgb565Pixel>(write_guard);
|
||||||
|
let colors = (0..WIDTH_VISIBLE_PIXELS as u8 / 2)
|
||||||
|
.rev()
|
||||||
|
.map(|val| Rgb565Pixel::from_rgb(0xFF, val * 2, 0))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
for (index, pixel) in buffer_src.iter_mut().enumerate() {
|
||||||
|
let mut x =
|
||||||
|
(index % WIDTH_STORED_PIXELS) as i16 - VISIBLE_OFFSET_IN_BUFFER_PIXELS as i16;
|
||||||
|
let mut y = (index / WIDTH_STORED_PIXELS) as i16;
|
||||||
|
|
||||||
|
if x < WIDTH_VISIBLE_PIXELS as i16 {
|
||||||
|
x = core::cmp::min(x, WIDTH_VISIBLE_PIXELS as i16 - 1 - x);
|
||||||
|
y = core::cmp::min(y, HEIGHT_PIXELS as i16 - 1 - y);
|
||||||
|
let min = core::cmp::min(x, y);
|
||||||
|
|
||||||
|
*pixel = colors[min as usize % colors.len()];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
*pixel = Rgb565Pixel::default();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut st7701s = display_peripherals.into_display().await;
|
||||||
|
let mut dma_bounce = DmaBounce::new(
|
||||||
|
Global,
|
||||||
|
channel,
|
||||||
|
AnySpi::from(peripheral),
|
||||||
|
st7701s.dpi,
|
||||||
|
swapchain_reader,
|
||||||
|
FRONT_PORCH_SKIPPED_PIXELS * BYTES_PER_PIXEL,
|
||||||
|
WIDTH_STORED_PIXELS * BYTES_PER_PIXEL,
|
||||||
|
ROWS_PER_WINDOW,
|
||||||
|
burst_config,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
let mut bb_controller = DmaBounceController::new(dma_bounce);
|
||||||
|
|
||||||
|
error!("TEST BOUNCE BUFFERS TASK LAUNCHED");
|
||||||
|
|
||||||
|
loop {
|
||||||
|
bb_controller.start().await.unwrap();
|
||||||
|
st7701s.controller.sleep_off().await;
|
||||||
|
Timer::after_secs(1).await;
|
||||||
|
st7701s.controller.sleep_on().await;
|
||||||
|
bb_controller.stop().await.unwrap();
|
||||||
|
Timer::after_secs(1).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,7 +8,7 @@ use enumset::EnumSet;
|
||||||
use crate::ffi::string::__xkbc_memcpy;
|
use crate::ffi::string::__xkbc_memcpy;
|
||||||
|
|
||||||
// Here we select the allocator to use for libxkbcommon.
|
// Here we select the allocator to use for libxkbcommon.
|
||||||
pub use crate::PSRAM_ALLOCATOR as XKBC_ALLOCATOR;
|
pub use crate::ram::PSRAM_ALLOCATOR as XKBC_ALLOCATOR;
|
||||||
|
|
||||||
// Implementation based on esp-alloc's `compat` feature.
|
// Implementation based on esp-alloc's `compat` feature.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ use core::{
|
||||||
ffi::{c_char, c_int, c_size_t, c_uchar, c_ulonglong},
|
ffi::{c_char, c_int, c_size_t, c_uchar, c_ulonglong},
|
||||||
};
|
};
|
||||||
|
|
||||||
use critical_section::Mutex;
|
|
||||||
use embassy_sync::blocking_mutex::{self, raw::CriticalSectionRawMutex};
|
use embassy_sync::blocking_mutex::{self, raw::CriticalSectionRawMutex};
|
||||||
use hmac::digest::{FixedOutput, KeyInit, Update};
|
use hmac::digest::{FixedOutput, KeyInit, Update};
|
||||||
use password_hash::Key;
|
use password_hash::Key;
|
||||||
|
|
@ -39,7 +38,8 @@ unsafe extern "C" fn __spre_crypto_hash_sha256(
|
||||||
|
|
||||||
/// This is the encrypted user key currently being used in the key derivation function of spectre.
|
/// This is the encrypted user key currently being used in the key derivation function of spectre.
|
||||||
/// It decrypts using the user's password into the key that would be derived with the original password hashing function.
|
/// It decrypts using the user's password into the key that would be derived with the original password hashing function.
|
||||||
pub static ACTIVE_ENCRYPTED_USER_KEY: Mutex<Cell<Key>> = Mutex::new(Cell::new([0; _]));
|
pub static ACTIVE_ENCRYPTED_USER_KEY: blocking_mutex::Mutex<CriticalSectionRawMutex, Cell<Key>> =
|
||||||
|
blocking_mutex::Mutex::new(Cell::new([0; _]));
|
||||||
|
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
|
@ -65,7 +65,7 @@ unsafe extern "C" fn __spre_crypto_pwhash_scryptsalsa208sha256_ll(
|
||||||
};
|
};
|
||||||
|
|
||||||
let output: &mut [u8] = unsafe { core::slice::from_raw_parts_mut(output, output_len) };
|
let output: &mut [u8] = unsafe { core::slice::from_raw_parts_mut(output, output_len) };
|
||||||
let mut user_key = critical_section::with(|cs| ACTIVE_ENCRYPTED_USER_KEY.borrow(cs).get());
|
let mut user_key = ACTIVE_ENCRYPTED_USER_KEY.lock(|user_key| user_key.get());
|
||||||
|
|
||||||
password_hash::decrypt_with(&mut user_key, &encryption_key);
|
password_hash::decrypt_with(&mut user_key, &encryption_key);
|
||||||
output.copy_from_slice(&user_key);
|
output.copy_from_slice(&user_key);
|
||||||
|
|
|
||||||
|
|
@ -149,7 +149,8 @@ pub unsafe extern "C" fn __xkbc_atoi(s: *const c_char) -> c_int {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: What is this even for?
|
// A pointer to an array of character attributes.
|
||||||
|
// This is used by `isdigit()`, `isalpha()`, `isspace()`, etc.
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
pub static __spre__ctype_: [c_char; 0] = [];
|
pub static __spre__ctype_: [c_char; 0] = [];
|
||||||
|
|
||||||
|
|
|
||||||
117
firmware/acid-firmware/src/flash.rs
Normal file
117
firmware/acid-firmware/src/flash.rs
Normal file
|
|
@ -0,0 +1,117 @@
|
||||||
|
use core::fmt::Write;
|
||||||
|
|
||||||
|
use alloc::{string::String, vec::Vec};
|
||||||
|
use embassy_embedded_hal::adapter::BlockingAsync;
|
||||||
|
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, mutex::Mutex};
|
||||||
|
use esp_bootloader_esp_idf::partitions::PartitionTable;
|
||||||
|
use esp_storage::FlashStorage;
|
||||||
|
use indoc::writedoc;
|
||||||
|
use log::info;
|
||||||
|
use rmk::storage::async_flash_wrapper;
|
||||||
|
use static_cell::StaticCell;
|
||||||
|
|
||||||
|
use crate::{PSRAM_ALLOCATOR, ram::PsramAllocator};
|
||||||
|
|
||||||
|
pub type Partition = embassy_embedded_hal::flash::partition::Partition<
|
||||||
|
'static,
|
||||||
|
CriticalSectionRawMutex,
|
||||||
|
BlockingAsync<FlashStorage<'static>>,
|
||||||
|
>;
|
||||||
|
|
||||||
|
pub struct Partitions {
|
||||||
|
pub rmk: Partition,
|
||||||
|
pub acid: Partition,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize the flash
|
||||||
|
pub fn initialize(flash_peripheral: esp_hal::peripherals::FLASH<'static>) -> Partitions {
|
||||||
|
static PARTITION_TABLE_BUFFER: StaticCell<Vec<u8, PsramAllocator>> = StaticCell::new();
|
||||||
|
let partition_table_buffer = PARTITION_TABLE_BUFFER.init_with(|| {
|
||||||
|
let mut buffer = Vec::<u8, _>::new_in(&PSRAM_ALLOCATOR);
|
||||||
|
buffer.resize(
|
||||||
|
esp_bootloader_esp_idf::partitions::PARTITION_TABLE_MAX_LEN,
|
||||||
|
0_u8,
|
||||||
|
);
|
||||||
|
buffer
|
||||||
|
});
|
||||||
|
|
||||||
|
static FLASH: StaticCell<(
|
||||||
|
Mutex<CriticalSectionRawMutex, BlockingAsync<FlashStorage>>,
|
||||||
|
PartitionTable<'static>,
|
||||||
|
)> = StaticCell::new();
|
||||||
|
let (flash, partition_table) = FLASH.init_with(|| {
|
||||||
|
let mut flash = FlashStorage::new(flash_peripheral)
|
||||||
|
// Flash memory may not be written to while another core is executing from it.
|
||||||
|
// By default, `FlashStorage` is configured to abort the operation and log an error message.
|
||||||
|
// However, it can also be configured to auto-park the other core, such that writing to
|
||||||
|
// flash succeeds.
|
||||||
|
// Alternatively, XiP from PSRAM could be used along with the `multicore_ignore` strategy,
|
||||||
|
// to avoid having to park the other core, which could result in better performance.
|
||||||
|
// Invalid configuration would then present itself as freezing/UB.
|
||||||
|
.multicore_auto_park();
|
||||||
|
let partition_table = {
|
||||||
|
esp_bootloader_esp_idf::partitions::read_partition_table(
|
||||||
|
&mut flash,
|
||||||
|
partition_table_buffer,
|
||||||
|
)
|
||||||
|
.expect("Failed to read the partition table.")
|
||||||
|
};
|
||||||
|
|
||||||
|
(
|
||||||
|
Mutex::<CriticalSectionRawMutex, _>::new(async_flash_wrapper(flash)),
|
||||||
|
partition_table,
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut buffer = String::new();
|
||||||
|
|
||||||
|
writeln!(buffer, "Partition table:").unwrap();
|
||||||
|
|
||||||
|
for (index, partition) in partition_table.iter().enumerate() {
|
||||||
|
writedoc!(
|
||||||
|
buffer,
|
||||||
|
"
|
||||||
|
Partition #{index} {label:?}:
|
||||||
|
offset: 0x{offset:x}
|
||||||
|
length: 0x{len:x}
|
||||||
|
type: 0x{type:?}
|
||||||
|
read only: {read_only}
|
||||||
|
encrypted: {encrypted}
|
||||||
|
magic: {magic}
|
||||||
|
",
|
||||||
|
label = partition.label_as_str(),
|
||||||
|
offset = partition.offset(),
|
||||||
|
len = partition.len(),
|
||||||
|
type = partition.partition_type(),
|
||||||
|
read_only = partition.is_read_only(),
|
||||||
|
encrypted = partition.is_encrypted(),
|
||||||
|
magic = partition.magic(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
info!("{}", buffer);
|
||||||
|
}
|
||||||
|
let flash_part_info_rmk = partition_table
|
||||||
|
.iter()
|
||||||
|
.find(|partition| partition.label_as_str() == "rmk")
|
||||||
|
.expect("No \"rmk\" partition found. Make sure to use the custom partition-table.csv when flashing.");
|
||||||
|
let flash_part_info_acid = partition_table
|
||||||
|
.iter()
|
||||||
|
.find(|partition| partition.label_as_str() == "acid")
|
||||||
|
.expect("No \"acid\" partition found. Make sure to use the custom partition-table.csv when flashing.");
|
||||||
|
|
||||||
|
Partitions {
|
||||||
|
rmk: Partition::new(
|
||||||
|
flash,
|
||||||
|
flash_part_info_rmk.offset(),
|
||||||
|
flash_part_info_rmk.len(),
|
||||||
|
),
|
||||||
|
acid: Partition::new(
|
||||||
|
flash,
|
||||||
|
flash_part_info_acid.offset(),
|
||||||
|
flash_part_info_acid.len(),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,7 @@ use core::fmt::Arguments;
|
||||||
|
|
||||||
use log::LevelFilter;
|
use log::LevelFilter;
|
||||||
|
|
||||||
|
// TODO: Replace with `log`'s `STATIC_MAX_LEVEL` set via crate features.
|
||||||
pub const LOG_LEVEL_FILTER: LevelFilter = {
|
pub const LOG_LEVEL_FILTER: LevelFilter = {
|
||||||
if let Some(string) = option_env!("ESP_LOG") {
|
if let Some(string) = option_env!("ESP_LOG") {
|
||||||
if string.eq_ignore_ascii_case("OFF") {
|
if string.eq_ignore_ascii_case("OFF") {
|
||||||
|
|
@ -70,27 +71,45 @@ pub mod usb {
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod uart {
|
pub mod uart {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::console;
|
|
||||||
use core::{cell::RefCell, fmt::Write};
|
use core::{cell::RefCell, fmt::Write};
|
||||||
use critical_section::{CriticalSection, Mutex};
|
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||||
use esp_hal::{
|
use esp_hal::{Blocking, uart::UartTx};
|
||||||
Blocking,
|
|
||||||
gpio::interconnect::{PeripheralInput, PeripheralOutput},
|
|
||||||
uart::{Uart, UartTx},
|
|
||||||
};
|
|
||||||
use log::{Log, info};
|
use log::{Log, info};
|
||||||
|
|
||||||
static ALT_LOGGER_UART: Mutex<RefCell<Option<UartTx<'static, Blocking>>>> =
|
#[cfg(feature = "racy-logging")]
|
||||||
Mutex::new(RefCell::new(None));
|
static ALT_LOGGER_UART: embassy_sync::mutex::Mutex<
|
||||||
|
CriticalSectionRawMutex,
|
||||||
|
RefCell<Option<UartTx<'static, Blocking>>>,
|
||||||
|
> = embassy_sync::mutex::Mutex::new(RefCell::new(None));
|
||||||
|
|
||||||
pub fn with_uart_tx<R>(
|
#[cfg(not(feature = "racy-logging"))]
|
||||||
f: impl FnOnce(CriticalSection<'_>, &'_ mut UartTx<'static, Blocking>) -> R,
|
static ALT_LOGGER_UART: embassy_sync::blocking_mutex::Mutex<
|
||||||
) -> R {
|
CriticalSectionRawMutex,
|
||||||
critical_section::with(|cs| {
|
RefCell<Option<UartTx<'static, Blocking>>>,
|
||||||
let mut uart = ALT_LOGGER_UART.borrow(cs).borrow_mut();
|
> = embassy_sync::blocking_mutex::Mutex::new(RefCell::new(None));
|
||||||
|
|
||||||
|
#[cfg(feature = "racy-logging")]
|
||||||
|
pub fn with_uart_tx<R>(f: impl FnOnce(&'_ mut UartTx<'static, Blocking>) -> R) -> R {
|
||||||
|
use crate::util::MutexExt;
|
||||||
|
|
||||||
|
// Safety:
|
||||||
|
// * The guard is not held across yield points.
|
||||||
|
// * **CARE MUST BE TAKEN NOT TO INVOKE THIS FUNCTION FROM AN INTERRUPT HANDLER.**
|
||||||
|
let uart = unsafe { ALT_LOGGER_UART.lock_blocking() };
|
||||||
|
let mut uart = uart.borrow_mut();
|
||||||
|
let uart = uart.as_mut().unwrap();
|
||||||
|
|
||||||
|
(f)(uart)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "racy-logging"))]
|
||||||
|
pub fn with_uart_tx<R>(f: impl FnOnce(&'_ mut UartTx<'static, Blocking>) -> R) -> R {
|
||||||
|
ALT_LOGGER_UART.lock(|uart| {
|
||||||
|
let mut uart = uart.borrow_mut();
|
||||||
let uart = uart.as_mut().unwrap();
|
let uart = uart.as_mut().unwrap();
|
||||||
|
|
||||||
(f)(cs, uart)
|
(f)(uart)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -107,7 +126,7 @@ pub mod uart {
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
fn do_print(args: core::fmt::Arguments<'_>) {
|
fn do_print(args: core::fmt::Arguments<'_>) {
|
||||||
with_uart_tx(|_, uart| {
|
with_uart_tx(|uart| {
|
||||||
uart.write_fmt(format_args!("{}\n", args)).unwrap();
|
uart.write_fmt(format_args!("{}\n", args)).unwrap();
|
||||||
uart.flush().unwrap();
|
uart.flush().unwrap();
|
||||||
})
|
})
|
||||||
|
|
@ -124,7 +143,7 @@ pub mod uart {
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
fn log(&self, record: &log::Record) {
|
fn log(&self, record: &log::Record) {
|
||||||
with_uart_tx(|cs, uart| {
|
with_uart_tx(|uart| {
|
||||||
with_formatted_log_record(record, |args| uart.write_fmt(args)).unwrap();
|
with_formatted_log_record(record, |args| uart.write_fmt(args)).unwrap();
|
||||||
uart.flush().unwrap();
|
uart.flush().unwrap();
|
||||||
})
|
})
|
||||||
|
|
@ -155,9 +174,23 @@ pub mod uart {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setup_logging(uart_tx: UartTx<'static, Blocking>) {
|
pub fn setup_logging(uart_tx: UartTx<'static, Blocking>) {
|
||||||
critical_section::with(|cs| {
|
{
|
||||||
*ALT_LOGGER_UART.borrow(cs).borrow_mut() = Some(uart_tx);
|
#[cfg(feature = "racy-logging")]
|
||||||
});
|
{
|
||||||
|
use crate::util::MutexExt;
|
||||||
|
|
||||||
|
// Safety:
|
||||||
|
// * The guard is not held across yield points.
|
||||||
|
// * This function is not invoked from an interrupt handler.
|
||||||
|
let uart = unsafe { ALT_LOGGER_UART.lock_blocking() };
|
||||||
|
*uart.borrow_mut() = Some(uart_tx);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "racy-logging"))]
|
||||||
|
ALT_LOGGER_UART.lock(move |uart| {
|
||||||
|
*uart.borrow_mut() = Some(uart_tx);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
log::set_logger_racy(&UartLogger).unwrap();
|
log::set_logger_racy(&UartLogger).unwrap();
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![feature(allocator_api)]
|
#![feature(allocator_api)]
|
||||||
|
#![feature(btreemap_alloc)]
|
||||||
#![feature(macro_metavar_expr)]
|
#![feature(macro_metavar_expr)]
|
||||||
#![feature(c_variadic)]
|
#![feature(c_variadic)]
|
||||||
#![feature(c_size_t)]
|
#![feature(c_size_t)]
|
||||||
|
|
@ -16,59 +17,37 @@
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use core::alloc::Layout;
|
|
||||||
use core::cell::RefCell;
|
use core::cell::RefCell;
|
||||||
use core::fmt::Write;
|
|
||||||
use core::sync::atomic::{AtomicBool, Ordering};
|
use core::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
|
||||||
use alloc::alloc::Global;
|
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
use alloc::collections::vec_deque::VecDeque;
|
use alloc::collections::vec_deque::VecDeque;
|
||||||
use alloc::format;
|
use alloc::format;
|
||||||
use alloc::string::String;
|
|
||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
use alloc::vec;
|
use embassy_executor::Spawner;
|
||||||
use alloc::vec::Vec;
|
use embassy_sync::blocking_mutex;
|
||||||
use cfg_if::cfg_if;
|
|
||||||
use embassy_embedded_hal::adapter::BlockingAsync;
|
|
||||||
use embassy_embedded_hal::flash::partition::Partition;
|
|
||||||
use embassy_executor::{SendSpawner, Spawner, SpawnerTraceExt};
|
|
||||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||||
use embassy_sync::channel::Channel;
|
use embassy_sync::channel::Channel;
|
||||||
use embassy_sync::mutex::Mutex;
|
|
||||||
use embassy_sync::signal::Signal;
|
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
use esp_alloc::{HeapRegion, MemoryCapability};
|
use esp_alloc::MemoryCapability;
|
||||||
use esp_bootloader_esp_idf::partitions::PartitionTable;
|
|
||||||
use esp_hal::clock::CpuClock;
|
use esp_hal::clock::CpuClock;
|
||||||
use esp_hal::dma::{
|
use esp_hal::dma::{BurstConfig, ExternalBurstConfig, InternalBurstConfig};
|
||||||
BurstConfig, DmaDescriptor, DmaTxBuf, ExternalBurstConfig, InternalBurstConfig,
|
|
||||||
};
|
|
||||||
use esp_hal::efuse::Efuse;
|
use esp_hal::efuse::Efuse;
|
||||||
#[cfg(not(feature = "alt-log"))]
|
use esp_hal::gpio::{Input, InputConfig, Level, Output, OutputConfig, Pull};
|
||||||
use esp_hal::gpio::NoPin;
|
|
||||||
use esp_hal::gpio::{Flex, Input, InputConfig, Level, Output, OutputConfig, Pull};
|
|
||||||
use esp_hal::i2c::master::{I2c, I2cAddress};
|
use esp_hal::i2c::master::{I2c, I2cAddress};
|
||||||
use esp_hal::interrupt::software::{SoftwareInterrupt, SoftwareInterruptControl};
|
use esp_hal::interrupt::software::{SoftwareInterrupt, SoftwareInterruptControl};
|
||||||
use esp_hal::lcd_cam::LcdCam;
|
|
||||||
use esp_hal::lcd_cam::lcd::dpi::{Dpi, DpiTransfer};
|
|
||||||
use esp_hal::mcpwm::{McPwm, PeripheralClockConfig};
|
|
||||||
use esp_hal::peripherals::{DMA_CH0, SPI0, SPI2};
|
|
||||||
use esp_hal::psram::{FlashFreq, PsramConfig, PsramSize, SpiRamFreq, SpiTimingConfigCoreClock};
|
use esp_hal::psram::{FlashFreq, PsramConfig, PsramSize, SpiRamFreq, SpiTimingConfigCoreClock};
|
||||||
use esp_hal::ram;
|
|
||||||
use esp_hal::rng::TrngSource;
|
use esp_hal::rng::TrngSource;
|
||||||
use esp_hal::sha::ShaBackend;
|
use esp_hal::sha::ShaBackend;
|
||||||
use esp_hal::spi::master::AnySpi;
|
|
||||||
use esp_hal::system::Stack;
|
use esp_hal::system::Stack;
|
||||||
use esp_hal::timer::timg::TimerGroup;
|
use esp_hal::timer::timg::TimerGroup;
|
||||||
use esp_hal::uart::{Uart, UartRx};
|
use esp_hal::uart::{Uart, UartRx};
|
||||||
use esp_hal::{Blocking, interrupt};
|
use esp_hal::{Blocking, interrupt};
|
||||||
|
use esp_hal_bounce_buffers::{DmaBounce, RunningDmaBounceHandle};
|
||||||
use esp_rtos::embassy::{Executor, InterruptExecutor};
|
use esp_rtos::embassy::{Executor, InterruptExecutor};
|
||||||
use esp_storage::FlashStorage;
|
use esp_storage::FlashStorage;
|
||||||
use i_slint_core::software_renderer::TargetPixel;
|
|
||||||
use indoc::writedoc;
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use log::{error, info, warn};
|
use log::{info, warn};
|
||||||
use rmk::channel::{CONTROLLER_CHANNEL, ControllerSub};
|
use rmk::channel::{CONTROLLER_CHANNEL, ControllerSub};
|
||||||
use rmk::config::{DeviceConfig, RmkConfig, StorageConfig, VialConfig};
|
use rmk::config::{DeviceConfig, RmkConfig, StorageConfig, VialConfig};
|
||||||
use rmk::controller::{Controller, EventController};
|
use rmk::controller::{Controller, EventController};
|
||||||
|
|
@ -78,18 +57,18 @@ use rmk::hid::Report;
|
||||||
use rmk::input_device::Runnable;
|
use rmk::input_device::Runnable;
|
||||||
use rmk::join_all;
|
use rmk::join_all;
|
||||||
use rmk::keyboard::Keyboard;
|
use rmk::keyboard::Keyboard;
|
||||||
use rmk::storage::async_flash_wrapper;
|
|
||||||
use rmk::types::action::{Action, KeyAction};
|
use rmk::types::action::{Action, KeyAction};
|
||||||
use rmk::{initialize_keymap_and_storage, run_devices, run_rmk};
|
use rmk::{initialize_keymap_and_storage, run_devices, run_rmk};
|
||||||
use slint::platform::software_renderer::Rgb565Pixel;
|
|
||||||
use static_cell::StaticCell;
|
use static_cell::StaticCell;
|
||||||
use {esp_alloc as _, esp_backtrace as _};
|
use {esp_alloc as _, esp_backtrace as _};
|
||||||
|
|
||||||
|
use crate::dpi::{DisplayPeripherals, Framebuffer};
|
||||||
|
use crate::flash::Partition;
|
||||||
use crate::matrix::IoeMatrix;
|
use crate::matrix::IoeMatrix;
|
||||||
use crate::peripherals::st7701s::St7701s;
|
use crate::peripherals::st7701s::St7701sController;
|
||||||
use crate::proxy::create_hid_report_interceptor;
|
use crate::proxy::create_hid_report_interceptor;
|
||||||
|
use crate::ram::{PSRAM_ALLOCATOR, STACK_SIZE_CORE_APP};
|
||||||
use crate::ui::backend::SlintBackend;
|
use crate::ui::backend::SlintBackend;
|
||||||
use crate::ui::dpi::{DmaBounce, DmaTxBounceBuf, Framebuffer, Swapchain, allocate_dma_buffer_in};
|
|
||||||
use crate::vial::{
|
use crate::vial::{
|
||||||
CustomKeycodes, VIAL_KEYBOARD_DEF, VIAL_KEYBOARD_ID, VIAL_KEYBOARD_NAME, VIAL_PRODUCT_ID,
|
CustomKeycodes, VIAL_KEYBOARD_DEF, VIAL_KEYBOARD_ID, VIAL_KEYBOARD_NAME, VIAL_PRODUCT_ID,
|
||||||
VIAL_VENDOR_ID,
|
VIAL_VENDOR_ID,
|
||||||
|
|
@ -100,11 +79,14 @@ mutually_exclusive_features::none_or_one_of!["usb-log", "alt-log", "rtt-log"];
|
||||||
mod config;
|
mod config;
|
||||||
mod crypto;
|
mod crypto;
|
||||||
mod db;
|
mod db;
|
||||||
|
mod dpi;
|
||||||
mod ffi;
|
mod ffi;
|
||||||
|
mod flash;
|
||||||
mod logging;
|
mod logging;
|
||||||
mod matrix;
|
mod matrix;
|
||||||
mod peripherals;
|
mod peripherals;
|
||||||
mod proxy;
|
mod proxy;
|
||||||
|
mod ram;
|
||||||
mod ui;
|
mod ui;
|
||||||
mod util;
|
mod util;
|
||||||
mod vial;
|
mod vial;
|
||||||
|
|
@ -116,129 +98,12 @@ mod console;
|
||||||
// For more information see: <https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/app_image_format.html#application-description>
|
// For more information see: <https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/app_image_format.html#application-description>
|
||||||
esp_bootloader_esp_idf::esp_app_desc!();
|
esp_bootloader_esp_idf::esp_app_desc!();
|
||||||
|
|
||||||
// Memory allocation regions.
|
|
||||||
// These can be debugged using `xtensa-esp32s3-elf-size -A <path-to-binary>`.
|
|
||||||
// A panic such as `memory allocation of 3740121773 bytes failed` is caused by a heap overflow. The size is `DEEDBAAD` in hex.
|
|
||||||
|
|
||||||
/// Total heap size
|
|
||||||
const HEAP_SIZE: usize = 112 * 1024;
|
|
||||||
/// Size of the app core's stack
|
|
||||||
const STACK_SIZE_CORE_APP: usize = 80 * 1024;
|
|
||||||
|
|
||||||
// const FRAME_DURATION_MIN: Duration = Duration::from_millis(40); // 25 FPS
|
// const FRAME_DURATION_MIN: Duration = Duration::from_millis(40); // 25 FPS
|
||||||
const FRAME_DURATION_MIN: Duration = Duration::from_millis(100); // 10 FPS
|
const FRAME_DURATION_MIN: Duration = Duration::from_millis(100); // 10 FPS
|
||||||
|
|
||||||
pub static PSRAM_ALLOCATOR: esp_alloc::EspHeap = esp_alloc::EspHeap::empty();
|
|
||||||
|
|
||||||
static KEYBOARD_REPORT_PROXY: Channel<CriticalSectionRawMutex, Report, 16> = Channel::new();
|
static KEYBOARD_REPORT_PROXY: Channel<CriticalSectionRawMutex, Report, 16> = Channel::new();
|
||||||
static LCD_ENABLED: AtomicBool = AtomicBool::new(false);
|
static LCD_ENABLED: AtomicBool = AtomicBool::new(false);
|
||||||
|
|
||||||
// /// Used to signal that MCU is ready to submit the framebuffer to the LCD.
|
|
||||||
// static SIGNAL_LCD_SUBMIT: Signal<CriticalSectionRawMutex, ()> = Signal::new();
|
|
||||||
|
|
||||||
// /// Used to signal that the MCU is ready to render the GUI.
|
|
||||||
// static SIGNAL_UI_RENDER: Signal<CriticalSectionRawMutex, ()> = Signal::new();
|
|
||||||
|
|
||||||
#[embassy_executor::task]
|
|
||||||
async fn test_bounce_buffers_task(
|
|
||||||
channel: DMA_CH0<'static>,
|
|
||||||
peripheral: SPI2<'static>,
|
|
||||||
st7701s: St7701s<'static, Blocking>,
|
|
||||||
) {
|
|
||||||
test_bounce_buffers(channel, peripheral, st7701s).await;
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn test_bounce_buffers(
|
|
||||||
channel: DMA_CH0<'static>,
|
|
||||||
peripheral: SPI2<'static>,
|
|
||||||
st7701s: St7701s<'static, Blocking>,
|
|
||||||
) {
|
|
||||||
error!("TEST BOUNCE BUFFERS SECTION ENTERED");
|
|
||||||
const BYTES_PER_PIXEL: usize = core::mem::size_of::<u16>();
|
|
||||||
// Assume highest burst config setting.
|
|
||||||
const EXTERNAL_BURST_CONFIG: ExternalBurstConfig = ExternalBurstConfig::Size32;
|
|
||||||
const ALIGNMENT_PIXELS: usize = EXTERNAL_BURST_CONFIG as usize / BYTES_PER_PIXEL;
|
|
||||||
// The total number of pixels demanded by the DPI, per row.
|
|
||||||
const WIDTH_TOTAL_PIXELS: usize = 368;
|
|
||||||
// The total number of rows demanded by the DPI, per frame.
|
|
||||||
const HEIGHT_PIXELS: usize = 960;
|
|
||||||
// The number of unused pixels at the start of the row.
|
|
||||||
const FRONT_PORCH_ACTUAL_PIXELS: usize = 120;
|
|
||||||
// The number of actually visible pixels, per row.
|
|
||||||
const WIDTH_VISIBLE_PIXELS: usize = 240;
|
|
||||||
// The number of pixels not stored in a bounce buffer, per row.
|
|
||||||
// This many arbitrary pixels are sent to the DPI.
|
|
||||||
const FRONT_PORCH_SKIPPED_PIXELS: usize =
|
|
||||||
(FRONT_PORCH_ACTUAL_PIXELS / ALIGNMENT_PIXELS) * ALIGNMENT_PIXELS;
|
|
||||||
const WIDTH_STORED_PIXELS: usize = WIDTH_TOTAL_PIXELS - FRONT_PORCH_SKIPPED_PIXELS;
|
|
||||||
const VISIBLE_OFFSET_IN_BUFFER_PIXELS: usize =
|
|
||||||
FRONT_PORCH_ACTUAL_PIXELS - FRONT_PORCH_SKIPPED_PIXELS;
|
|
||||||
const ROWS_PER_WINDOW: usize = 16;
|
|
||||||
let burst_config = BurstConfig {
|
|
||||||
internal_memory: InternalBurstConfig::Enabled,
|
|
||||||
external_memory: EXTERNAL_BURST_CONFIG,
|
|
||||||
};
|
|
||||||
let (swapchain_reader, mut swapchain_writer) = Swapchain {
|
|
||||||
framebuffers: [
|
|
||||||
Box::leak(allocate_dma_buffer_in(
|
|
||||||
HEIGHT_PIXELS * WIDTH_STORED_PIXELS * BYTES_PER_PIXEL,
|
|
||||||
burst_config,
|
|
||||||
&PSRAM_ALLOCATOR,
|
|
||||||
)),
|
|
||||||
Box::leak(allocate_dma_buffer_in(
|
|
||||||
HEIGHT_PIXELS * WIDTH_STORED_PIXELS * BYTES_PER_PIXEL,
|
|
||||||
burst_config,
|
|
||||||
&PSRAM_ALLOCATOR,
|
|
||||||
)),
|
|
||||||
],
|
|
||||||
}
|
|
||||||
.into_reader_writer();
|
|
||||||
|
|
||||||
{
|
|
||||||
let write_guard = &mut swapchain_writer.write();
|
|
||||||
let buffer_src = write_guard.cast::<Rgb565Pixel>();
|
|
||||||
let colors = (0..WIDTH_VISIBLE_PIXELS as u8 / 2)
|
|
||||||
.rev()
|
|
||||||
.map(|val| Rgb565Pixel::from_rgb(0xFF, val * 2, 0))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
for (index, pixel) in buffer_src.iter_mut().enumerate() {
|
|
||||||
let mut x =
|
|
||||||
(index % WIDTH_STORED_PIXELS) as i16 - VISIBLE_OFFSET_IN_BUFFER_PIXELS as i16;
|
|
||||||
let mut y = (index / WIDTH_STORED_PIXELS) as i16;
|
|
||||||
|
|
||||||
if x < WIDTH_VISIBLE_PIXELS as i16 {
|
|
||||||
x = core::cmp::min(x, WIDTH_VISIBLE_PIXELS as i16 - 1 - x);
|
|
||||||
y = core::cmp::min(y, HEIGHT_PIXELS as i16 - 1 - y);
|
|
||||||
let min = core::cmp::min(x, y);
|
|
||||||
|
|
||||||
*pixel = colors[min as usize % colors.len()].clone();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
*pixel = Rgb565Pixel::default();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
warn!("FRONT_PORCH_SKIPPED_PIXELS: {FRONT_PORCH_SKIPPED_PIXELS}");
|
|
||||||
warn!("WIDTH_STORED_PIXELS: {WIDTH_STORED_PIXELS}");
|
|
||||||
warn!("ROWS_PER_WINDOW: {ROWS_PER_WINDOW}");
|
|
||||||
|
|
||||||
let buf = DmaBounce::new(
|
|
||||||
Global,
|
|
||||||
channel,
|
|
||||||
AnySpi::from(peripheral),
|
|
||||||
st7701s.dpi,
|
|
||||||
swapchain_reader,
|
|
||||||
FRONT_PORCH_SKIPPED_PIXELS * BYTES_PER_PIXEL,
|
|
||||||
WIDTH_STORED_PIXELS * BYTES_PER_PIXEL,
|
|
||||||
ROWS_PER_WINDOW,
|
|
||||||
burst_config,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
buf.launch_interrupt_driven_task().await;
|
|
||||||
error!("TEST BOUNCE BUFFERS SECTION DONE");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[esp_rtos::main]
|
#[esp_rtos::main]
|
||||||
async fn main(_spawner: Spawner) {
|
async fn main(_spawner: Spawner) {
|
||||||
let config = esp_hal::Config::default()
|
let config = esp_hal::Config::default()
|
||||||
|
|
@ -256,7 +121,7 @@ async fn main(_spawner: Spawner) {
|
||||||
#[cfg(feature = "alt-log")]
|
#[cfg(feature = "alt-log")]
|
||||||
let (tx, rx) = (peripherals.GPIO12, peripherals.GPIO5);
|
let (tx, rx) = (peripherals.GPIO12, peripherals.GPIO5);
|
||||||
#[cfg(not(feature = "alt-log"))]
|
#[cfg(not(feature = "alt-log"))]
|
||||||
let (tx, rx) = (NoPin, NoPin);
|
let (tx, rx) = (esp_hal::gpio::NoPin, esp_hal::gpio::NoPin);
|
||||||
|
|
||||||
Uart::new(peripherals.UART2, Default::default())
|
Uart::new(peripherals.UART2, Default::default())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|
@ -272,32 +137,8 @@ async fn main(_spawner: Spawner) {
|
||||||
#[cfg(feature = "rtt-log")]
|
#[cfg(feature = "rtt-log")]
|
||||||
logging::rtt::setup_logging();
|
logging::rtt::setup_logging();
|
||||||
|
|
||||||
// Use the internal DRAM as the heap.
|
// Set up allocators.
|
||||||
// Memory reclaimed from the esp-idf bootloader.
|
ram::initialize(peripherals.PSRAM);
|
||||||
const HEAP_SIZE_RECLAIMED: usize = const {
|
|
||||||
let range = esp_metadata_generated::memory_range!("DRAM2_UNINIT");
|
|
||||||
range.end - range.start
|
|
||||||
};
|
|
||||||
|
|
||||||
esp_alloc::heap_allocator!(#[ram(reclaimed)] size: HEAP_SIZE_RECLAIMED);
|
|
||||||
esp_alloc::heap_allocator!(size: HEAP_SIZE - HEAP_SIZE_RECLAIMED);
|
|
||||||
info!("Heap initialized! {:#?}", esp_alloc::HEAP.stats());
|
|
||||||
|
|
||||||
// Initialize the PSRAM allocator.
|
|
||||||
{
|
|
||||||
let (psram_offset, psram_size) = esp_hal::psram::psram_raw_parts(&peripherals.PSRAM);
|
|
||||||
unsafe {
|
|
||||||
PSRAM_ALLOCATOR.add_region(HeapRegion::new(
|
|
||||||
psram_offset,
|
|
||||||
psram_size,
|
|
||||||
MemoryCapability::External.into(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
info!(
|
|
||||||
"PSRAM allocator initialized with capacity of {} MiB!",
|
|
||||||
psram_size / 1024 / 1024
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// let mut io = Io::new(peripherals.IO_MUX);
|
// let mut io = Io::new(peripherals.IO_MUX);
|
||||||
// io.set_interrupt_handler(interrupt_handler);
|
// io.set_interrupt_handler(interrupt_handler);
|
||||||
|
|
@ -317,16 +158,15 @@ async fn main(_spawner: Spawner) {
|
||||||
// Enable antenna
|
// Enable antenna
|
||||||
let _ = Output::new(peripherals.GPIO11, Level::Low, OutputConfig::default());
|
let _ = Output::new(peripherals.GPIO11, Level::Low, OutputConfig::default());
|
||||||
|
|
||||||
// TODO: Use PWM to control the pwm_pin.
|
|
||||||
let mut _pwm = McPwm::new(peripherals.MCPWM0, PeripheralClockConfig::with_prescaler(1));
|
|
||||||
let mut _pwm_pin = Output::new(peripherals.GPIO21, Level::High, OutputConfig::default());
|
|
||||||
|
|
||||||
let mut sha_backend = ShaBackend::new(peripherals.SHA);
|
let mut sha_backend = ShaBackend::new(peripherals.SHA);
|
||||||
let _sha_driver_handle = sha_backend.start();
|
let _sha_driver_handle = sha_backend.start();
|
||||||
|
|
||||||
let timg0 = TimerGroup::new(peripherals.TIMG0);
|
let timg0 = TimerGroup::new(peripherals.TIMG0);
|
||||||
let software_interrupt = SoftwareInterruptControl::new(peripherals.SW_INTERRUPT);
|
let software_interrupt = SoftwareInterruptControl::new(peripherals.SW_INTERRUPT);
|
||||||
esp_rtos::start(timg0.timer0, software_interrupt.software_interrupt0);
|
esp_rtos::start(
|
||||||
|
timg0.timer0,
|
||||||
|
// software_interrupt.software_interrupt0,
|
||||||
|
);
|
||||||
|
|
||||||
// A task executor that is able to handle interrupts, and then return back to executing tasks.
|
// A task executor that is able to handle interrupts, and then return back to executing tasks.
|
||||||
static EXECUTOR_CORE_0: StaticCell<InterruptExecutor<2>> = StaticCell::new();
|
static EXECUTOR_CORE_0: StaticCell<InterruptExecutor<2>> = StaticCell::new();
|
||||||
|
|
@ -345,46 +185,53 @@ async fn main(_spawner: Spawner) {
|
||||||
// high_priority_task_spawner: interrupt_core_1_spawner,
|
// high_priority_task_spawner: interrupt_core_1_spawner,
|
||||||
uart_rx,
|
uart_rx,
|
||||||
software_interrupt1: software_interrupt.software_interrupt1,
|
software_interrupt1: software_interrupt.software_interrupt1,
|
||||||
|
software_interrupt0: software_interrupt.software_interrupt0,
|
||||||
RNG: peripherals.RNG,
|
RNG: peripherals.RNG,
|
||||||
ADC1: peripherals.ADC1,
|
ADC1: peripherals.ADC1,
|
||||||
USB0: peripherals.USB0,
|
USB0: peripherals.USB0,
|
||||||
FLASH: peripherals.FLASH,
|
FLASH: peripherals.FLASH,
|
||||||
LCD_CAM: peripherals.LCD_CAM,
|
|
||||||
DMA_CH0: peripherals.DMA_CH0,
|
DMA_CH0: peripherals.DMA_CH0,
|
||||||
DMA_CH2: peripherals.DMA_CH2,
|
|
||||||
I2C0: peripherals.I2C0,
|
|
||||||
SPI2: peripherals.SPI2,
|
SPI2: peripherals.SPI2,
|
||||||
CPU_CTRL: peripherals.CPU_CTRL,
|
CPU_CTRL: peripherals.CPU_CTRL,
|
||||||
GPIO0: gpio0,
|
|
||||||
GPIO1: peripherals.GPIO1,
|
|
||||||
GPIO2: peripherals.GPIO2,
|
|
||||||
GPIO3: peripherals.GPIO3,
|
|
||||||
GPIO4: peripherals.GPIO4,
|
|
||||||
#[cfg(not(feature = "alt-log"))]
|
|
||||||
GPIO5: peripherals.GPIO5,
|
|
||||||
GPIO6: peripherals.GPIO6,
|
|
||||||
GPIO7: peripherals.GPIO7,
|
|
||||||
GPIO8: peripherals.GPIO8,
|
|
||||||
GPIO9: peripherals.GPIO9,
|
|
||||||
#[cfg(not(feature = "alt-log"))]
|
|
||||||
GPIO12: peripherals.GPIO12,
|
|
||||||
GPIO13: peripherals.GPIO13,
|
|
||||||
GPIO14: peripherals.GPIO14,
|
|
||||||
GPIO15: peripherals.GPIO15,
|
|
||||||
GPIO16: peripherals.GPIO16,
|
|
||||||
GPIO19: peripherals.GPIO19,
|
GPIO19: peripherals.GPIO19,
|
||||||
GPIO20: peripherals.GPIO20,
|
GPIO20: peripherals.GPIO20,
|
||||||
GPIO34: peripherals.GPIO34,
|
display: DisplayPeripherals {
|
||||||
GPIO35: peripherals.GPIO35,
|
DMA_CH2: peripherals.DMA_CH2,
|
||||||
GPIO36: peripherals.GPIO36,
|
LCD_CAM: peripherals.LCD_CAM,
|
||||||
GPIO37: peripherals.GPIO37,
|
LEDC: peripherals.LEDC,
|
||||||
GPIO38: peripherals.GPIO38,
|
GPIO0: gpio0,
|
||||||
GPIO39: peripherals.GPIO39,
|
GPIO1: peripherals.GPIO1,
|
||||||
GPIO40: peripherals.GPIO40,
|
GPIO2: peripherals.GPIO2,
|
||||||
GPIO41: peripherals.GPIO41,
|
GPIO3: peripherals.GPIO3,
|
||||||
GPIO42: peripherals.GPIO42,
|
GPIO4: peripherals.GPIO4,
|
||||||
GPIO43: peripherals.GPIO43,
|
#[cfg(not(feature = "alt-log"))]
|
||||||
GPIO44: peripherals.GPIO44,
|
GPIO5: peripherals.GPIO5,
|
||||||
|
GPIO6: peripherals.GPIO6,
|
||||||
|
#[cfg(not(feature = "alt-log"))]
|
||||||
|
GPIO12: peripherals.GPIO12,
|
||||||
|
GPIO13: peripherals.GPIO13,
|
||||||
|
GPIO14: peripherals.GPIO14,
|
||||||
|
GPIO15: peripherals.GPIO15,
|
||||||
|
GPIO16: peripherals.GPIO16,
|
||||||
|
GPIO21: peripherals.GPIO21,
|
||||||
|
GPIO34: peripherals.GPIO34,
|
||||||
|
GPIO35: peripherals.GPIO35,
|
||||||
|
GPIO36: peripherals.GPIO36,
|
||||||
|
GPIO37: peripherals.GPIO37,
|
||||||
|
GPIO38: peripherals.GPIO38,
|
||||||
|
GPIO39: peripherals.GPIO39,
|
||||||
|
GPIO40: peripherals.GPIO40,
|
||||||
|
GPIO41: peripherals.GPIO41,
|
||||||
|
GPIO42: peripherals.GPIO42,
|
||||||
|
GPIO43: peripherals.GPIO43,
|
||||||
|
GPIO44: peripherals.GPIO44,
|
||||||
|
},
|
||||||
|
matrix: MatrixPeripherals {
|
||||||
|
I2C0: peripherals.I2C0,
|
||||||
|
GPIO7: peripherals.GPIO7,
|
||||||
|
GPIO8: peripherals.GPIO8,
|
||||||
|
GPIO9: peripherals.GPIO9,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
interrupt_core_0_spawner.must_spawn(main_task(main_task_peripherals));
|
interrupt_core_0_spawner.must_spawn(main_task(main_task_peripherals));
|
||||||
|
|
@ -393,56 +240,35 @@ async fn main(_spawner: Spawner) {
|
||||||
/// Peripherals passed to the main task.
|
/// Peripherals passed to the main task.
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
struct MainPeripherals {
|
struct MainPeripherals {
|
||||||
// high_priority_task_spawner: SendSpawner,
|
|
||||||
uart_rx: UartRx<'static, Blocking>,
|
uart_rx: UartRx<'static, Blocking>,
|
||||||
software_interrupt1: SoftwareInterrupt<'static, 1>,
|
software_interrupt1: SoftwareInterrupt<'static, 1>,
|
||||||
|
software_interrupt0: SoftwareInterrupt<'static, 0>,
|
||||||
RNG: esp_hal::peripherals::RNG<'static>,
|
RNG: esp_hal::peripherals::RNG<'static>,
|
||||||
ADC1: esp_hal::peripherals::ADC1<'static>,
|
ADC1: esp_hal::peripherals::ADC1<'static>,
|
||||||
USB0: esp_hal::peripherals::USB0<'static>,
|
USB0: esp_hal::peripherals::USB0<'static>,
|
||||||
FLASH: esp_hal::peripherals::FLASH<'static>,
|
FLASH: esp_hal::peripherals::FLASH<'static>,
|
||||||
LCD_CAM: esp_hal::peripherals::LCD_CAM<'static>,
|
|
||||||
DMA_CH0: esp_hal::peripherals::DMA_CH0<'static>,
|
DMA_CH0: esp_hal::peripherals::DMA_CH0<'static>,
|
||||||
DMA_CH2: esp_hal::peripherals::DMA_CH2<'static>,
|
|
||||||
I2C0: esp_hal::peripherals::I2C0<'static>,
|
|
||||||
SPI2: esp_hal::peripherals::SPI2<'static>,
|
SPI2: esp_hal::peripherals::SPI2<'static>,
|
||||||
CPU_CTRL: esp_hal::peripherals::CPU_CTRL<'static>,
|
CPU_CTRL: esp_hal::peripherals::CPU_CTRL<'static>,
|
||||||
GPIO0: Output<'static>,
|
|
||||||
GPIO1: esp_hal::peripherals::GPIO1<'static>,
|
|
||||||
GPIO2: esp_hal::peripherals::GPIO2<'static>,
|
|
||||||
GPIO3: esp_hal::peripherals::GPIO3<'static>,
|
|
||||||
GPIO4: esp_hal::peripherals::GPIO4<'static>,
|
|
||||||
#[cfg(not(feature = "alt-log"))]
|
|
||||||
GPIO5: esp_hal::peripherals::GPIO5<'static>,
|
|
||||||
GPIO6: esp_hal::peripherals::GPIO6<'static>,
|
|
||||||
GPIO7: esp_hal::peripherals::GPIO7<'static>,
|
|
||||||
GPIO8: esp_hal::peripherals::GPIO8<'static>,
|
|
||||||
GPIO9: esp_hal::peripherals::GPIO9<'static>,
|
|
||||||
// GPIO10: esp_hal::peripherals::GPIO10<'static>,
|
// GPIO10: esp_hal::peripherals::GPIO10<'static>,
|
||||||
#[cfg(not(feature = "alt-log"))]
|
|
||||||
GPIO12: esp_hal::peripherals::GPIO12<'static>,
|
|
||||||
GPIO13: esp_hal::peripherals::GPIO13<'static>,
|
|
||||||
GPIO14: esp_hal::peripherals::GPIO14<'static>,
|
|
||||||
GPIO15: esp_hal::peripherals::GPIO15<'static>,
|
|
||||||
GPIO16: esp_hal::peripherals::GPIO16<'static>,
|
|
||||||
// GPIO18: esp_hal::peripherals::GPIO18<'static>,
|
// GPIO18: esp_hal::peripherals::GPIO18<'static>,
|
||||||
GPIO19: esp_hal::peripherals::GPIO19<'static>,
|
GPIO19: esp_hal::peripherals::GPIO19<'static>,
|
||||||
GPIO20: esp_hal::peripherals::GPIO20<'static>,
|
GPIO20: esp_hal::peripherals::GPIO20<'static>,
|
||||||
// GPIO33: esp_hal::peripherals::GPIO33<'static>,
|
// GPIO33: esp_hal::peripherals::GPIO33<'static>,
|
||||||
GPIO34: esp_hal::peripherals::GPIO34<'static>,
|
|
||||||
GPIO35: esp_hal::peripherals::GPIO35<'static>,
|
|
||||||
GPIO36: esp_hal::peripherals::GPIO36<'static>,
|
|
||||||
GPIO37: esp_hal::peripherals::GPIO37<'static>,
|
|
||||||
GPIO38: esp_hal::peripherals::GPIO38<'static>,
|
|
||||||
GPIO39: esp_hal::peripherals::GPIO39<'static>,
|
|
||||||
GPIO40: esp_hal::peripherals::GPIO40<'static>,
|
|
||||||
GPIO41: esp_hal::peripherals::GPIO41<'static>,
|
|
||||||
GPIO42: esp_hal::peripherals::GPIO42<'static>,
|
|
||||||
GPIO43: esp_hal::peripherals::GPIO43<'static>,
|
|
||||||
GPIO44: esp_hal::peripherals::GPIO44<'static>,
|
|
||||||
// GPIO45: esp_hal::peripherals::GPIO45<'static>,
|
// GPIO45: esp_hal::peripherals::GPIO45<'static>,
|
||||||
// GPIO46: esp_hal::peripherals::GPIO46<'static>,
|
// GPIO46: esp_hal::peripherals::GPIO46<'static>,
|
||||||
// GPIO47: esp_hal::peripherals::GPIO47<'static>,
|
// GPIO47: esp_hal::peripherals::GPIO47<'static>,
|
||||||
// GPIO48: esp_hal::peripherals::GPIO48<'static>,
|
// GPIO48: esp_hal::peripherals::GPIO48<'static>,
|
||||||
|
display: DisplayPeripherals,
|
||||||
|
matrix: MatrixPeripherals,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
struct MatrixPeripherals {
|
||||||
|
I2C0: esp_hal::peripherals::I2C0<'static>,
|
||||||
|
GPIO7: esp_hal::peripherals::GPIO7<'static>,
|
||||||
|
GPIO8: esp_hal::peripherals::GPIO8<'static>,
|
||||||
|
GPIO9: esp_hal::peripherals::GPIO9<'static>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
|
|
@ -494,133 +320,12 @@ async fn main_task(peripherals: MainPeripherals) {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Initialize the flash
|
// Initialize the flash
|
||||||
static PARTITION_TABLE_BUFFER: StaticCell<Vec<u8, &'static esp_alloc::EspHeap>> =
|
let flash_partitions = flash::initialize(peripherals.FLASH);
|
||||||
StaticCell::new();
|
|
||||||
let partition_table_buffer = PARTITION_TABLE_BUFFER.init_with(|| {
|
|
||||||
let mut buffer = Vec::<u8, _>::new_in(&PSRAM_ALLOCATOR);
|
|
||||||
buffer.resize(1024, 0_u8);
|
|
||||||
buffer
|
|
||||||
});
|
|
||||||
|
|
||||||
static FLASH: StaticCell<(
|
|
||||||
Mutex<CriticalSectionRawMutex, BlockingAsync<FlashStorage>>,
|
|
||||||
PartitionTable<'static>,
|
|
||||||
)> = StaticCell::new();
|
|
||||||
let (flash, partition_table) = FLASH.init_with(|| {
|
|
||||||
let mut flash = FlashStorage::new(peripherals.FLASH)
|
|
||||||
// Flash memory may not be written to while another core is executing from it.
|
|
||||||
// By default, `FlashStorage` is configured to abort the operation and log an error message.
|
|
||||||
// However, it can also be configured to auto-park the other core, such that writing to
|
|
||||||
// flash succeeds.
|
|
||||||
// Alternatively, XiP from PSRAM could be used along with the `multicore_ignore` strategy,
|
|
||||||
// to avoid having to park the other core, which could result in better performance.
|
|
||||||
// Invalid configuration would then present itself as freezing/UB.
|
|
||||||
.multicore_auto_park();
|
|
||||||
let partition_table = {
|
|
||||||
esp_bootloader_esp_idf::partitions::read_partition_table(
|
|
||||||
&mut flash,
|
|
||||||
partition_table_buffer,
|
|
||||||
)
|
|
||||||
.expect("Failed to read the partition table.")
|
|
||||||
};
|
|
||||||
|
|
||||||
(
|
|
||||||
Mutex::<CriticalSectionRawMutex, _>::new(async_flash_wrapper(flash)),
|
|
||||||
partition_table,
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
{
|
|
||||||
let mut buffer = String::new();
|
|
||||||
|
|
||||||
writeln!(buffer, "Partition table:").unwrap();
|
|
||||||
|
|
||||||
for (index, partition) in partition_table.iter().enumerate() {
|
|
||||||
writedoc!(
|
|
||||||
buffer,
|
|
||||||
"
|
|
||||||
Partition #{index} {label:?}:
|
|
||||||
offset: 0x{offset:x}
|
|
||||||
length: 0x{len:x}
|
|
||||||
type: 0x{type:?}
|
|
||||||
read only: {read_only}
|
|
||||||
encrypted: {encrypted}
|
|
||||||
magic: {magic}
|
|
||||||
",
|
|
||||||
label = partition.label_as_str(),
|
|
||||||
offset = partition.offset(),
|
|
||||||
len = partition.len(),
|
|
||||||
type = partition.partition_type(),
|
|
||||||
read_only = partition.is_read_only(),
|
|
||||||
encrypted = partition.is_encrypted(),
|
|
||||||
magic = partition.magic(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
info!("{}", buffer);
|
|
||||||
}
|
|
||||||
let flash_part_info_rmk = partition_table
|
|
||||||
.iter()
|
|
||||||
.find(|partition| partition.label_as_str() == "rmk")
|
|
||||||
.expect("No \"rmk\" partition found. Make sure to use the custom partition-table.csv when flashing.");
|
|
||||||
let flash_part_info_acid = partition_table
|
|
||||||
.iter()
|
|
||||||
.find(|partition| partition.label_as_str() == "acid")
|
|
||||||
.expect("No \"acid\" partition found. Make sure to use the custom partition-table.csv when flashing.");
|
|
||||||
let flash_part_rmk = Partition::new(
|
|
||||||
flash,
|
|
||||||
flash_part_info_rmk.offset(),
|
|
||||||
flash_part_info_rmk.len(),
|
|
||||||
);
|
|
||||||
let flash_part_acid = Partition::new(
|
|
||||||
flash,
|
|
||||||
flash_part_info_acid.offset(),
|
|
||||||
flash_part_info_acid.len(),
|
|
||||||
);
|
|
||||||
|
|
||||||
info!("Flash memory configured!");
|
info!("Flash memory configured!");
|
||||||
|
|
||||||
let sck = Output::new(peripherals.GPIO36, Level::High, OutputConfig::default());
|
// Uncomment this to run bounce buffer test code instead.
|
||||||
let mosi = Flex::new(peripherals.GPIO35);
|
// dpi::test_bounce_buffers(peripherals.DMA_CH0, peripherals.SPI2, peripherals.display).await;
|
||||||
let cs = Output::new(peripherals.GPIO6, Level::High, OutputConfig::default());
|
|
||||||
|
|
||||||
let lcd = LcdCam::new(peripherals.LCD_CAM).lcd;
|
|
||||||
let unconfigured_dpi = Dpi::new(lcd, peripherals.DMA_CH2, Default::default())
|
|
||||||
.unwrap()
|
|
||||||
.with_de(peripherals.GPIO37)
|
|
||||||
.with_pclk(peripherals.GPIO34)
|
|
||||||
.with_hsync(peripherals.GPIO44)
|
|
||||||
.with_vsync(peripherals.GPIO43)
|
|
||||||
// Blue
|
|
||||||
.with_data0(peripherals.GPIO38)
|
|
||||||
.with_data1(peripherals.GPIO39)
|
|
||||||
.with_data2(peripherals.GPIO40)
|
|
||||||
.with_data3(peripherals.GPIO41)
|
|
||||||
.with_data4(peripherals.GPIO42)
|
|
||||||
// Green
|
|
||||||
.with_data7(peripherals.GPIO13)
|
|
||||||
.with_data8(peripherals.GPIO14)
|
|
||||||
.with_data9(peripherals.GPIO15)
|
|
||||||
.with_data10(peripherals.GPIO16)
|
|
||||||
// Red
|
|
||||||
.with_data11(peripherals.GPIO0)
|
|
||||||
.with_data12(peripherals.GPIO1)
|
|
||||||
.with_data13(peripherals.GPIO2)
|
|
||||||
.with_data14(peripherals.GPIO3)
|
|
||||||
.with_data15(peripherals.GPIO4);
|
|
||||||
|
|
||||||
#[cfg(not(feature = "alt-log"))]
|
|
||||||
let unconfigured_dpi = unconfigured_dpi
|
|
||||||
// Green
|
|
||||||
.with_data5(peripherals.GPIO5)
|
|
||||||
.with_data6(peripherals.GPIO12);
|
|
||||||
|
|
||||||
let st7701s = St7701s::new(sck, mosi, cs, unconfigured_dpi).await;
|
|
||||||
|
|
||||||
info!("ST7701S-based LCD display initialized!");
|
|
||||||
|
|
||||||
// test_bounce_buffers(peripherals.DMA_CH0, peripherals.SPI2, st7701s).await;
|
|
||||||
// return;
|
// return;
|
||||||
|
|
||||||
// RMK config
|
// RMK config
|
||||||
|
|
@ -629,12 +334,12 @@ async fn main_task(peripherals: MainPeripherals) {
|
||||||
start_addr: 0,
|
start_addr: 0,
|
||||||
num_sectors: {
|
num_sectors: {
|
||||||
assert!(
|
assert!(
|
||||||
flash_part_info_rmk.len() % FlashStorage::SECTOR_SIZE == 0,
|
flash_partitions.rmk.size() % FlashStorage::SECTOR_SIZE == 0,
|
||||||
"The size of the RMK partition must be a multiple of {} bytes. Current size: {}",
|
"The size of the RMK partition must be a multiple of {} bytes. Current size: {}",
|
||||||
FlashStorage::SECTOR_SIZE,
|
FlashStorage::SECTOR_SIZE,
|
||||||
flash_part_info_rmk.len()
|
flash_partitions.rmk.size()
|
||||||
);
|
);
|
||||||
(flash_part_info_rmk.len() / FlashStorage::SECTOR_SIZE) as u8
|
(flash_partitions.rmk.size() / FlashStorage::SECTOR_SIZE) as u8
|
||||||
},
|
},
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
@ -671,7 +376,7 @@ async fn main_task(peripherals: MainPeripherals) {
|
||||||
let mut positional_config = config::get_positional_config();
|
let mut positional_config = config::get_positional_config();
|
||||||
let (keymap, mut storage) = initialize_keymap_and_storage(
|
let (keymap, mut storage) = initialize_keymap_and_storage(
|
||||||
&mut default_keymap,
|
&mut default_keymap,
|
||||||
flash_part_rmk,
|
flash_partitions.rmk,
|
||||||
&storage_config,
|
&storage_config,
|
||||||
&mut behavior_config,
|
&mut behavior_config,
|
||||||
&mut positional_config,
|
&mut positional_config,
|
||||||
|
|
@ -680,17 +385,50 @@ async fn main_task(peripherals: MainPeripherals) {
|
||||||
|
|
||||||
info!("Initialized keymap and storage for RMK!");
|
info!("Initialized keymap and storage for RMK!");
|
||||||
|
|
||||||
|
let mut keyboard = Keyboard::new(&keymap); // Initialize the light controller
|
||||||
|
|
||||||
|
info!("Keyboard initialized!");
|
||||||
|
info!("Awaiting on all tasks...");
|
||||||
|
|
||||||
|
// TODO: Probably want to select! instead and re-try.
|
||||||
|
join_all![
|
||||||
|
ram::run_alloc_stats_reporter(),
|
||||||
|
initialize_and_run_rmk_devices(peripherals.matrix),
|
||||||
|
keyboard.run(), // Keyboard is special
|
||||||
|
run_rmk(
|
||||||
|
&keymap,
|
||||||
|
#[cfg(not(feature = "no-usb"))]
|
||||||
|
usb_driver,
|
||||||
|
#[cfg(feature = "ble")]
|
||||||
|
&stack,
|
||||||
|
&mut storage,
|
||||||
|
rmk_config,
|
||||||
|
),
|
||||||
|
create_hid_report_interceptor(),
|
||||||
|
initialize_display_and_renderer(
|
||||||
|
peripherals.display,
|
||||||
|
peripherals.DMA_CH0,
|
||||||
|
peripherals.SPI2,
|
||||||
|
peripherals.CPU_CTRL,
|
||||||
|
peripherals.software_interrupt0,
|
||||||
|
peripherals.software_interrupt1,
|
||||||
|
flash_partitions.acid
|
||||||
|
),
|
||||||
|
console::run_console(peripherals.uart_rx.into_async())
|
||||||
|
]
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn initialize_and_run_rmk_devices(matrix_peripherals: MatrixPeripherals) {
|
||||||
// Initialize the matrix and keyboard
|
// Initialize the matrix and keyboard
|
||||||
const I2C_ADDR_MATRIX_LEFT: I2cAddress = I2cAddress::SevenBit(0b0100000);
|
const I2C_ADDR_MATRIX_LEFT: I2cAddress = I2cAddress::SevenBit(0b0100000);
|
||||||
const I2C_ADDR_MATRIX_RIGHT: I2cAddress = I2cAddress::SevenBit(0b0100001);
|
const I2C_ADDR_MATRIX_RIGHT: I2cAddress = I2cAddress::SevenBit(0b0100001);
|
||||||
|
|
||||||
let i2c = I2c::new(peripherals.I2C0, Default::default())
|
let i2c = I2c::new(matrix_peripherals.I2C0, Default::default())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.with_sda(peripherals.GPIO8)
|
.with_sda(matrix_peripherals.GPIO8)
|
||||||
.with_scl(peripherals.GPIO9);
|
.with_scl(matrix_peripherals.GPIO9);
|
||||||
|
let matrix_interrupt_low = Input::new(matrix_peripherals.GPIO7, InputConfig::default());
|
||||||
let matrix_interrupt_low = Input::new(peripherals.GPIO7, InputConfig::default());
|
|
||||||
|
|
||||||
let mut matrix = IoeMatrix::new(
|
let mut matrix = IoeMatrix::new(
|
||||||
matrix_interrupt_low,
|
matrix_interrupt_low,
|
||||||
i2c.into_async(),
|
i2c.into_async(),
|
||||||
|
|
@ -698,49 +436,64 @@ async fn main_task(peripherals: MainPeripherals) {
|
||||||
[I2C_ADDR_MATRIX_LEFT, I2C_ADDR_MATRIX_RIGHT],
|
[I2C_ADDR_MATRIX_LEFT, I2C_ADDR_MATRIX_RIGHT],
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
let mut keyboard = Keyboard::new(&keymap); // Initialize the light controller
|
run_devices! (
|
||||||
|
(matrix) => rmk::channel::EVENT_CHANNEL,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
info!("Keyboard initialized!");
|
async fn initialize_display_and_renderer(
|
||||||
|
display_peripherals: DisplayPeripherals,
|
||||||
|
dma_ch0: esp_hal::peripherals::DMA_CH0<'static>,
|
||||||
|
spi2: esp_hal::peripherals::SPI2<'static>,
|
||||||
|
cpu_ctrl: esp_hal::peripherals::CPU_CTRL<'static>,
|
||||||
|
software_interrupt0: SoftwareInterrupt<'static, 0>,
|
||||||
|
software_interrupt1: SoftwareInterrupt<'static, 1>,
|
||||||
|
partition_acid: Partition,
|
||||||
|
) {
|
||||||
|
let st7701s = display_peripherals.into_display().await;
|
||||||
|
|
||||||
static FRAMEBUFFER: StaticCell<Framebuffer> = StaticCell::new();
|
static FRAMEBUFFER: StaticCell<Framebuffer> = StaticCell::new();
|
||||||
let framebuffer = FRAMEBUFFER.init(Framebuffer::new(
|
let framebuffer = FRAMEBUFFER.init_with(move || {
|
||||||
peripherals.DMA_CH0,
|
Framebuffer::new(
|
||||||
peripherals.SPI2.into(),
|
dma_ch0,
|
||||||
st7701s.dpi,
|
spi2.into(),
|
||||||
BurstConfig {
|
st7701s.dpi,
|
||||||
internal_memory: InternalBurstConfig::Enabled,
|
BurstConfig {
|
||||||
external_memory: ExternalBurstConfig::Size32,
|
internal_memory: InternalBurstConfig::Enabled,
|
||||||
},
|
external_memory: ExternalBurstConfig::Size32,
|
||||||
// The burst config (16/32/64) doesn't seem to affect the alignment of the row size.
|
},
|
||||||
//
|
// The burst config (16/32/64) doesn't seem to affect the alignment of the row size.
|
||||||
// | | ( displayed range ) |
|
//
|
||||||
// | [ pad ] [ pad ]
|
// | | ( displayed range ) |
|
||||||
// | [ DMA-transmissible range ]
|
// | [ pad ] [ pad ]
|
||||||
// [ DMA-t. left overscan ] | | |
|
// | [ DMA-transmissible range ]
|
||||||
// 0 112 120 360 368 (index of u16 pixel)
|
// [ DMA-t. left overscan ] | | |
|
||||||
// ^ aligned ^ aligned ^ aligned
|
// 0 112 120 360 368 (index of u16 pixel)
|
||||||
//
|
// ^ aligned ^ aligned ^ aligned
|
||||||
// TODO: Compute the appropriate ranges to pass to the renderer and DPI peripheral.
|
//
|
||||||
// The renderer should pass the size of the `pad`ding to the GUI is parameters,
|
// TODO: Compute the appropriate ranges to pass to the renderer and DPI peripheral.
|
||||||
// to align the content to the displayed range.
|
// The renderer should pass the size of the `pad`ding to the GUI is parameters,
|
||||||
112,
|
// to align the content to the displayed range.
|
||||||
368 - 112,
|
112,
|
||||||
960,
|
368 - 112,
|
||||||
8,
|
960,
|
||||||
true,
|
16,
|
||||||
));
|
true,
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
info!("Framebuffer created!");
|
info!("Framebuffer created!");
|
||||||
|
|
||||||
let window_size = [framebuffer.height, framebuffer.width];
|
let window_size = [framebuffer.height, framebuffer.width];
|
||||||
let swapchain_writer = framebuffer.swapchain.take().unwrap();
|
let swapchain_writer = framebuffer.swapchain.take().unwrap();
|
||||||
|
|
||||||
static SECOND_CORE_STACK: StaticCell<Stack<STACK_SIZE_CORE_APP>> = StaticCell::new();
|
static SECOND_CORE_STACK: StaticCell<Stack<{ STACK_SIZE_CORE_APP }>> = StaticCell::new();
|
||||||
let second_core_stack = SECOND_CORE_STACK.init(Stack::new());
|
let second_core_stack = SECOND_CORE_STACK.init(Stack::new());
|
||||||
esp_rtos::start_second_core(
|
esp_rtos::start_second_core(
|
||||||
peripherals.CPU_CTRL,
|
cpu_ctrl,
|
||||||
// peripherals.software_interrupt0,
|
software_interrupt0,
|
||||||
peripherals.software_interrupt1,
|
software_interrupt1,
|
||||||
second_core_stack,
|
second_core_stack,
|
||||||
move || {
|
move || {
|
||||||
// static EXECUTOR: StaticCell<InterruptExecutor<2>> = StaticCell::new();
|
// static EXECUTOR: StaticCell<InterruptExecutor<2>> = StaticCell::new();
|
||||||
|
|
@ -758,101 +511,76 @@ async fn main_task(peripherals: MainPeripherals) {
|
||||||
window: RefCell::new(None),
|
window: RefCell::new(None),
|
||||||
swapchain: RefCell::new(swapchain_writer),
|
swapchain: RefCell::new(swapchain_writer),
|
||||||
quit_event_loop: Default::default(),
|
quit_event_loop: Default::default(),
|
||||||
events: Arc::new(critical_section::Mutex::new(RefCell::new(VecDeque::new()))),
|
events: Arc::new(blocking_mutex::Mutex::new(RefCell::new(VecDeque::new()))),
|
||||||
};
|
};
|
||||||
spawner.must_spawn(ui::run_renderer_task(slint_backend, flash_part_acid));
|
spawner.must_spawn(ui::run_renderer_task(slint_backend, partition_acid));
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
info!("Second core started!");
|
info!("Second core started!");
|
||||||
|
|
||||||
let mut user_controller = UserController::new();
|
let bb_controller = DmaBounceController::new(framebuffer.bounce_buffers.take().unwrap());
|
||||||
|
let mut user_controller = UserController::new(st7701s.controller, bb_controller);
|
||||||
|
|
||||||
info!("Awaiting on all tasks...");
|
user_controller.event_loop().await
|
||||||
|
|
||||||
framebuffer
|
|
||||||
.bounce_buffers
|
|
||||||
.take()
|
|
||||||
.unwrap()
|
|
||||||
.launch_interrupt_driven_task()
|
|
||||||
.await;
|
|
||||||
|
|
||||||
// TODO: Probably want to select! instead and re-try.
|
|
||||||
join_all![
|
|
||||||
run_alloc_stats_reporter(),
|
|
||||||
// We currently send the framebuffer data using the main core, which does not seem to slow
|
|
||||||
// down the rest of the tasks too much.
|
|
||||||
// async {
|
|
||||||
// warn!("Waiting...");
|
|
||||||
// Timer::after_secs(3).await;
|
|
||||||
// warn!("Waited.");
|
|
||||||
// framebuffer.bounce_buffers.send().await;
|
|
||||||
// },
|
|
||||||
// framebuffer.bounce_buffers.send(),
|
|
||||||
// ui::dpi::run_lcd(st7701s, framebuffer),
|
|
||||||
// lcd_task,
|
|
||||||
run_devices! (
|
|
||||||
(matrix) => rmk::channel::EVENT_CHANNEL,
|
|
||||||
),
|
|
||||||
keyboard.run(), // Keyboard is special
|
|
||||||
run_rmk(
|
|
||||||
&keymap,
|
|
||||||
#[cfg(not(feature = "no-usb"))]
|
|
||||||
usb_driver,
|
|
||||||
#[cfg(feature = "ble")]
|
|
||||||
&stack,
|
|
||||||
&mut storage,
|
|
||||||
rmk_config,
|
|
||||||
),
|
|
||||||
create_hid_report_interceptor(),
|
|
||||||
user_controller.event_loop(),
|
|
||||||
console::run_console(peripherals.uart_rx.into_async())
|
|
||||||
]
|
|
||||||
.await;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run_alloc_stats_reporter() {
|
enum DmaBounceControllerInner {
|
||||||
let mut psram_used_prev = 0;
|
Idle(DmaBounce),
|
||||||
let mut heap_used_prev = 0;
|
Transmitting(RunningDmaBounceHandle),
|
||||||
loop {
|
}
|
||||||
let psram_stats = PSRAM_ALLOCATOR.stats();
|
|
||||||
let heap_stats = esp_alloc::HEAP.stats();
|
struct DmaBounceController {
|
||||||
if psram_stats.current_usage != psram_used_prev {
|
inner: Option<DmaBounceControllerInner>,
|
||||||
let difference = psram_stats.current_usage as isize - psram_used_prev as isize;
|
}
|
||||||
psram_used_prev = psram_stats.current_usage;
|
|
||||||
warn!(
|
impl DmaBounceController {
|
||||||
"PSRAM usage changed: {}{}\n{psram_stats}",
|
pub fn new(dma_bounce: DmaBounce) -> Self {
|
||||||
if difference < 0 { '-' } else { '+' },
|
Self {
|
||||||
difference.abs()
|
inner: Some(DmaBounceControllerInner::Idle(dma_bounce)),
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if heap_stats.current_usage != heap_used_prev {
|
}
|
||||||
let difference = heap_stats.current_usage as isize - heap_used_prev as isize;
|
|
||||||
heap_used_prev = heap_stats.current_usage;
|
pub async fn start(&mut self) -> Result<(), ()> {
|
||||||
warn!(
|
let DmaBounceControllerInner::Idle(dma_bounce) = self.inner.take().unwrap() else {
|
||||||
"HEAP usage changed: {}{}\n{heap_stats}",
|
return Err(());
|
||||||
if difference < 0 { '-' } else { '+' },
|
};
|
||||||
difference.abs()
|
self.inner = Some(DmaBounceControllerInner::Transmitting(
|
||||||
);
|
dma_bounce.launch_interrupt_driven_task().await,
|
||||||
}
|
));
|
||||||
Timer::after_secs(1).await;
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn stop(&mut self) -> Result<(), ()> {
|
||||||
|
let DmaBounceControllerInner::Transmitting(running_dma_bounce) = self.inner.take().unwrap()
|
||||||
|
else {
|
||||||
|
return Err(());
|
||||||
|
};
|
||||||
|
self.inner = Some(DmaBounceControllerInner::Idle(
|
||||||
|
running_dma_bounce.stop().await,
|
||||||
|
));
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct UserController {
|
struct UserController<'a> {
|
||||||
sub: ControllerSub,
|
sub: ControllerSub,
|
||||||
|
lcd_controller: St7701sController<'a>,
|
||||||
|
bb_controller: DmaBounceController,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UserController {
|
impl<'a> UserController<'a> {
|
||||||
fn new() -> Self {
|
fn new(lcd_controller: St7701sController<'a>, bb_controller: DmaBounceController) -> Self {
|
||||||
Self {
|
Self {
|
||||||
sub: CONTROLLER_CHANNEL.subscriber().unwrap(),
|
sub: CONTROLLER_CHANNEL.subscriber().unwrap(),
|
||||||
|
lcd_controller,
|
||||||
|
bb_controller,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Controller for UserController {
|
impl<'a> Controller for UserController<'a> {
|
||||||
type Event = ControllerEvent;
|
type Event = ControllerEvent;
|
||||||
|
|
||||||
async fn process_event(&mut self, event: Self::Event) {
|
async fn process_event(&mut self, event: Self::Event) {
|
||||||
|
|
@ -868,10 +596,14 @@ impl Controller for UserController {
|
||||||
info!("Disabling LCD.");
|
info!("Disabling LCD.");
|
||||||
*rmk::channel::KEYBOARD_REPORT_SENDER.write().await =
|
*rmk::channel::KEYBOARD_REPORT_SENDER.write().await =
|
||||||
&rmk::channel::KEYBOARD_REPORT_RECEIVER;
|
&rmk::channel::KEYBOARD_REPORT_RECEIVER;
|
||||||
|
self.lcd_controller.sleep_on().await;
|
||||||
|
self.bb_controller.stop().await.unwrap();
|
||||||
}
|
}
|
||||||
true => {
|
true => {
|
||||||
info!("Enabling LCD.");
|
info!("Enabling LCD.");
|
||||||
*rmk::channel::KEYBOARD_REPORT_SENDER.write().await = &KEYBOARD_REPORT_PROXY;
|
*rmk::channel::KEYBOARD_REPORT_SENDER.write().await = &KEYBOARD_REPORT_PROXY;
|
||||||
|
self.bb_controller.start().await.unwrap();
|
||||||
|
self.lcd_controller.sleep_off().await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1231
firmware/acid-firmware/src/peripherals/st7701s/commands.rs
Normal file
1231
firmware/acid-firmware/src/peripherals/st7701s/commands.rs
Normal file
File diff suppressed because it is too large
Load diff
405
firmware/acid-firmware/src/peripherals/st7701s/init_sequence.rs
Normal file
405
firmware/acid-firmware/src/peripherals/st7701s/init_sequence.rs
Normal file
|
|
@ -0,0 +1,405 @@
|
||||||
|
use tinyvec::ArrayVec;
|
||||||
|
|
||||||
|
use crate::peripherals::st7701s::commands::*;
|
||||||
|
|
||||||
|
pub enum InitSequenceAction {
|
||||||
|
// TODO: Each command takes up 17 bytes. Consider storing compressed.
|
||||||
|
Command(ArrayCommand<16>),
|
||||||
|
SleepMs(u64),
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! make_init_action {
|
||||||
|
(command: $command:expr$(,)?) => {
|
||||||
|
InitSequenceAction::Command({
|
||||||
|
let command = $command;
|
||||||
|
let args_slice = command.args_slice();
|
||||||
|
let mut args_array = [0; _];
|
||||||
|
let mut args_len = 0;
|
||||||
|
while args_len < args_slice.len() {
|
||||||
|
args_array[args_len] = args_slice[args_len];
|
||||||
|
args_len += 1;
|
||||||
|
}
|
||||||
|
ArrayCommand {
|
||||||
|
address: command.address_const(),
|
||||||
|
args: match ArrayVec::try_from_array_len(args_array, args_len) {
|
||||||
|
Ok(args) => args,
|
||||||
|
Err(_) => panic!("too many command args"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
(sleep_ms: $expr:expr) => {
|
||||||
|
InitSequenceAction::SleepMs($expr)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! make_init_sequence {
|
||||||
|
($({ $($tt:tt)* }),*$(,)?) => {
|
||||||
|
[
|
||||||
|
$( make_init_action!($($tt)*) ),*
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const INIT_SEQUENCE_COMMANDS: [InitSequenceAction; 46] = make_init_sequence! [
|
||||||
|
{ command: CmdCn2bkxsel(
|
||||||
|
CmdCn2bkxselArg0::new(),
|
||||||
|
CmdCn2bkxselArg1::new(),
|
||||||
|
CmdCn2bkxselArg2::new(),
|
||||||
|
CmdCn2bkxselArg3::new(),
|
||||||
|
CmdCn2bkxselArg4::new().with_bksel(0x3).with_cn2(true),
|
||||||
|
) },
|
||||||
|
{ command: CustomCommand {
|
||||||
|
address: 0xEF,
|
||||||
|
args: &[0x08],
|
||||||
|
} },
|
||||||
|
{ command: CmdCn2bkxsel(
|
||||||
|
CmdCn2bkxselArg0::new(),
|
||||||
|
CmdCn2bkxselArg1::new(),
|
||||||
|
CmdCn2bkxselArg2::new(),
|
||||||
|
CmdCn2bkxselArg3::new(),
|
||||||
|
CmdCn2bkxselArg4::new().with_bksel(0x0).with_cn2(true),
|
||||||
|
) },
|
||||||
|
{ command: CmdLneset(
|
||||||
|
CmdLnesetArg0::new().with_bar(119).with_lde_en(false),
|
||||||
|
CmdLnesetArg1::new().with_line_delta(0),
|
||||||
|
) },
|
||||||
|
{ command: CmdPorctrl(
|
||||||
|
CmdPorctrlArg0::new().with_vbp(17),
|
||||||
|
CmdPorctrlArg1::new().with_vfp(12),
|
||||||
|
) },
|
||||||
|
{ command: CmdInvsel(
|
||||||
|
CmdInvselArg0::new().with_nlinv(0b111),
|
||||||
|
CmdInvselArg1::new().with_rtni(2),
|
||||||
|
) },
|
||||||
|
{ command: CustomCommand {
|
||||||
|
address: 0xCC,
|
||||||
|
args: &[0x30],
|
||||||
|
} },
|
||||||
|
{ command: CmdPvgamctrl(
|
||||||
|
CmdPvgamctrlArg0::new().with_vc0p(6).with_aj0p(0),
|
||||||
|
CmdPvgamctrlArg1::new().with_vc4p(15).with_aj1p(3),
|
||||||
|
CmdPvgamctrlArg2::new().with_vc8p(14).with_aj2p(0),
|
||||||
|
CmdPvgamctrlArg3::new().with_vc16p(12),
|
||||||
|
CmdPvgamctrlArg4::new().with_vc24p(15).with_aj3p(0),
|
||||||
|
CmdPvgamctrlArg5::new().with_vc52p(3),
|
||||||
|
CmdPvgamctrlArg6::new().with_vc80p(0),
|
||||||
|
CmdPvgamctrlArg7::new().with_vc108p(10),
|
||||||
|
CmdPvgamctrlArg8::new().with_vc147p(7),
|
||||||
|
CmdPvgamctrlArg9::new().with_vc175p(27),
|
||||||
|
CmdPvgamctrlArg10::new().with_vc203p(3),
|
||||||
|
CmdPvgamctrlArg11::new().with_vc231p(18).with_aj4p(0),
|
||||||
|
CmdPvgamctrlArg12::new().with_vc239p(16),
|
||||||
|
CmdPvgamctrlArg13::new().with_vc247p(37).with_aj5p(0),
|
||||||
|
CmdPvgamctrlArg14::new().with_vc251p(54).with_aj6p(0),
|
||||||
|
CmdPvgamctrlArg15::new().with_vc255p(30).with_aj7p(0),
|
||||||
|
) },
|
||||||
|
{ command: CmdNvgamctrl(
|
||||||
|
CmdNvgamctrlArg0::new().with_vc0n(12).with_aj0n(0),
|
||||||
|
CmdNvgamctrlArg1::new().with_vc4n(14).with_aj1n(3),
|
||||||
|
CmdNvgamctrlArg2::new().with_vc8n(18).with_aj2n(0),
|
||||||
|
CmdNvgamctrlArg3::new().with_vc16n(12),
|
||||||
|
CmdNvgamctrlArg4::new().with_vc24n(14).with_aj3n(0),
|
||||||
|
CmdNvgamctrlArg5::new().with_vc52n(6),
|
||||||
|
CmdNvgamctrlArg6::new().with_vc80n(3),
|
||||||
|
CmdNvgamctrlArg7::new().with_vc108n(6),
|
||||||
|
CmdNvgamctrlArg8::new().with_vc147n(8),
|
||||||
|
CmdNvgamctrlArg9::new().with_vc175n(35),
|
||||||
|
CmdNvgamctrlArg10::new().with_vc203n(6),
|
||||||
|
CmdNvgamctrlArg11::new().with_vc231n(18).with_aj4n(0),
|
||||||
|
CmdNvgamctrlArg12::new().with_vc239n(16),
|
||||||
|
CmdNvgamctrlArg13::new().with_vc247n(48).with_aj5n(0),
|
||||||
|
CmdNvgamctrlArg14::new().with_vc251n(47).with_aj6n(0),
|
||||||
|
CmdNvgamctrlArg15::new().with_vc255n(31).with_aj7n(0),
|
||||||
|
) },
|
||||||
|
{ command: CmdCn2bkxsel(
|
||||||
|
CmdCn2bkxselArg0::new(),
|
||||||
|
CmdCn2bkxselArg1::new(),
|
||||||
|
CmdCn2bkxselArg2::new(),
|
||||||
|
CmdCn2bkxselArg3::new(),
|
||||||
|
CmdCn2bkxselArg4::new().with_bksel(0x1).with_cn2(true),
|
||||||
|
) },
|
||||||
|
{ command: CmdVrhs(
|
||||||
|
CmdVrhsArg0::new().with_vrha(115),
|
||||||
|
) },
|
||||||
|
{ command: CmdVcoms(
|
||||||
|
CmdVcomsArg0::new().with_vcom(124),
|
||||||
|
) },
|
||||||
|
{ command: CmdVghss(
|
||||||
|
// The first bit is set to 1 in the original init code, but not here.
|
||||||
|
CmdVghssArg0::new().with_vghss(0x3), // 13 V
|
||||||
|
) },
|
||||||
|
{ command: CmdTescmd(
|
||||||
|
CmdTescmdArg0::new(),
|
||||||
|
) },
|
||||||
|
{ command: CmdVgls(
|
||||||
|
CmdVglsArg0::new().with_vgls(0x9) // -10.17 V
|
||||||
|
) },
|
||||||
|
{ command: CmdPwctrl1(
|
||||||
|
CmdPwctrl1Arg0::new()
|
||||||
|
.with_apos(0x3) // Max
|
||||||
|
.with_apis(0x1) // Min
|
||||||
|
.with_ap(0x2) // Middle
|
||||||
|
) },
|
||||||
|
{ command: CmdPwctrl2(
|
||||||
|
CmdPwctrl2Arg0::new()
|
||||||
|
.with_avcl(0x3) // -5 V
|
||||||
|
.with_avdd(0x3) // 6.8 V
|
||||||
|
) },
|
||||||
|
{ command: CmdPwctrl3(
|
||||||
|
CmdPwctrl3Arg0::new()
|
||||||
|
.with_svno_pum(0) // Cell setting 4
|
||||||
|
.with_svpo_pum(0x1) // Cell setting 5
|
||||||
|
) },
|
||||||
|
{ command: CmdPclks2(
|
||||||
|
CmdPclks2Arg0::new().with_sbstcks(0x3)
|
||||||
|
) },
|
||||||
|
{ command: CmdPdr1(
|
||||||
|
CmdPdr1Arg0::new().with_t2d(8) // 1.6 us
|
||||||
|
) },
|
||||||
|
{ command: CmdPdr2(
|
||||||
|
CmdPdr2Arg0::new().with_t3d(8) // 6.4 us
|
||||||
|
) },
|
||||||
|
{ command: CmdMipiset1(
|
||||||
|
CmdMipiset1Arg0::new().with_err_sel(0).with_eotp_en(true),
|
||||||
|
) },
|
||||||
|
{ command: CustomCommand {
|
||||||
|
address: 0xE0,
|
||||||
|
args: &[
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x02,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x0C,
|
||||||
|
]
|
||||||
|
} },
|
||||||
|
{ command: CustomCommand {
|
||||||
|
address: 0xE1,
|
||||||
|
args: &[
|
||||||
|
0x05,
|
||||||
|
0x96,
|
||||||
|
0x07,
|
||||||
|
0x96,
|
||||||
|
0x06,
|
||||||
|
0x96,
|
||||||
|
0x08,
|
||||||
|
0x96,
|
||||||
|
0x00,
|
||||||
|
0x44,
|
||||||
|
0x44,
|
||||||
|
]
|
||||||
|
} },
|
||||||
|
{ command: CustomCommand {
|
||||||
|
address: 0xE2,
|
||||||
|
args: &[
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x03,
|
||||||
|
0x03,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x02,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x02,
|
||||||
|
0x00,
|
||||||
|
]
|
||||||
|
} },
|
||||||
|
{ command: CustomCommand {
|
||||||
|
address: 0xE3,
|
||||||
|
args: &[
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x33,
|
||||||
|
0x33,
|
||||||
|
]
|
||||||
|
} },
|
||||||
|
{ command: CustomCommand {
|
||||||
|
address: 0xE4,
|
||||||
|
args: &[
|
||||||
|
0x44,
|
||||||
|
0x44,
|
||||||
|
]
|
||||||
|
} },
|
||||||
|
{ command: CustomCommand {
|
||||||
|
address: 0xE5,
|
||||||
|
args: &[
|
||||||
|
0x0D,
|
||||||
|
0xD4,
|
||||||
|
0x28,
|
||||||
|
0x8C,
|
||||||
|
0x0F,
|
||||||
|
0xD6,
|
||||||
|
0x28,
|
||||||
|
0x8C,
|
||||||
|
0x09,
|
||||||
|
0xD0,
|
||||||
|
0x28,
|
||||||
|
0x8C,
|
||||||
|
0x0B,
|
||||||
|
0xD2,
|
||||||
|
0x28,
|
||||||
|
0x8C,
|
||||||
|
]
|
||||||
|
} },
|
||||||
|
{ command: CustomCommand {
|
||||||
|
address: 0xE6,
|
||||||
|
args: &[
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x33,
|
||||||
|
0x33,
|
||||||
|
]
|
||||||
|
} },
|
||||||
|
{ command: CustomCommand {
|
||||||
|
address: 0xE7,
|
||||||
|
args: &[
|
||||||
|
0x44,
|
||||||
|
0x44,
|
||||||
|
]
|
||||||
|
} },
|
||||||
|
{ command: CustomCommand {
|
||||||
|
address: 0xE8,
|
||||||
|
args: &[
|
||||||
|
0x0E,
|
||||||
|
0xD5,
|
||||||
|
0x28,
|
||||||
|
0x8C,
|
||||||
|
0x10,
|
||||||
|
0xD7,
|
||||||
|
0x28,
|
||||||
|
0x8C,
|
||||||
|
0x0A,
|
||||||
|
0xD1,
|
||||||
|
0x28,
|
||||||
|
0x8C,
|
||||||
|
0x0C,
|
||||||
|
0xD3,
|
||||||
|
0x28,
|
||||||
|
0x8C,
|
||||||
|
]
|
||||||
|
} },
|
||||||
|
{ command: CustomCommand {
|
||||||
|
address: 0xEB,
|
||||||
|
args: &[
|
||||||
|
0x00,
|
||||||
|
0x01,
|
||||||
|
0xE4,
|
||||||
|
0xE4,
|
||||||
|
0x44,
|
||||||
|
0x00,
|
||||||
|
]
|
||||||
|
} },
|
||||||
|
{ command: CustomCommand {
|
||||||
|
address: 0xED,
|
||||||
|
args: &[
|
||||||
|
0xF3,
|
||||||
|
0xC1,
|
||||||
|
0xBA,
|
||||||
|
0x0F,
|
||||||
|
0x66,
|
||||||
|
0x77,
|
||||||
|
0x44,
|
||||||
|
0x55,
|
||||||
|
0x55,
|
||||||
|
0x44,
|
||||||
|
0x77,
|
||||||
|
0x66,
|
||||||
|
0xF0,
|
||||||
|
0xAB,
|
||||||
|
0x1C,
|
||||||
|
0x3F,
|
||||||
|
]
|
||||||
|
} },
|
||||||
|
{ command: CustomCommand {
|
||||||
|
address: 0xEF,
|
||||||
|
args: &[
|
||||||
|
0x10,
|
||||||
|
0x0D,
|
||||||
|
0x04,
|
||||||
|
0x08,
|
||||||
|
0x3F,
|
||||||
|
0x1F,
|
||||||
|
]
|
||||||
|
} },
|
||||||
|
{ command: CmdCn2bkxsel(
|
||||||
|
CmdCn2bkxselArg0::new(),
|
||||||
|
CmdCn2bkxselArg1::new(),
|
||||||
|
CmdCn2bkxselArg2::new(),
|
||||||
|
CmdCn2bkxselArg3::new(),
|
||||||
|
CmdCn2bkxselArg4::new().with_bksel(0x3).with_cn2(true),
|
||||||
|
) },
|
||||||
|
{ command: CustomCommand {
|
||||||
|
address: 0xE8,
|
||||||
|
args: &[
|
||||||
|
0x00,
|
||||||
|
0x0E,
|
||||||
|
],
|
||||||
|
} },
|
||||||
|
{ command: CmdSlpout() },
|
||||||
|
{ sleep_ms: 120 },
|
||||||
|
{ command: CustomCommand {
|
||||||
|
address: 0xE8,
|
||||||
|
args: &[
|
||||||
|
0x00,
|
||||||
|
0x0C,
|
||||||
|
],
|
||||||
|
} },
|
||||||
|
{ sleep_ms: 10 },
|
||||||
|
{ command: CustomCommand {
|
||||||
|
address: 0xE8,
|
||||||
|
args: &[
|
||||||
|
0x40,
|
||||||
|
0x00,
|
||||||
|
],
|
||||||
|
} },
|
||||||
|
{ command: CmdCn2bkxsel(
|
||||||
|
CmdCn2bkxselArg0::new(),
|
||||||
|
CmdCn2bkxselArg1::new(),
|
||||||
|
CmdCn2bkxselArg2::new(),
|
||||||
|
CmdCn2bkxselArg3::new(),
|
||||||
|
CmdCn2bkxselArg4::new().with_bksel(0).with_cn2(false),
|
||||||
|
) },
|
||||||
|
{ command: CmdMadctl(
|
||||||
|
CmdMadctlArg0::new().with_bgr(false).with_ml(false),
|
||||||
|
) },
|
||||||
|
{ command: CmdColmod(
|
||||||
|
CmdColmodArg0::new().with_vipf(6) // 18-bit pixel
|
||||||
|
) },
|
||||||
|
{ command: CmdDispon() },
|
||||||
|
{ sleep_ms: 20 },
|
||||||
|
// { command: CmdCn2bkxsel(
|
||||||
|
// CmdCn2bkxselArg0::new(),
|
||||||
|
// CmdCn2bkxselArg1::new(),
|
||||||
|
// CmdCn2bkxselArg2::new(),
|
||||||
|
// CmdCn2bkxselArg3::new(),
|
||||||
|
// CmdCn2bkxselArg4::new().with_bksel(0).with_cn2(true),
|
||||||
|
// ) },
|
||||||
|
// { command: CmdPorctrl(
|
||||||
|
// CmdPorctrlArg0::new().with_vbp(0xFF),
|
||||||
|
// CmdPorctrlArg1::new().with_vfp(0x0),
|
||||||
|
// ) },
|
||||||
|
// // { command: CmdRgbctrl(
|
||||||
|
// // CmdRgbctrlArg0::new()
|
||||||
|
// // .with_ep(false)
|
||||||
|
// // .with_dp(false)
|
||||||
|
// // .with_hsp(false)
|
||||||
|
// // .with_vsp(false)
|
||||||
|
// // .with_de_hv(true),
|
||||||
|
// // CmdRgbctrlArg1::new()
|
||||||
|
// // .with_hbp_hvrgb(16),
|
||||||
|
// // CmdRgbctrlArg2::new()
|
||||||
|
// // .with_vbp_hvrgb(8),
|
||||||
|
// // ) },
|
||||||
|
// { command: CmdCn2bkxsel(
|
||||||
|
// CmdCn2bkxselArg0::new(),
|
||||||
|
// CmdCn2bkxselArg1::new(),
|
||||||
|
// CmdCn2bkxselArg2::new(),
|
||||||
|
// CmdCn2bkxselArg3::new(),
|
||||||
|
// CmdCn2bkxselArg4::new().with_bksel(0).with_cn2(false),
|
||||||
|
// ) },
|
||||||
|
// { sleep_ms: 20 },
|
||||||
|
];
|
||||||
|
|
@ -1,489 +0,0 @@
|
||||||
use alloc::{boxed::Box, vec, vec::Vec};
|
|
||||||
use core::iter::once;
|
|
||||||
use embassy_time::{Duration, Timer};
|
|
||||||
use esp_hal::gpio::{Flex, Level, Output};
|
|
||||||
use lazy_static::lazy_static;
|
|
||||||
|
|
||||||
use crate::peripherals::st7701s::Command;
|
|
||||||
|
|
||||||
async fn spi_delay() {
|
|
||||||
Timer::after(Duration::from_micros(1)).await;
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn spi_dummy_bit(sck: &mut Output<'_>) {
|
|
||||||
sck.set_low();
|
|
||||||
spi_delay().await;
|
|
||||||
sck.set_high();
|
|
||||||
spi_delay().await;
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn spi_write_bit(bit: bool, mosi: &mut Flex<'_>, sck: &mut Output<'_>) {
|
|
||||||
mosi.set_level(if bit { Level::High } else { Level::Low });
|
|
||||||
sck.set_low();
|
|
||||||
spi_delay().await;
|
|
||||||
sck.set_high();
|
|
||||||
spi_delay().await;
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn spi_read_bit(mosi: &mut Flex<'_>, sck: &mut Output<'_>) -> bool {
|
|
||||||
sck.set_low();
|
|
||||||
spi_delay().await;
|
|
||||||
sck.set_high();
|
|
||||||
spi_delay().await;
|
|
||||||
mosi.is_high()
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn spi_write_bits(
|
|
||||||
bits: impl Iterator<Item = bool>,
|
|
||||||
mosi: &mut Flex<'_>,
|
|
||||||
sck: &mut Output<'_>,
|
|
||||||
) {
|
|
||||||
for bit in bits {
|
|
||||||
spi_write_bit(bit, mosi, sck).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn spi_write_word(is_param: bool, data: u8, mosi: &mut Flex<'_>, sck: &mut Output<'_>) {
|
|
||||||
assert!(sck.is_set_high());
|
|
||||||
spi_write_bits(
|
|
||||||
once(is_param).chain((0..8).map(|i| (data >> i) & 1 != 0).rev()),
|
|
||||||
mosi,
|
|
||||||
sck,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn spi_write(
|
|
||||||
command: u8,
|
|
||||||
args: impl IntoIterator<Item = u8>,
|
|
||||||
mosi: &mut Flex<'_>,
|
|
||||||
sck: &mut Output<'_>,
|
|
||||||
cs: &mut Output<'_>,
|
|
||||||
) {
|
|
||||||
cs.set_low();
|
|
||||||
spi_write_word(false, command, mosi, sck).await;
|
|
||||||
|
|
||||||
for arg in args {
|
|
||||||
spi_write_word(true, arg, mosi, sck).await;
|
|
||||||
}
|
|
||||||
|
|
||||||
cs.set_high();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[expect(unused)]
|
|
||||||
pub async fn spi_read(
|
|
||||||
command: u8,
|
|
||||||
dummy_cycle: bool,
|
|
||||||
mosi: &mut Flex<'_>,
|
|
||||||
sck: &mut Output<'_>,
|
|
||||||
cs: &mut Output<'_>,
|
|
||||||
output_buffer: &mut [u8],
|
|
||||||
) {
|
|
||||||
output_buffer.fill(0);
|
|
||||||
|
|
||||||
cs.set_low();
|
|
||||||
spi_write_word(false, command, mosi, sck).await;
|
|
||||||
|
|
||||||
mosi.set_output_enable(false);
|
|
||||||
mosi.set_input_enable(true);
|
|
||||||
|
|
||||||
if dummy_cycle {
|
|
||||||
spi_dummy_bit(sck).await;
|
|
||||||
}
|
|
||||||
|
|
||||||
for output_byte in output_buffer {
|
|
||||||
for i in (0..8).rev() {
|
|
||||||
if spi_read_bit(mosi, sck).await {
|
|
||||||
*output_byte |= 1 << i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mosi.set_input_enable(false);
|
|
||||||
mosi.set_output_enable(true);
|
|
||||||
|
|
||||||
cs.set_high();
|
|
||||||
}
|
|
||||||
|
|
||||||
use crate::peripherals::st7701s::*;
|
|
||||||
|
|
||||||
// struct InitSequenceAction {
|
|
||||||
// command: ArrayCommand<8>,
|
|
||||||
// sleep: u64,
|
|
||||||
// }
|
|
||||||
|
|
||||||
// pub const INIT_SEQUENCE: [InitSequenceAction; _] = [CmdCn2bkxsel(
|
|
||||||
// CmdCn2bkxselArg0::new(),
|
|
||||||
// CmdCn2bkxselArg1::new(),
|
|
||||||
// CmdCn2bkxselArg2::new(),
|
|
||||||
// CmdCn2bkxselArg3::new(),
|
|
||||||
// CmdCn2bkxselArg4::new().with_bksel(0x3).with_cn2(true),
|
|
||||||
// )];
|
|
||||||
|
|
||||||
lazy_static! {
|
|
||||||
pub static ref INIT_SEQUENCE_COMMANDS: Vec<(Vec<Box<dyn Command + Send + Sync>>, u64)> = vec![
|
|
||||||
(vec![
|
|
||||||
Box::new(CmdCn2bkxsel(
|
|
||||||
CmdCn2bkxselArg0::new(),
|
|
||||||
CmdCn2bkxselArg1::new(),
|
|
||||||
CmdCn2bkxselArg2::new(),
|
|
||||||
CmdCn2bkxselArg3::new(),
|
|
||||||
CmdCn2bkxselArg4::new().with_bksel(0x3).with_cn2(true),
|
|
||||||
)),
|
|
||||||
Box::new(CustomCommand {
|
|
||||||
address: 0xEF,
|
|
||||||
args: &[0x08],
|
|
||||||
}),
|
|
||||||
Box::new(CmdCn2bkxsel(
|
|
||||||
CmdCn2bkxselArg0::new(),
|
|
||||||
CmdCn2bkxselArg1::new(),
|
|
||||||
CmdCn2bkxselArg2::new(),
|
|
||||||
CmdCn2bkxselArg3::new(),
|
|
||||||
CmdCn2bkxselArg4::new().with_bksel(0x0).with_cn2(true),
|
|
||||||
)),
|
|
||||||
Box::new(CmdLneset(
|
|
||||||
CmdLnesetArg0::new().with_bar(119).with_lde_en(false),
|
|
||||||
CmdLnesetArg1::new().with_line_delta(0),
|
|
||||||
)),
|
|
||||||
Box::new(CmdPorctrl(
|
|
||||||
CmdPorctrlArg0::new().with_vbp(17),
|
|
||||||
CmdPorctrlArg1::new().with_vfp(12),
|
|
||||||
)),
|
|
||||||
Box::new(CmdInvsel(
|
|
||||||
CmdInvselArg0::new().with_nlinv(0b111),
|
|
||||||
CmdInvselArg1::new().with_rtni(2),
|
|
||||||
)),
|
|
||||||
Box::new(CustomCommand {
|
|
||||||
address: 0xCC,
|
|
||||||
args: &[0x30],
|
|
||||||
}),
|
|
||||||
Box::new(CmdPvgamctrl(
|
|
||||||
CmdPvgamctrlArg0::new().with_vc0p(6).with_aj0p(0),
|
|
||||||
CmdPvgamctrlArg1::new().with_vc4p(15).with_aj1p(3),
|
|
||||||
CmdPvgamctrlArg2::new().with_vc8p(14).with_aj2p(0),
|
|
||||||
CmdPvgamctrlArg3::new().with_vc16p(12),
|
|
||||||
CmdPvgamctrlArg4::new().with_vc24p(15).with_aj3p(0),
|
|
||||||
CmdPvgamctrlArg5::new().with_vc52p(3),
|
|
||||||
CmdPvgamctrlArg6::new().with_vc80p(0),
|
|
||||||
CmdPvgamctrlArg7::new().with_vc108p(10),
|
|
||||||
CmdPvgamctrlArg8::new().with_vc147p(7),
|
|
||||||
CmdPvgamctrlArg9::new().with_vc175p(27),
|
|
||||||
CmdPvgamctrlArg10::new().with_vc203p(3),
|
|
||||||
CmdPvgamctrlArg11::new().with_vc231p(18).with_aj4p(0),
|
|
||||||
CmdPvgamctrlArg12::new().with_vc239p(16),
|
|
||||||
CmdPvgamctrlArg13::new().with_vc247p(37).with_aj5p(0),
|
|
||||||
CmdPvgamctrlArg14::new().with_vc251p(54).with_aj6p(0),
|
|
||||||
CmdPvgamctrlArg15::new().with_vc255p(30).with_aj7p(0),
|
|
||||||
)),
|
|
||||||
Box::new(CmdNvgamctrl(
|
|
||||||
CmdNvgamctrlArg0::new().with_vc0n(12).with_aj0n(0),
|
|
||||||
CmdNvgamctrlArg1::new().with_vc4n(14).with_aj1n(3),
|
|
||||||
CmdNvgamctrlArg2::new().with_vc8n(18).with_aj2n(0),
|
|
||||||
CmdNvgamctrlArg3::new().with_vc16n(12),
|
|
||||||
CmdNvgamctrlArg4::new().with_vc24n(14).with_aj3n(0),
|
|
||||||
CmdNvgamctrlArg5::new().with_vc52n(6),
|
|
||||||
CmdNvgamctrlArg6::new().with_vc80n(3),
|
|
||||||
CmdNvgamctrlArg7::new().with_vc108n(6),
|
|
||||||
CmdNvgamctrlArg8::new().with_vc147n(8),
|
|
||||||
CmdNvgamctrlArg9::new().with_vc175n(35),
|
|
||||||
CmdNvgamctrlArg10::new().with_vc203n(6),
|
|
||||||
CmdNvgamctrlArg11::new().with_vc231n(18).with_aj4n(0),
|
|
||||||
CmdNvgamctrlArg12::new().with_vc239n(16),
|
|
||||||
CmdNvgamctrlArg13::new().with_vc247n(48).with_aj5n(0),
|
|
||||||
CmdNvgamctrlArg14::new().with_vc251n(47).with_aj6n(0),
|
|
||||||
CmdNvgamctrlArg15::new().with_vc255n(31).with_aj7n(0),
|
|
||||||
)),
|
|
||||||
Box::new(CmdCn2bkxsel(
|
|
||||||
CmdCn2bkxselArg0::new(),
|
|
||||||
CmdCn2bkxselArg1::new(),
|
|
||||||
CmdCn2bkxselArg2::new(),
|
|
||||||
CmdCn2bkxselArg3::new(),
|
|
||||||
CmdCn2bkxselArg4::new().with_bksel(0x1).with_cn2(true),
|
|
||||||
)),
|
|
||||||
Box::new(CmdVrhs(
|
|
||||||
CmdVrhsArg0::new().with_vrha(115),
|
|
||||||
)),
|
|
||||||
Box::new(CmdVcoms(
|
|
||||||
CmdVcomsArg0::new().with_vcom(124),
|
|
||||||
)),
|
|
||||||
Box::new(CmdVghss(
|
|
||||||
// The first bit is set to 1 in the original init code, but not here.
|
|
||||||
CmdVghssArg0::new().with_vghss(0x3), // 13 V
|
|
||||||
)),
|
|
||||||
Box::new(CmdTescmd(
|
|
||||||
CmdTescmdArg0::new(),
|
|
||||||
)),
|
|
||||||
Box::new(CmdVgls(
|
|
||||||
CmdVglsArg0::new().with_vgls(0x9) // -10.17 V
|
|
||||||
)),
|
|
||||||
Box::new(CmdPwctrl1(
|
|
||||||
CmdPwctrl1Arg0::new()
|
|
||||||
.with_apos(0x3) // Max
|
|
||||||
.with_apis(0x1) // Min
|
|
||||||
.with_ap(0x2) // Middle
|
|
||||||
)),
|
|
||||||
Box::new(CmdPwctrl2(
|
|
||||||
CmdPwctrl2Arg0::new()
|
|
||||||
.with_avcl(0x3) // -5 V
|
|
||||||
.with_avdd(0x3) // 6.8 V
|
|
||||||
)),
|
|
||||||
Box::new(CmdPwctrl3(
|
|
||||||
CmdPwctrl3Arg0::new()
|
|
||||||
.with_svno_pum(0) // Cell setting 4
|
|
||||||
.with_svpo_pum(0x1) // Cell setting 5
|
|
||||||
)),
|
|
||||||
Box::new(CmdPclks2(
|
|
||||||
CmdPclks2Arg0::new().with_sbstcks(0x3)
|
|
||||||
)),
|
|
||||||
Box::new(CmdPdr1(
|
|
||||||
CmdPdr1Arg0::new().with_t2d(8) // 1.6 us
|
|
||||||
)),
|
|
||||||
Box::new(CmdPdr2(
|
|
||||||
CmdPdr2Arg0::new().with_t3d(8) // 6.4 us
|
|
||||||
)),
|
|
||||||
Box::new(CmdMipiset1(
|
|
||||||
CmdMipiset1Arg0::new().with_err_sel(0).with_eotp_en(true),
|
|
||||||
)),
|
|
||||||
Box::new(CustomCommand {
|
|
||||||
address: 0xE0,
|
|
||||||
args: &[
|
|
||||||
0x00,
|
|
||||||
0x00,
|
|
||||||
0x02,
|
|
||||||
0x00,
|
|
||||||
0x00,
|
|
||||||
0x0C,
|
|
||||||
]
|
|
||||||
}),
|
|
||||||
Box::new(CustomCommand {
|
|
||||||
address: 0xE1,
|
|
||||||
args: &[
|
|
||||||
0x05,
|
|
||||||
0x96,
|
|
||||||
0x07,
|
|
||||||
0x96,
|
|
||||||
0x06,
|
|
||||||
0x96,
|
|
||||||
0x08,
|
|
||||||
0x96,
|
|
||||||
0x00,
|
|
||||||
0x44,
|
|
||||||
0x44,
|
|
||||||
]
|
|
||||||
}),
|
|
||||||
Box::new(CustomCommand {
|
|
||||||
address: 0xE2,
|
|
||||||
args: &[
|
|
||||||
0x00,
|
|
||||||
0x00,
|
|
||||||
0x03,
|
|
||||||
0x03,
|
|
||||||
0x00,
|
|
||||||
0x00,
|
|
||||||
0x02,
|
|
||||||
0x00,
|
|
||||||
0x00,
|
|
||||||
0x00,
|
|
||||||
0x02,
|
|
||||||
0x00,
|
|
||||||
]
|
|
||||||
}),
|
|
||||||
Box::new(CustomCommand {
|
|
||||||
address: 0xE3,
|
|
||||||
args: &[
|
|
||||||
0x00,
|
|
||||||
0x00,
|
|
||||||
0x33,
|
|
||||||
0x33,
|
|
||||||
]
|
|
||||||
}),
|
|
||||||
Box::new(CustomCommand {
|
|
||||||
address: 0xE4,
|
|
||||||
args: &[
|
|
||||||
0x44,
|
|
||||||
0x44,
|
|
||||||
]
|
|
||||||
}),
|
|
||||||
Box::new(CustomCommand {
|
|
||||||
address: 0xE5,
|
|
||||||
args: &[
|
|
||||||
0x0D,
|
|
||||||
0xD4,
|
|
||||||
0x28,
|
|
||||||
0x8C,
|
|
||||||
0x0F,
|
|
||||||
0xD6,
|
|
||||||
0x28,
|
|
||||||
0x8C,
|
|
||||||
0x09,
|
|
||||||
0xD0,
|
|
||||||
0x28,
|
|
||||||
0x8C,
|
|
||||||
0x0B,
|
|
||||||
0xD2,
|
|
||||||
0x28,
|
|
||||||
0x8C,
|
|
||||||
]
|
|
||||||
}),
|
|
||||||
Box::new(CustomCommand {
|
|
||||||
address: 0xE6,
|
|
||||||
args: &[
|
|
||||||
0x00,
|
|
||||||
0x00,
|
|
||||||
0x33,
|
|
||||||
0x33,
|
|
||||||
]
|
|
||||||
}),
|
|
||||||
Box::new(CustomCommand {
|
|
||||||
address: 0xE7,
|
|
||||||
args: &[
|
|
||||||
0x44,
|
|
||||||
0x44,
|
|
||||||
]
|
|
||||||
}),
|
|
||||||
Box::new(CustomCommand {
|
|
||||||
address: 0xE8,
|
|
||||||
args: &[
|
|
||||||
0x0E,
|
|
||||||
0xD5,
|
|
||||||
0x28,
|
|
||||||
0x8C,
|
|
||||||
0x10,
|
|
||||||
0xD7,
|
|
||||||
0x28,
|
|
||||||
0x8C,
|
|
||||||
0x0A,
|
|
||||||
0xD1,
|
|
||||||
0x28,
|
|
||||||
0x8C,
|
|
||||||
0x0C,
|
|
||||||
0xD3,
|
|
||||||
0x28,
|
|
||||||
0x8C,
|
|
||||||
]
|
|
||||||
}),
|
|
||||||
Box::new(CustomCommand {
|
|
||||||
address: 0xEB,
|
|
||||||
args: &[
|
|
||||||
0x00,
|
|
||||||
0x01,
|
|
||||||
0xE4,
|
|
||||||
0xE4,
|
|
||||||
0x44,
|
|
||||||
0x00,
|
|
||||||
]
|
|
||||||
}),
|
|
||||||
Box::new(CustomCommand {
|
|
||||||
address: 0xED,
|
|
||||||
args: &[
|
|
||||||
0xF3,
|
|
||||||
0xC1,
|
|
||||||
0xBA,
|
|
||||||
0x0F,
|
|
||||||
0x66,
|
|
||||||
0x77,
|
|
||||||
0x44,
|
|
||||||
0x55,
|
|
||||||
0x55,
|
|
||||||
0x44,
|
|
||||||
0x77,
|
|
||||||
0x66,
|
|
||||||
0xF0,
|
|
||||||
0xAB,
|
|
||||||
0x1C,
|
|
||||||
0x3F,
|
|
||||||
]
|
|
||||||
}),
|
|
||||||
Box::new(CustomCommand {
|
|
||||||
address: 0xEF,
|
|
||||||
args: &[
|
|
||||||
0x10,
|
|
||||||
0x0D,
|
|
||||||
0x04,
|
|
||||||
0x08,
|
|
||||||
0x3F,
|
|
||||||
0x1F,
|
|
||||||
]
|
|
||||||
}),
|
|
||||||
Box::new(CmdCn2bkxsel(
|
|
||||||
CmdCn2bkxselArg0::new(),
|
|
||||||
CmdCn2bkxselArg1::new(),
|
|
||||||
CmdCn2bkxselArg2::new(),
|
|
||||||
CmdCn2bkxselArg3::new(),
|
|
||||||
CmdCn2bkxselArg4::new().with_bksel(0x3).with_cn2(true),
|
|
||||||
)),
|
|
||||||
Box::new(CustomCommand {
|
|
||||||
address: 0xE8,
|
|
||||||
args: &[
|
|
||||||
0x00,
|
|
||||||
0x0E,
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
Box::new(CmdSlpout()),
|
|
||||||
], 120),
|
|
||||||
(vec![
|
|
||||||
Box::new(CustomCommand {
|
|
||||||
address: 0xE8,
|
|
||||||
args: &[
|
|
||||||
0x00,
|
|
||||||
0x0C,
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
], 10),
|
|
||||||
(vec![
|
|
||||||
Box::new(CustomCommand {
|
|
||||||
address: 0xE8,
|
|
||||||
args: &[
|
|
||||||
0x40,
|
|
||||||
0x00,
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
Box::new(CmdCn2bkxsel(
|
|
||||||
CmdCn2bkxselArg0::new(),
|
|
||||||
CmdCn2bkxselArg1::new(),
|
|
||||||
CmdCn2bkxselArg2::new(),
|
|
||||||
CmdCn2bkxselArg3::new(),
|
|
||||||
CmdCn2bkxselArg4::new().with_bksel(0).with_cn2(false),
|
|
||||||
)),
|
|
||||||
Box::new(CmdMadctl(
|
|
||||||
CmdMadctlArg0::new().with_bgr(false).with_ml(false),
|
|
||||||
)),
|
|
||||||
Box::new(CmdColmod(
|
|
||||||
CmdColmodArg0::new().with_vipf(6) // 18-bit pixel
|
|
||||||
)),
|
|
||||||
Box::new(CmdDispon()),
|
|
||||||
], 20),
|
|
||||||
// (vec![
|
|
||||||
// Box::new(CmdCn2bkxsel(
|
|
||||||
// CmdCn2bkxselArg0::new(),
|
|
||||||
// CmdCn2bkxselArg1::new(),
|
|
||||||
// CmdCn2bkxselArg2::new(),
|
|
||||||
// CmdCn2bkxselArg3::new(),
|
|
||||||
// CmdCn2bkxselArg4::new().with_bksel(0).with_cn2(true),
|
|
||||||
// )),
|
|
||||||
// Box::new(CmdPorctrl(
|
|
||||||
// CmdPorctrlArg0::new().with_vbp(0xFF),
|
|
||||||
// CmdPorctrlArg1::new().with_vfp(0x0),
|
|
||||||
// )),
|
|
||||||
// // Box::new(CmdRgbctrl(
|
|
||||||
// // CmdRgbctrlArg0::new()
|
|
||||||
// // .with_ep(false)
|
|
||||||
// // .with_dp(false)
|
|
||||||
// // .with_hsp(false)
|
|
||||||
// // .with_vsp(false)
|
|
||||||
// // .with_de_hv(true),
|
|
||||||
// // CmdRgbctrlArg1::new()
|
|
||||||
// // .with_hbp_hvrgb(16),
|
|
||||||
// // CmdRgbctrlArg2::new()
|
|
||||||
// // .with_vbp_hvrgb(8),
|
|
||||||
// // )),
|
|
||||||
// Box::new(CmdCn2bkxsel(
|
|
||||||
// CmdCn2bkxselArg0::new(),
|
|
||||||
// CmdCn2bkxselArg1::new(),
|
|
||||||
// CmdCn2bkxselArg2::new(),
|
|
||||||
// CmdCn2bkxselArg3::new(),
|
|
||||||
// CmdCn2bkxselArg4::new().with_bksel(0).with_cn2(false),
|
|
||||||
// )),
|
|
||||||
// ], 20),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load diff
102
firmware/acid-firmware/src/peripherals/st7701s/spi.rs
Normal file
102
firmware/acid-firmware/src/peripherals/st7701s/spi.rs
Normal file
|
|
@ -0,0 +1,102 @@
|
||||||
|
use core::iter::once;
|
||||||
|
use embassy_time::{Duration, Timer};
|
||||||
|
use esp_hal::gpio::{Flex, Level, Output};
|
||||||
|
|
||||||
|
async fn spi_delay() {
|
||||||
|
Timer::after(Duration::from_micros(1)).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn spi_dummy_bit(sck: &mut Output<'_>) {
|
||||||
|
sck.set_low();
|
||||||
|
spi_delay().await;
|
||||||
|
sck.set_high();
|
||||||
|
spi_delay().await;
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn spi_write_bit(bit: bool, mosi: &mut Flex<'_>, sck: &mut Output<'_>) {
|
||||||
|
mosi.set_level(if bit { Level::High } else { Level::Low });
|
||||||
|
sck.set_low();
|
||||||
|
spi_delay().await;
|
||||||
|
sck.set_high();
|
||||||
|
spi_delay().await;
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn spi_read_bit(mosi: &mut Flex<'_>, sck: &mut Output<'_>) -> bool {
|
||||||
|
sck.set_low();
|
||||||
|
spi_delay().await;
|
||||||
|
sck.set_high();
|
||||||
|
spi_delay().await;
|
||||||
|
mosi.is_high()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn spi_write_bits(
|
||||||
|
bits: impl Iterator<Item = bool>,
|
||||||
|
mosi: &mut Flex<'_>,
|
||||||
|
sck: &mut Output<'_>,
|
||||||
|
) {
|
||||||
|
for bit in bits {
|
||||||
|
spi_write_bit(bit, mosi, sck).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn spi_write_word(is_param: bool, data: u8, mosi: &mut Flex<'_>, sck: &mut Output<'_>) {
|
||||||
|
assert!(sck.is_set_high());
|
||||||
|
spi_write_bits(
|
||||||
|
once(is_param).chain((0..8).map(|i| (data >> i) & 1 != 0).rev()),
|
||||||
|
mosi,
|
||||||
|
sck,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn spi_write(
|
||||||
|
command: u8,
|
||||||
|
args: impl IntoIterator<Item = u8>,
|
||||||
|
mosi: &mut Flex<'_>,
|
||||||
|
sck: &mut Output<'_>,
|
||||||
|
cs: &mut Output<'_>,
|
||||||
|
) {
|
||||||
|
cs.set_low();
|
||||||
|
spi_write_word(false, command, mosi, sck).await;
|
||||||
|
|
||||||
|
for arg in args {
|
||||||
|
spi_write_word(true, arg, mosi, sck).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
cs.set_high();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[expect(unused)]
|
||||||
|
pub async fn spi_read(
|
||||||
|
command: u8,
|
||||||
|
dummy_cycle: bool,
|
||||||
|
mosi: &mut Flex<'_>,
|
||||||
|
sck: &mut Output<'_>,
|
||||||
|
cs: &mut Output<'_>,
|
||||||
|
output_buffer: &mut [u8],
|
||||||
|
) {
|
||||||
|
output_buffer.fill(0);
|
||||||
|
|
||||||
|
cs.set_low();
|
||||||
|
spi_write_word(false, command, mosi, sck).await;
|
||||||
|
|
||||||
|
mosi.set_output_enable(false);
|
||||||
|
mosi.set_input_enable(true);
|
||||||
|
|
||||||
|
if dummy_cycle {
|
||||||
|
spi_dummy_bit(sck).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
for output_byte in output_buffer {
|
||||||
|
for i in (0..8).rev() {
|
||||||
|
if spi_read_bit(mosi, sck).await {
|
||||||
|
*output_byte |= 1 << i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mosi.set_input_enable(false);
|
||||||
|
mosi.set_output_enable(true);
|
||||||
|
|
||||||
|
cs.set_high();
|
||||||
|
}
|
||||||
|
|
@ -11,7 +11,7 @@ use alloc::vec::Vec;
|
||||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||||
use embassy_sync::channel::Channel;
|
use embassy_sync::channel::Channel;
|
||||||
use embassy_time::Instant;
|
use embassy_time::Instant;
|
||||||
use esp_alloc::{EspHeap, MemoryCapability};
|
use esp_alloc::MemoryCapability;
|
||||||
use log::{debug, error, info, warn};
|
use log::{debug, error, info, warn};
|
||||||
use rmk::descriptor::KeyboardReport;
|
use rmk::descriptor::KeyboardReport;
|
||||||
use rmk::hid::Report;
|
use rmk::hid::Report;
|
||||||
|
|
@ -19,6 +19,7 @@ use rmk::{heapless, join_all};
|
||||||
use slint::platform::Key;
|
use slint::platform::Key;
|
||||||
use xkbcommon::xkb::{self, FeedResult, KeyDirection, Keysym, ModMask, Status};
|
use xkbcommon::xkb::{self, FeedResult, KeyDirection, Keysym, ModMask, Status};
|
||||||
|
|
||||||
|
use crate::ram::PsramAllocator;
|
||||||
use crate::util::{DurationExt, get_file_name};
|
use crate::util::{DurationExt, get_file_name};
|
||||||
use crate::{KEYBOARD_REPORT_PROXY, PSRAM_ALLOCATOR};
|
use crate::{KEYBOARD_REPORT_PROXY, PSRAM_ALLOCATOR};
|
||||||
|
|
||||||
|
|
@ -401,8 +402,8 @@ struct KeysymEntry {
|
||||||
mask: xkb::ModMask,
|
mask: xkb::ModMask,
|
||||||
}
|
}
|
||||||
|
|
||||||
type KeysymEntries = Vec<KeysymEntry, &'static EspHeap>;
|
type KeysymEntries = Vec<KeysymEntry, PsramAllocator>;
|
||||||
type KeysymMap = BTreeMap<Keysym, KeysymEntries, &'static EspHeap>;
|
type KeysymMap = BTreeMap<Keysym, KeysymEntries, PsramAllocator>;
|
||||||
|
|
||||||
/// Based on https://github.com/xkbcommon/libxkbcommon/blob/6c67e3d41d3215ab1edd4406de215c7bf1f20c74/tools/how-to-type.c#L434
|
/// Based on https://github.com/xkbcommon/libxkbcommon/blob/6c67e3d41d3215ab1edd4406de215c7bf1f20c74/tools/how-to-type.c#L434
|
||||||
fn lookup_keysym_entries(
|
fn lookup_keysym_entries(
|
||||||
|
|
@ -427,7 +428,7 @@ pub fn string_to_hid_keycodes(
|
||||||
keymap: &xkb::Keymap,
|
keymap: &xkb::Keymap,
|
||||||
_compose_table: &xkb::compose::Table,
|
_compose_table: &xkb::compose::Table,
|
||||||
string: &str,
|
string: &str,
|
||||||
) -> Result<Vec<HidKeycodeWithMods, &'static EspHeap>, char> {
|
) -> Result<Vec<HidKeycodeWithMods, PsramAllocator>, char> {
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
struct KeycodeChoice {
|
struct KeycodeChoice {
|
||||||
mod_mask: ModMask,
|
mod_mask: ModMask,
|
||||||
|
|
|
||||||
373
firmware/acid-firmware/src/ram.rs
Normal file
373
firmware/acid-firmware/src/ram.rs
Normal file
|
|
@ -0,0 +1,373 @@
|
||||||
|
use embassy_time::Timer;
|
||||||
|
use esp_alloc::{HeapRegion, MemoryCapability};
|
||||||
|
use esp_hal::ram;
|
||||||
|
use log::{info, warn};
|
||||||
|
|
||||||
|
// Memory allocation regions.
|
||||||
|
// These can be debugged using `xtensa-esp32s3-elf-size -A <path-to-binary>`.
|
||||||
|
// A panic such as `memory allocation of 3740121773 bytes failed` is caused by a heap overflow. The size is `DEEDBAAD` in hex.
|
||||||
|
//
|
||||||
|
// RAM usage of static variables can be diagnosed with:
|
||||||
|
// ```sh
|
||||||
|
// xtensa-esp32s3-elf-nm.exe -S --size-sort -t d ../target/xtensa-esp32s3-none-elf/release/acid-firmware | grep -iE ' [dbv] ' | tail -n 10 | tac
|
||||||
|
// ```
|
||||||
|
|
||||||
|
/// Total heap size
|
||||||
|
pub const HEAP_SIZE: usize = 196 * 1024;
|
||||||
|
/// Size of the app core's stack
|
||||||
|
pub const STACK_SIZE_CORE_APP: usize = 80 * 1024;
|
||||||
|
|
||||||
|
pub static PSRAM_ALLOCATOR: esp_alloc::EspHeap = esp_alloc::EspHeap::empty();
|
||||||
|
pub type PsramAllocator = &'static esp_alloc::EspHeap;
|
||||||
|
|
||||||
|
pub fn initialize(psram_peripheral: esp_hal::peripherals::PSRAM) {
|
||||||
|
// Use the internal DRAM as the heap.
|
||||||
|
// Memory reclaimed from the esp-idf bootloader.
|
||||||
|
const HEAP_SIZE_RECLAIMED: usize = const {
|
||||||
|
let range = esp_metadata_generated::memory_range!("DRAM2_UNINIT");
|
||||||
|
range.end - range.start
|
||||||
|
};
|
||||||
|
|
||||||
|
esp_alloc::heap_allocator!(#[ram(reclaimed)] size: HEAP_SIZE_RECLAIMED);
|
||||||
|
esp_alloc::heap_allocator!(size: HEAP_SIZE - HEAP_SIZE_RECLAIMED);
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no-alloc-tracing"))]
|
||||||
|
alloc_tracing::install_ram_allocator_proxy();
|
||||||
|
|
||||||
|
info!(
|
||||||
|
"Internal RAM heap initialized!\n{}",
|
||||||
|
esp_alloc::HEAP.stats()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Initialize the PSRAM allocator.
|
||||||
|
{
|
||||||
|
let (psram_offset, psram_size) = esp_hal::psram::psram_raw_parts(&psram_peripheral);
|
||||||
|
unsafe {
|
||||||
|
PSRAM_ALLOCATOR.add_region(HeapRegion::new(
|
||||||
|
psram_offset,
|
||||||
|
psram_size,
|
||||||
|
MemoryCapability::External.into(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
info!(
|
||||||
|
"External PSRAM heap initialized with capacity of {} MiB!\n{}",
|
||||||
|
psram_size / 1024 / 1024,
|
||||||
|
PSRAM_ALLOCATOR.stats(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn run_alloc_stats_reporter() {
|
||||||
|
let mut psram_used_prev = 0;
|
||||||
|
let mut heap_used_prev = 0;
|
||||||
|
loop {
|
||||||
|
let psram_stats = PSRAM_ALLOCATOR.stats();
|
||||||
|
let heap_stats = esp_alloc::HEAP.stats();
|
||||||
|
if psram_stats.current_usage != psram_used_prev {
|
||||||
|
let difference = psram_stats.current_usage as isize - psram_used_prev as isize;
|
||||||
|
psram_used_prev = psram_stats.current_usage;
|
||||||
|
warn!(
|
||||||
|
"External PSRAM heap usage changed: {}{}\n{psram_stats}",
|
||||||
|
if difference < 0 { '-' } else { '+' },
|
||||||
|
difference.abs()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if heap_stats.current_usage != heap_used_prev {
|
||||||
|
let difference = heap_stats.current_usage as isize - heap_used_prev as isize;
|
||||||
|
heap_used_prev = heap_stats.current_usage;
|
||||||
|
warn!(
|
||||||
|
"Internal RAM heap usage changed: {}{}\n{heap_stats}",
|
||||||
|
if difference < 0 { '-' } else { '+' },
|
||||||
|
difference.abs()
|
||||||
|
);
|
||||||
|
#[cfg(not(feature = "no-alloc-tracing"))]
|
||||||
|
alloc_tracing::report_stats();
|
||||||
|
}
|
||||||
|
Timer::after_secs(1).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no-alloc-tracing"))]
|
||||||
|
mod alloc_tracing {
|
||||||
|
use core::{
|
||||||
|
alloc::GlobalAlloc,
|
||||||
|
cell::RefCell,
|
||||||
|
cmp::{Ordering, Reverse},
|
||||||
|
fmt::Display,
|
||||||
|
};
|
||||||
|
|
||||||
|
use alloc::collections::btree_map::BTreeMap;
|
||||||
|
use embassy_sync::blocking_mutex::{Mutex, raw::CriticalSectionRawMutex};
|
||||||
|
use esp_alloc::EspHeap;
|
||||||
|
use esp_backtrace::Backtrace;
|
||||||
|
use esp_sync::NonReentrantMutex;
|
||||||
|
use log::warn;
|
||||||
|
use tinyvec::ArrayVec;
|
||||||
|
|
||||||
|
use crate::ram::{PSRAM_ALLOCATOR, PsramAllocator};
|
||||||
|
|
||||||
|
#[derive(Default, Clone, PartialEq, Eq, Debug)]
|
||||||
|
struct Stats {
|
||||||
|
/// The total number of allocations.
|
||||||
|
allocations: usize,
|
||||||
|
/// The number of bytes allocated in total.
|
||||||
|
allocated_total: usize,
|
||||||
|
/// The number of bytes allocated minus the number of bytes deallocated.
|
||||||
|
allocated_current: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Stats {
|
||||||
|
fn update(&mut self, allocations_delta: isize, bytes_delta: isize, bytes_new: usize) {
|
||||||
|
self.allocations = (self.allocations as isize + allocations_delta) as usize;
|
||||||
|
self.allocated_total += bytes_new;
|
||||||
|
self.allocated_current = (self.allocated_current as isize + bytes_delta) as usize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialOrd for Stats {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for Stats {
|
||||||
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
|
self.allocated_current
|
||||||
|
.cmp(&other.allocated_current)
|
||||||
|
.then_with(|| self.allocated_total.cmp(&other.allocated_total).reverse())
|
||||||
|
.then_with(|| self.allocations.cmp(&other.allocations).reverse())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct BacktraceWrapper(Backtrace);
|
||||||
|
|
||||||
|
impl Display for BacktraceWrapper {
|
||||||
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
|
let mut it = self.0.frames().iter();
|
||||||
|
if let Some(frame) = it.next() {
|
||||||
|
write!(f, "0x{:08x}", frame.program_counter())?;
|
||||||
|
}
|
||||||
|
while let Some(frame) = it.next() {
|
||||||
|
write!(f, " 0x{:08x}", frame.program_counter())?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for BacktraceWrapper {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
if self.0.frames().len() != other.0.frames().len() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (lhs_frame, rhs_frame) in self.0.frames().iter().zip(other.0.frames()) {
|
||||||
|
if lhs_frame.program_counter() != rhs_frame.program_counter() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for BacktraceWrapper {}
|
||||||
|
|
||||||
|
impl PartialOrd for BacktraceWrapper {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for BacktraceWrapper {
|
||||||
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
|
let mut lhs_it = self.0.frames().iter().rev();
|
||||||
|
let mut rhs_it = other.0.frames().iter().rev();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
match (lhs_it.next(), rhs_it.next()) {
|
||||||
|
(Some(lhs_frame), Some(rhs_frame)) => {
|
||||||
|
let ordering = lhs_frame
|
||||||
|
.program_counter()
|
||||||
|
.cmp(&rhs_frame.program_counter());
|
||||||
|
|
||||||
|
if ordering != Ordering::Equal {
|
||||||
|
return ordering;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(Some(_), None) => return Ordering::Greater,
|
||||||
|
(None, Some(_)) => return Ordering::Less,
|
||||||
|
(None, None) => return Ordering::Equal,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct AllocationTracer {
|
||||||
|
bt_to_stats: BTreeMap<BacktraceWrapper, Stats, PsramAllocator>,
|
||||||
|
ptr_to_bt: BTreeMap<*mut u8, BacktraceWrapper, PsramAllocator>,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for AllocationTracer {}
|
||||||
|
|
||||||
|
impl AllocationTracer {
|
||||||
|
const fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
bt_to_stats: BTreeMap::new_in(&PSRAM_ALLOCATOR),
|
||||||
|
ptr_to_bt: BTreeMap::new_in(&PSRAM_ALLOCATOR),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn alloc(&mut self, bt: Backtrace, ptr: *mut u8, bytes: usize) {
|
||||||
|
let bt = BacktraceWrapper(bt.clone());
|
||||||
|
self.ptr_to_bt.insert(ptr, bt.clone());
|
||||||
|
let stats = self
|
||||||
|
.bt_to_stats
|
||||||
|
.entry(bt)
|
||||||
|
.or_insert_with(|| Default::default());
|
||||||
|
stats.update(1, bytes as isize, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn realloc(
|
||||||
|
&mut self,
|
||||||
|
ptr_old: *mut u8,
|
||||||
|
ptr_new: *mut u8,
|
||||||
|
bytes_old: usize,
|
||||||
|
bytes_new: usize,
|
||||||
|
) {
|
||||||
|
let bt = self.ptr_to_bt.remove(&ptr_old).unwrap();
|
||||||
|
self.ptr_to_bt.insert(ptr_new, bt.clone());
|
||||||
|
let stats = self.bt_to_stats.get_mut(&bt).unwrap();
|
||||||
|
stats.update(0, bytes_new as isize - bytes_old as isize, bytes_new);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dealloc(&mut self, ptr: *mut u8, bytes: usize) {
|
||||||
|
let bt = self.ptr_to_bt.remove(&ptr).unwrap();
|
||||||
|
let stats = self.bt_to_stats.get_mut(&bt).unwrap();
|
||||||
|
stats.update(-1, -(bytes as isize), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TracingAllocator<T: GlobalAlloc + 'static> {
|
||||||
|
inner: NonReentrantMutex<Option<&'static T>>,
|
||||||
|
tracer: Mutex<CriticalSectionRawMutex, RefCell<AllocationTracer>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> TracingAllocator<T>
|
||||||
|
where
|
||||||
|
T: GlobalAlloc,
|
||||||
|
{
|
||||||
|
const fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
inner: NonReentrantMutex::new(None),
|
||||||
|
tracer: Mutex::new(RefCell::new(AllocationTracer::new())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_inner<R>(&self, callback: impl FnOnce(&T) -> R) -> R {
|
||||||
|
self.inner.with(|inner| {
|
||||||
|
(callback)(
|
||||||
|
inner
|
||||||
|
.as_ref()
|
||||||
|
.expect("an allocator must be installed in the global allocator proxy"),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_with<R>(&self, callback: impl FnOnce(&mut AllocationTracer) -> R) -> R {
|
||||||
|
self.tracer
|
||||||
|
.lock(|tracer| (callback)(&mut tracer.borrow_mut()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<T> GlobalAlloc for TracingAllocator<T>
|
||||||
|
where
|
||||||
|
T: GlobalAlloc,
|
||||||
|
{
|
||||||
|
unsafe fn alloc(&self, layout: core::alloc::Layout) -> *mut u8 {
|
||||||
|
let bt = Backtrace::capture();
|
||||||
|
let ptr = self.with_inner(|inner| unsafe { inner.alloc(layout) });
|
||||||
|
self.update_with(|tracer| tracer.alloc(bt, ptr, layout.size()));
|
||||||
|
ptr
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn alloc_zeroed(&self, layout: core::alloc::Layout) -> *mut u8 {
|
||||||
|
let bt = Backtrace::capture();
|
||||||
|
let ptr = self.with_inner(|inner| unsafe { inner.alloc_zeroed(layout) });
|
||||||
|
self.update_with(|tracer| tracer.alloc(bt, ptr, layout.size()));
|
||||||
|
ptr
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn realloc(
|
||||||
|
&self,
|
||||||
|
ptr_old: *mut u8,
|
||||||
|
layout: core::alloc::Layout,
|
||||||
|
new_size: usize,
|
||||||
|
) -> *mut u8 {
|
||||||
|
let ptr_new =
|
||||||
|
self.with_inner(|inner| unsafe { inner.realloc(ptr_old, layout, new_size) });
|
||||||
|
self.update_with(|tracer| tracer.realloc(ptr_old, ptr_new, layout.size(), new_size));
|
||||||
|
ptr_new
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn dealloc(&self, ptr: *mut u8, layout: core::alloc::Layout) {
|
||||||
|
self.update_with(|tracer| tracer.dealloc(ptr, layout.size()));
|
||||||
|
self.with_inner(|inner| unsafe { inner.dealloc(ptr, layout) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[global_allocator]
|
||||||
|
static PROXY: TracingAllocator<EspHeap> = TracingAllocator::new();
|
||||||
|
|
||||||
|
pub fn install_ram_allocator_proxy() {
|
||||||
|
PROXY.inner.with(|inner| {
|
||||||
|
*inner = Some(&esp_alloc::HEAP);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn report_stats() {
|
||||||
|
let AllocationTracer {
|
||||||
|
bt_to_stats,
|
||||||
|
ptr_to_bt,
|
||||||
|
} = PROXY.tracer.lock(|tracer| tracer.borrow().clone());
|
||||||
|
// Wrapped in `Option` because of the `Default` requirement.
|
||||||
|
let mut sorted = ArrayVec::<[Option<(BacktraceWrapper, Reverse<Stats>)>; 5]>::new();
|
||||||
|
let bt_to_stats_len = bt_to_stats.len();
|
||||||
|
|
||||||
|
for (key, value) in bt_to_stats {
|
||||||
|
// Reverse ordering of stats because we are interested in the largest.
|
||||||
|
let value_rev = Reverse(value);
|
||||||
|
if let Some((_, value_last)) = sorted.last().and_then(|last| last.as_ref())
|
||||||
|
&& &value_rev >= value_last
|
||||||
|
&& sorted.len() >= sorted.capacity()
|
||||||
|
{
|
||||||
|
// This stat is not large enough to be inserted.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let index = match sorted.binary_search_by_key(&Some(&value_rev), |item| {
|
||||||
|
item.as_ref().map(|(_, current_value)| current_value)
|
||||||
|
}) {
|
||||||
|
Ok(index) => index,
|
||||||
|
Err(index) => index,
|
||||||
|
};
|
||||||
|
if sorted.len() >= sorted.capacity() {
|
||||||
|
assert!(
|
||||||
|
index < sorted.len(),
|
||||||
|
"the stat should be large enough to be inserted not at the end of the list"
|
||||||
|
);
|
||||||
|
let _ = sorted.pop().unwrap();
|
||||||
|
}
|
||||||
|
sorted.insert(index, Some((key, value_rev)));
|
||||||
|
}
|
||||||
|
|
||||||
|
warn!("Largest allocations in global allocator:");
|
||||||
|
|
||||||
|
for (index, (key, value)) in sorted.into_iter().map(Option::unwrap).enumerate() {
|
||||||
|
warn!("{}. {}\n{:#?}", index + 1, key, value.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
warn!("bt_to_stats.len() = {}", bt_to_stats_len);
|
||||||
|
warn!("ptr_to_bt.len() = {}", ptr_to_bt.len());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -7,8 +7,9 @@ use core::{
|
||||||
use alloc::{
|
use alloc::{
|
||||||
boxed::Box, collections::vec_deque::VecDeque, rc::Rc, string::ToString, sync::Arc, vec::Vec,
|
boxed::Box, collections::vec_deque::VecDeque, rc::Rc, string::ToString, sync::Arc, vec::Vec,
|
||||||
};
|
};
|
||||||
use critical_section::Mutex;
|
use embassy_sync::blocking_mutex::{self, raw::CriticalSectionRawMutex};
|
||||||
use esp_hal::time::Instant;
|
use esp_hal::time::Instant;
|
||||||
|
use esp_hal_bounce_buffers::SwapchainWriter;
|
||||||
use log::{debug, info};
|
use log::{debug, info};
|
||||||
use slint::{
|
use slint::{
|
||||||
EventLoopError, PhysicalSize, SharedString, WindowSize,
|
EventLoopError, PhysicalSize, SharedString, WindowSize,
|
||||||
|
|
@ -19,10 +20,7 @@ use slint::{
|
||||||
};
|
};
|
||||||
use xkbcommon::xkb::{self, Keysym};
|
use xkbcommon::xkb::{self, Keysym};
|
||||||
|
|
||||||
use crate::{
|
use crate::proxy::{KEY_MESSAGE_CHANNEL, TryFromKeysym};
|
||||||
proxy::{KEY_MESSAGE_CHANNEL, TryFromKeysym},
|
|
||||||
ui::dpi::SwapchainWriter,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::window_adapter::SoftwareWindowAdapter;
|
use super::window_adapter::SoftwareWindowAdapter;
|
||||||
|
|
||||||
|
|
@ -31,7 +29,9 @@ pub struct SlintBackend {
|
||||||
pub window: RefCell<Option<Rc<SoftwareWindowAdapter>>>,
|
pub window: RefCell<Option<Rc<SoftwareWindowAdapter>>>,
|
||||||
pub swapchain: RefCell<SwapchainWriter>,
|
pub swapchain: RefCell<SwapchainWriter>,
|
||||||
pub quit_event_loop: Arc<AtomicBool>,
|
pub quit_event_loop: Arc<AtomicBool>,
|
||||||
pub events: Arc<Mutex<RefCell<VecDeque<Box<dyn FnOnce() + Send>>>>>,
|
pub events: Arc<
|
||||||
|
blocking_mutex::Mutex<CriticalSectionRawMutex, RefCell<VecDeque<Box<dyn FnOnce() + Send>>>>,
|
||||||
|
>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl slint::platform::Platform for SlintBackend {
|
impl slint::platform::Platform for SlintBackend {
|
||||||
|
|
@ -68,13 +68,9 @@ impl slint::platform::Platform for SlintBackend {
|
||||||
|
|
||||||
/* loop */
|
/* loop */
|
||||||
{
|
{
|
||||||
let drained_events = critical_section::with(|cs| {
|
let drained_events = self
|
||||||
self.events
|
.events
|
||||||
.borrow(cs)
|
.lock(|events| events.borrow_mut().drain(..).collect::<Vec<_>>());
|
||||||
.borrow_mut()
|
|
||||||
.drain(..)
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
});
|
|
||||||
|
|
||||||
for event in drained_events {
|
for event in drained_events {
|
||||||
(event)();
|
(event)();
|
||||||
|
|
@ -135,7 +131,7 @@ impl slint::platform::Platform for SlintBackend {
|
||||||
// TODO: VSYNC support.
|
// TODO: VSYNC support.
|
||||||
let mut swapchain = self.swapchain.borrow_mut();
|
let mut swapchain = self.swapchain.borrow_mut();
|
||||||
let mut write_guard = swapchain.write();
|
let mut write_guard = swapchain.write();
|
||||||
let framebuffer = write_guard.cast::<Rgb565Pixel>();
|
let framebuffer = bytemuck::cast_slice_mut::<u8, Rgb565Pixel>(&mut write_guard);
|
||||||
renderer.render(framebuffer, self.window_size[1] as usize);
|
renderer.render(framebuffer, self.window_size[1] as usize);
|
||||||
info!("UI rendered.");
|
info!("UI rendered.");
|
||||||
});
|
});
|
||||||
|
|
@ -148,7 +144,9 @@ impl slint::platform::Platform for SlintBackend {
|
||||||
|
|
||||||
struct AcidEventLoopProxy {
|
struct AcidEventLoopProxy {
|
||||||
pub quit_event_loop: Arc<AtomicBool>,
|
pub quit_event_loop: Arc<AtomicBool>,
|
||||||
pub events: Arc<Mutex<RefCell<VecDeque<Box<dyn FnOnce() + Send>>>>>,
|
pub events: Arc<
|
||||||
|
blocking_mutex::Mutex<CriticalSectionRawMutex, RefCell<VecDeque<Box<dyn FnOnce() + Send>>>>,
|
||||||
|
>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventLoopProxy for AcidEventLoopProxy {
|
impl EventLoopProxy for AcidEventLoopProxy {
|
||||||
|
|
@ -161,8 +159,8 @@ impl EventLoopProxy for AcidEventLoopProxy {
|
||||||
&self,
|
&self,
|
||||||
event: Box<dyn FnOnce() + Send>,
|
event: Box<dyn FnOnce() + Send>,
|
||||||
) -> Result<(), EventLoopError> {
|
) -> Result<(), EventLoopError> {
|
||||||
critical_section::with(|cs| {
|
self.events.lock(|events| {
|
||||||
self.events.borrow(cs).borrow_mut().push_back(event);
|
events.borrow_mut().push_back(event);
|
||||||
});
|
});
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -36,6 +36,7 @@ use crate::{
|
||||||
},
|
},
|
||||||
ffi::{alloc::__spre_free, crypto::ACTIVE_ENCRYPTED_USER_KEY},
|
ffi::{alloc::__spre_free, crypto::ACTIVE_ENCRYPTED_USER_KEY},
|
||||||
proxy::OUTPUT_STRING_CHANNEL,
|
proxy::OUTPUT_STRING_CHANNEL,
|
||||||
|
ram::PsramAllocator,
|
||||||
ui::{
|
ui::{
|
||||||
backend::SlintBackend,
|
backend::SlintBackend,
|
||||||
messages::{
|
messages::{
|
||||||
|
|
@ -48,21 +49,27 @@ use crate::{
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod backend;
|
pub mod backend;
|
||||||
pub mod dpi;
|
|
||||||
pub mod messages;
|
pub mod messages;
|
||||||
pub mod storage;
|
pub mod storage;
|
||||||
pub mod window_adapter;
|
pub mod window_adapter;
|
||||||
|
|
||||||
slint::include_modules!();
|
slint::include_modules!();
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
struct EmptyPassword;
|
||||||
|
|
||||||
fn spectre_derive_user_key(
|
fn spectre_derive_user_key(
|
||||||
username: &CStr,
|
username: &CStr,
|
||||||
password: &CStr,
|
password: &CStr,
|
||||||
encrypted_key: Option<Key>,
|
encrypted_key: Option<Key>,
|
||||||
) -> SpectreUserKey {
|
) -> Result<SpectreUserKey, EmptyPassword> {
|
||||||
|
if password.is_empty() {
|
||||||
|
return Err(EmptyPassword);
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(encrypted_key) = encrypted_key {
|
if let Some(encrypted_key) = encrypted_key {
|
||||||
critical_section::with(|cs| {
|
ACTIVE_ENCRYPTED_USER_KEY.lock(|user_key| {
|
||||||
ACTIVE_ENCRYPTED_USER_KEY.borrow(cs).set(encrypted_key);
|
user_key.set(encrypted_key);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -84,7 +91,7 @@ fn spectre_derive_user_key(
|
||||||
// TODO: Erase memory before freeing
|
// TODO: Erase memory before freeing
|
||||||
__spre_free(user_key as *const _ as *mut _);
|
__spre_free(user_key as *const _ as *mut _);
|
||||||
|
|
||||||
user_key_stack
|
Ok(user_key_stack)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -131,7 +138,7 @@ pub async fn run_renderer_task(backend: SlintBackend, flash_part_acid: Partition
|
||||||
|
|
||||||
struct State {
|
struct State {
|
||||||
window: AppWindow,
|
window: AppWindow,
|
||||||
db: Rc<AcidDatabase>,
|
db: Rc<AcidDatabase, PsramAllocator>,
|
||||||
users: SpectreUsersConfig,
|
users: SpectreUsersConfig,
|
||||||
/// Currently active view.
|
/// Currently active view.
|
||||||
view: AppState,
|
view: AppState,
|
||||||
|
|
@ -143,20 +150,23 @@ struct State {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
async fn new(db: AcidDatabase, main: AppWindow) -> Rc<RefCell<Self>> {
|
async fn new(db: AcidDatabase, main: AppWindow) -> Rc<RefCell<Self>, PsramAllocator> {
|
||||||
let users = Self::load_users(&db).await;
|
let users = Self::load_users(&db).await;
|
||||||
let usernames = users.users.clone().map(|user| user.username);
|
let usernames = users.users.clone().map(|user| user.username);
|
||||||
|
|
||||||
let state = Rc::new(RefCell::new(State {
|
let state = Rc::new_in(
|
||||||
window: main.clone_strong(),
|
RefCell::new(State {
|
||||||
users,
|
window: main.clone_strong(),
|
||||||
db: Rc::new(db),
|
users,
|
||||||
view: AppState::Login,
|
db: Rc::new_in(db, &PSRAM_ALLOCATOR),
|
||||||
state_login: Default::default(),
|
view: AppState::Login,
|
||||||
state_users: Default::default(),
|
state_login: Default::default(),
|
||||||
state_user_edit: Default::default(),
|
state_users: Default::default(),
|
||||||
state_user_sites: Default::default(),
|
state_user_edit: Default::default(),
|
||||||
}));
|
state_user_sites: Default::default(),
|
||||||
|
}),
|
||||||
|
&PSRAM_ALLOCATOR,
|
||||||
|
);
|
||||||
|
|
||||||
main.on_enter_view({
|
main.on_enter_view({
|
||||||
let state = state.clone();
|
let state = state.clone();
|
||||||
|
|
@ -333,13 +343,18 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_callback_message(state_rc: &Rc<RefCell<State>>, message: CallbackMessage) {
|
fn process_callback_message(
|
||||||
|
state_rc: &Rc<RefCell<State>, PsramAllocator>,
|
||||||
|
mut message: CallbackMessage,
|
||||||
|
) {
|
||||||
let view = state_rc.borrow().view;
|
let view = state_rc.borrow().view;
|
||||||
match view {
|
while let Some(next_message) = match view {
|
||||||
AppState::Login => StateLogin::process_callback_message(state_rc, message),
|
AppState::Login => StateLogin::process_callback_message(state_rc, message),
|
||||||
AppState::Users => StateUsers::process_callback_message(state_rc, message),
|
AppState::Users => StateUsers::process_callback_message(state_rc, message),
|
||||||
AppState::UserEdit => StateUserEdit::process_callback_message(state_rc, message),
|
AppState::UserEdit => StateUserEdit::process_callback_message(state_rc, message),
|
||||||
AppState::UserSites => StateUserSites::process_callback_message(state_rc, message),
|
AppState::UserSites => StateUserSites::process_callback_message(state_rc, message),
|
||||||
|
} {
|
||||||
|
message = next_message
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -373,16 +388,8 @@ impl State {
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
slint::run_event_loop().unwrap();
|
slint::run_event_loop().unwrap();
|
||||||
// SIGNAL_LCD_SUBMIT.signal(());
|
|
||||||
#[cfg(feature = "limit-fps")]
|
#[cfg(feature = "limit-fps")]
|
||||||
embassy_time::Timer::after(FRAME_DURATION_MIN).await;
|
embassy_time::Timer::after(FRAME_DURATION_MIN).await;
|
||||||
// let frames_skipped = FRAMES_SKIPPED.wait().await;
|
|
||||||
|
|
||||||
// if frames_skipped > 0 {
|
|
||||||
// error!("Renderer missed {frames_skipped} frames.");
|
|
||||||
// }
|
|
||||||
|
|
||||||
// SIGNAL_UI_RENDER.wait().await;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(unreachable_code)]
|
#[expect(unreachable_code)]
|
||||||
|
|
@ -391,14 +398,22 @@ impl State {
|
||||||
}
|
}
|
||||||
|
|
||||||
trait AppViewTrait {
|
trait AppViewTrait {
|
||||||
fn process_callback_message(_state_rc: &Rc<RefCell<State>>, _message: CallbackMessage) {}
|
fn process_callback_message(
|
||||||
|
_state_rc: &Rc<RefCell<State>, PsramAllocator>,
|
||||||
|
_message: CallbackMessage,
|
||||||
|
) -> Option<CallbackMessage> {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct StateLogin {}
|
struct StateLogin {}
|
||||||
|
|
||||||
impl AppViewTrait for StateLogin {
|
impl AppViewTrait for StateLogin {
|
||||||
fn process_callback_message(state_rc: &Rc<RefCell<State>>, message: CallbackMessage) {
|
fn process_callback_message(
|
||||||
|
state_rc: &Rc<RefCell<State>, PsramAllocator>,
|
||||||
|
message: CallbackMessage,
|
||||||
|
) -> Option<CallbackMessage> {
|
||||||
let mut state = state_rc.borrow_mut();
|
let mut state = state_rc.borrow_mut();
|
||||||
match message {
|
match message {
|
||||||
CallbackMessage::Login(CallbackMessageLogin::PwAccepted {
|
CallbackMessage::Login(CallbackMessageLogin::PwAccepted {
|
||||||
|
|
@ -408,14 +423,18 @@ impl AppViewTrait for StateLogin {
|
||||||
}) => {
|
}) => {
|
||||||
let Some(user) = state.users.users.row_data(user_index as usize) else {
|
let Some(user) = state.users.users.row_data(user_index as usize) else {
|
||||||
error!("Failed to find a user with index {user_index}.");
|
error!("Failed to find a user with index {user_index}.");
|
||||||
return;
|
return None;
|
||||||
};
|
};
|
||||||
let username_c = CString::new(&*user.username)
|
let username_c = CString::new(&*user.username)
|
||||||
.expect("Username cannot be converted to a C string.");
|
.expect("Username cannot be converted to a C string.");
|
||||||
let password_c =
|
let password_c =
|
||||||
CString::new(&*password).expect("Password cannot be converted to a C string.");
|
CString::new(&*password).expect("Password cannot be converted to a C string.");
|
||||||
let user_key =
|
let Ok(user_key) =
|
||||||
spectre_derive_user_key(&username_c, &password_c, Some(user.encrypted_key));
|
spectre_derive_user_key(&username_c, &password_c, Some(user.encrypted_key))
|
||||||
|
else {
|
||||||
|
error!("Password empty.");
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
// {
|
// {
|
||||||
// let mut write = db.write_transaction().await;
|
// let mut write = db.write_transaction().await;
|
||||||
|
|
@ -454,14 +473,10 @@ impl AppViewTrait for StateLogin {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
if user.key_id != user_key.keyID.bytes {
|
if user.key_id != user_key.keyID.bytes {
|
||||||
State::process_callback_message(
|
return Some(CallbackMessage::Login(CallbackMessageLogin::LoginResult {
|
||||||
state_rc,
|
username: user.username,
|
||||||
CallbackMessage::Login(CallbackMessageLogin::LoginResult {
|
result: LoginResult::Failure,
|
||||||
username: user.username,
|
}));
|
||||||
result: LoginResult::Failure,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
slint::spawn_local({
|
slint::spawn_local({
|
||||||
|
|
@ -544,6 +559,8 @@ impl AppViewTrait for StateLogin {
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -551,7 +568,10 @@ impl AppViewTrait for StateLogin {
|
||||||
struct StateUsers {}
|
struct StateUsers {}
|
||||||
|
|
||||||
impl AppViewTrait for StateUsers {
|
impl AppViewTrait for StateUsers {
|
||||||
fn process_callback_message(state_rc: &Rc<RefCell<State>>, message: CallbackMessage) {
|
fn process_callback_message(
|
||||||
|
state_rc: &Rc<RefCell<State>, PsramAllocator>,
|
||||||
|
message: CallbackMessage,
|
||||||
|
) -> Option<CallbackMessage> {
|
||||||
let mut state = state_rc.borrow_mut();
|
let mut state = state_rc.borrow_mut();
|
||||||
match message {
|
match message {
|
||||||
CallbackMessage::Escape => {
|
CallbackMessage::Escape => {
|
||||||
|
|
@ -569,6 +589,8 @@ impl AppViewTrait for StateUsers {
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -581,7 +603,10 @@ struct StateUserEdit {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppViewTrait for StateUserEdit {
|
impl AppViewTrait for StateUserEdit {
|
||||||
fn process_callback_message(state_rc: &Rc<RefCell<State>>, message: CallbackMessage) {
|
fn process_callback_message(
|
||||||
|
state_rc: &Rc<RefCell<State>, PsramAllocator>,
|
||||||
|
message: CallbackMessage,
|
||||||
|
) -> Option<CallbackMessage> {
|
||||||
let state = state_rc.clone();
|
let state = state_rc.clone();
|
||||||
let mut state = state.borrow_mut();
|
let mut state = state.borrow_mut();
|
||||||
match message {
|
match message {
|
||||||
|
|
@ -619,7 +644,7 @@ impl AppViewTrait for StateUserEdit {
|
||||||
}) => {
|
}) => {
|
||||||
let Some(password) = state.state_user_edit.password.as_ref() else {
|
let Some(password) = state.state_user_edit.password.as_ref() else {
|
||||||
warn!("Attempted to compute a key ID when no password has been entered.");
|
warn!("Attempted to compute a key ID when no password has been entered.");
|
||||||
return;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut key: Key = [0; _];
|
let mut key: Key = [0; _];
|
||||||
|
|
@ -643,14 +668,18 @@ impl AppViewTrait for StateUserEdit {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
state.window.set_user_edit_key_error(message);
|
state.window.set_user_edit_key_error(message);
|
||||||
return;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let username_c = CString::new(&*state.state_user_edit.username)
|
let username_c = CString::new(&*state.state_user_edit.username)
|
||||||
.expect("Username cannot be converted to a C string.");
|
.expect("Username cannot be converted to a C string.");
|
||||||
let password_c =
|
let password_c =
|
||||||
CString::new(&**password).expect("Password cannot be converted to a C string.");
|
CString::new(&**password).expect("Password cannot be converted to a C string.");
|
||||||
let user_key = spectre_derive_user_key(&username_c, &password_c, Some(key));
|
let Ok(user_key) = spectre_derive_user_key(&username_c, &password_c, Some(key))
|
||||||
|
else {
|
||||||
|
error!("Password empty.");
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
state.window.set_user_edit_key_error(SharedString::new());
|
state.window.set_user_edit_key_error(SharedString::new());
|
||||||
state.window.set_user_edit_key_id(
|
state.window.set_user_edit_key_id(
|
||||||
|
|
@ -672,7 +701,7 @@ impl AppViewTrait for StateUserEdit {
|
||||||
)) = state.state_user_edit.encrypted_key.take()
|
)) = state.state_user_edit.encrypted_key.take()
|
||||||
else {
|
else {
|
||||||
warn!("Encrypted key is not set.");
|
warn!("Encrypted key is not set.");
|
||||||
return;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
// If a user with that username already exists, overwrite it.
|
// If a user with that username already exists, overwrite it.
|
||||||
|
|
@ -719,6 +748,8 @@ impl AppViewTrait for StateUserEdit {
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -731,7 +762,10 @@ struct StateUserSites {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppViewTrait for StateUserSites {
|
impl AppViewTrait for StateUserSites {
|
||||||
fn process_callback_message(state_rc: &Rc<RefCell<State>>, message: CallbackMessage) {
|
fn process_callback_message(
|
||||||
|
state_rc: &Rc<RefCell<State>, PsramAllocator>,
|
||||||
|
message: CallbackMessage,
|
||||||
|
) -> Option<CallbackMessage> {
|
||||||
let state = state_rc.clone();
|
let state = state_rc.clone();
|
||||||
let mut state = state.borrow_mut();
|
let mut state = state.borrow_mut();
|
||||||
match message {
|
match message {
|
||||||
|
|
@ -749,12 +783,12 @@ impl AppViewTrait for StateUserSites {
|
||||||
}) => {
|
}) => {
|
||||||
let Some(user_sites) = state.state_user_sites.as_mut() else {
|
let Some(user_sites) = state.state_user_sites.as_mut() else {
|
||||||
error!("User sites uninitialized.");
|
error!("User sites uninitialized.");
|
||||||
return;
|
return None;
|
||||||
};
|
};
|
||||||
let Some(site_list_entry) = user_sites.site_list.row_data(site_list_index as usize)
|
let Some(site_list_entry) = user_sites.site_list.row_data(site_list_index as usize)
|
||||||
else {
|
else {
|
||||||
error!("Invalid site list entry index: {site_list_index}");
|
error!("Invalid site list entry index: {site_list_index}");
|
||||||
return;
|
return None;
|
||||||
};
|
};
|
||||||
warn!("Site name accepted: {site_list_entry:?}");
|
warn!("Site name accepted: {site_list_entry:?}");
|
||||||
let site_name = match site_list_entry {
|
let site_name = match site_list_entry {
|
||||||
|
|
@ -795,6 +829,8 @@ impl AppViewTrait for StateUserSites {
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,9 @@
|
||||||
use core::fmt::Display;
|
use core::fmt::Display;
|
||||||
|
|
||||||
|
use embassy_sync::{
|
||||||
|
blocking_mutex::raw::RawMutex,
|
||||||
|
mutex::{Mutex, MutexGuard},
|
||||||
|
};
|
||||||
use embassy_time::Duration;
|
use embassy_time::Duration;
|
||||||
|
|
||||||
pub struct FormattedDuration<'a>(&'a Duration);
|
pub struct FormattedDuration<'a>(&'a Duration);
|
||||||
|
|
@ -46,3 +50,37 @@ pub const fn get_file_name(path: &str) -> &str {
|
||||||
Err(_) => panic!("Failed to extract the file name from a path."),
|
Err(_) => panic!("Failed to extract the file name from a path."),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub trait MutexExt<M, T> {
|
||||||
|
type Guard<'a>
|
||||||
|
where
|
||||||
|
M: 'a,
|
||||||
|
T: 'a,
|
||||||
|
Self: 'a;
|
||||||
|
|
||||||
|
/// Locks the mutex, while entering a critical section only during locking and unlocking.
|
||||||
|
///
|
||||||
|
/// # Safety:
|
||||||
|
/// * The guard must not be kept across async `yield` points.
|
||||||
|
/// * This must not be called from within interrupt handlers.
|
||||||
|
/// Otherwise, a deadlock might occur.
|
||||||
|
unsafe fn lock_blocking(&self) -> Self::Guard<'_>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<M: RawMutex, T> MutexExt<M, T> for Mutex<M, T> {
|
||||||
|
type Guard<'a>
|
||||||
|
= MutexGuard<'a, M, T>
|
||||||
|
where
|
||||||
|
M: 'a,
|
||||||
|
T: 'a,
|
||||||
|
Self: 'a;
|
||||||
|
|
||||||
|
unsafe fn lock_blocking(&self) -> Self::Guard<'_> {
|
||||||
|
loop {
|
||||||
|
if let Ok(guard) = self.try_lock() {
|
||||||
|
return guard;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue