feat: bachelor test impl
This commit is contained in:
parent
d0b0de550b
commit
061abd74b9
@ -5,8 +5,12 @@
|
||||
<sourceFolder url="file://$MODULE_DIR$/app/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/embedded-graphics-profiler-display/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/lvgl-based/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/slint-based/src" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/app/target" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/lvgl-based/target" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/slint-based/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
|
228
Cargo.lock
generated
228
Cargo.lock
generated
@ -4,9 +4,9 @@ version = 3
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.15"
|
||||
version = "0.6.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526"
|
||||
checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
@ -19,43 +19,43 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.8"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1"
|
||||
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.5"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb"
|
||||
checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.1.1"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a"
|
||||
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
|
||||
dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.4"
|
||||
version = "3.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8"
|
||||
checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.88"
|
||||
version = "1.0.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e1496f8fb1fbf272686b8d37f523dab3e4a7443300055e74cdaa449f3114356"
|
||||
checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775"
|
||||
|
||||
[[package]]
|
||||
name = "atomic"
|
||||
@ -77,9 +77,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.3.0"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
|
||||
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||
|
||||
[[package]]
|
||||
name = "az"
|
||||
@ -128,9 +128,9 @@ checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c"
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.18.0"
|
||||
version = "1.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94bbb0ad554ad961ddc5da507a12a29b14e4ae5bda06b19f575a3e6079d2e2ae"
|
||||
checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
@ -146,9 +146,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.17"
|
||||
version = "4.5.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e5a21b8495e732f1b3c364c9949b201ca7bae518c502c80256c96ad79eaf6ac"
|
||||
checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
@ -156,9 +156,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.17"
|
||||
version = "4.5.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8cf2dd12af7a047ad9d6da2b6b249759a22a7abc0f474c1dae1777afa4b21a73"
|
||||
checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@ -168,33 +168,33 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.13"
|
||||
version = "4.5.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0"
|
||||
checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.77",
|
||||
"syn 2.0.89",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.7.2"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
|
||||
checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.2"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0"
|
||||
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
|
||||
|
||||
[[package]]
|
||||
name = "critical-section"
|
||||
version = "1.1.3"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f64009896348fc5af4222e9cf7d7d82a95a256c634ebcf61c53e4ea461422242"
|
||||
checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
@ -217,7 +217,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"syn 2.0.77",
|
||||
"syn 2.0.89",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -228,7 +228,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn 2.0.77",
|
||||
"syn 2.0.89",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -239,7 +239,7 @@ checksum = "4e018fccbeeb50ff26562ece792ed06659b9c2dae79ece77c4456bb10d9bf79b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.77",
|
||||
"syn 2.0.89",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -288,9 +288,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "embassy-executor"
|
||||
version = "0.6.0"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09ed0e24bdd4a5f4ff1b72ee4f264b1d23e179ea71a77d984b5fd24877a2bbe1"
|
||||
checksum = "f64f84599b0f4296b92a4b6ac2109bc02340094bda47b9766c5f9ec6a318ebf8"
|
||||
dependencies = [
|
||||
"critical-section",
|
||||
"document-features",
|
||||
@ -300,14 +300,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "embassy-executor-macros"
|
||||
version = "0.5.0"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4d4c0c34b32c2c653c9eecce1cefaf8539dd9a54e61deb5499254f01e2fcac2"
|
||||
checksum = "3577b1e9446f61381179a330fc5324b01d511624c55f25e3c66c9e3c626dbecf"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.77",
|
||||
"syn 2.0.89",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -497,9 +497,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "embedded-sdmmc"
|
||||
version = "0.8.0"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "150f320125310e179b9e73b081173b349e63c5c7d4ca44db4e5b9121b10387ec"
|
||||
checksum = "eb637331040ec9b35f6a8151904d1aca914cc349d14c91b9a3e92ba789b22f3f"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"embedded-hal 1.0.0",
|
||||
@ -531,7 +531,7 @@ dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.77",
|
||||
"syn 2.0.89",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -552,7 +552,7 @@ dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.77",
|
||||
"syn 2.0.89",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -579,7 +579,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b94a4b8d74e7cc7baabcca5b2277b41877e039ad9cd49959d48ef94dac7eab4b"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn 2.0.77",
|
||||
"syn 2.0.89",
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
@ -659,7 +659,7 @@ dependencies = [
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.77",
|
||||
"syn 2.0.89",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -690,9 +690,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "esp-riscv-rt"
|
||||
version = "0.9.0"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfc32298ed7c263b06c8b031704d8517cc62c819f2a9d5c261d0cb119634d6e9"
|
||||
checksum = "94aca65db6157aa5f42d9df6595b21462f28207ca4230b799aa3620352ef6a72"
|
||||
dependencies = [
|
||||
"document-features",
|
||||
"riscv",
|
||||
@ -725,6 +725,12 @@ version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "foldhash"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2"
|
||||
|
||||
[[package]]
|
||||
name = "format_no_std"
|
||||
version = "1.2.0"
|
||||
@ -742,21 +748,21 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.30"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
|
||||
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.30"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
|
||||
checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.30"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
|
||||
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
@ -790,9 +796,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.5"
|
||||
version = "0.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3"
|
||||
|
||||
[[package]]
|
||||
name = "heapless"
|
||||
@ -834,9 +840,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.5.0"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5"
|
||||
checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
@ -880,10 +886,11 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "kolibri-embedded-gui"
|
||||
version = "0.0.0-alpha.1"
|
||||
source = "git+https://github.com/Yandrik/kolibri.git?branch=optimizations#f3e92212ac29431561748e6c37427651b3151bc4"
|
||||
source = "git+https://github.com/Yandrik/kolibri.git?branch=optimizations#ab04bf432d09eace365029e6420bf6e59ac8fc2f"
|
||||
dependencies = [
|
||||
"embedded-graphics",
|
||||
"embedded-iconoir",
|
||||
"foldhash",
|
||||
"heapless 0.7.17",
|
||||
]
|
||||
|
||||
@ -932,9 +939,9 @@ checksum = "c3c8dda44ff03a2f238717214da50f65d5a53b45cd213a7370424ffdb6fae815"
|
||||
|
||||
[[package]]
|
||||
name = "minijinja"
|
||||
version = "2.2.0"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d7d3e3a3eece1fa4618237ad41e1de855ced47eab705cec1c9a920e1d1c5aad"
|
||||
checksum = "2c37e1b517d1dcd0e51dc36c4567b9d5a29262b3ec8da6cb5d35e27a8fb529b5"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
@ -990,9 +997,9 @@ checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.14"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
|
||||
checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
@ -1002,9 +1009,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.7.0"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265"
|
||||
checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
@ -1041,9 +1048,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.86"
|
||||
version = "1.0.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
|
||||
checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@ -1080,23 +1087,43 @@ checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
|
||||
[[package]]
|
||||
name = "riscv"
|
||||
version = "0.11.1"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f5c1b8bf41ea746266cdee443d1d1e9125c86ce1447e1a2615abd34330d33a9"
|
||||
checksum = "5ea8ff73d3720bdd0a97925f0bf79ad2744b6da8ff36be3840c48ac81191d7a7"
|
||||
dependencies = [
|
||||
"critical-section",
|
||||
"embedded-hal 1.0.0",
|
||||
"paste",
|
||||
"riscv-macros",
|
||||
"riscv-pac",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "riscv-rt-macros"
|
||||
version = "0.2.1"
|
||||
name = "riscv-macros"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8d100d466dbb76681ef6a9386f3da9abc570d57394e86da0ba5af8c4408486d"
|
||||
checksum = "f265be5d634272320a7de94cea15c22a3bfdd4eb42eb43edc528415f066a1f25"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
"syn 2.0.89",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "riscv-pac"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8188909339ccc0c68cfb5a04648313f09621e8b87dc03095454f1a11f6c5d436"
|
||||
|
||||
[[package]]
|
||||
name = "riscv-rt-macros"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30f19a85fe107b65031e0ba8ec60c34c2494069fe910d6c297f5e7cb5a6f76d0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.89",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1110,9 +1137,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.17"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
|
||||
checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
@ -1122,9 +1149,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "semihosting"
|
||||
version = "0.1.14"
|
||||
version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e11f0f8bcc4088e72905fcd826b820e72de6113218c22f1734cd94a3a5cf9172"
|
||||
checksum = "a5c5996e5d1dec34b0dff3285e27124e70964504e3fd361bce330dc476cebafd"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
@ -1134,29 +1161,29 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.210"
|
||||
version = "1.0.215"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
|
||||
checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.210"
|
||||
version = "1.0.215"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
|
||||
checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.77",
|
||||
"syn 2.0.89",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "0.6.7"
|
||||
version = "0.6.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d"
|
||||
checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
@ -1216,7 +1243,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn 2.0.77",
|
||||
"syn 2.0.89",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1232,9 +1259,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.77"
|
||||
version = "2.0.89"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
|
||||
checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -1273,9 +1300,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.22.20"
|
||||
version = "0.22.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d"
|
||||
checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde",
|
||||
@ -1313,9 +1340,9 @@ checksum = "e87a2ed6b42ec5e28cc3b94c09982969e9227600b2e3dcbc1db927a84c06bd69"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.13"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
|
||||
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
@ -1347,16 +1374,7 @@ version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
||||
dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1434,9 +1452,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.6.18"
|
||||
version = "0.6.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f"
|
||||
checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
@ -1464,9 +1482,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "xtensa-lx-rt"
|
||||
version = "0.17.1"
|
||||
version = "0.17.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2ceb69c1487b78d83531c5d94fb81d0dceef1ccb0affba29f29420b1f72d3ddb"
|
||||
checksum = "5c0307d03dadbf95633942e13901984f2059df4c963367348168cbd21c962669"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bare-metal",
|
||||
@ -1490,5 +1508,5 @@ dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.77",
|
||||
"syn 2.0.89",
|
||||
]
|
||||
|
@ -19,6 +19,9 @@ path = "src/bin/xpt.rs"
|
||||
name = "calibrate"
|
||||
path = "src/bin/calibrate.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "light-control"
|
||||
|
||||
[lib]
|
||||
|
||||
[dependencies]
|
||||
|
19
app/rustfmt.toml
Normal file
19
app/rustfmt.toml
Normal file
@ -0,0 +1,19 @@
|
||||
# Edition
|
||||
edition = "2021"
|
||||
|
||||
# Comments
|
||||
format_code_in_doc_comments = true
|
||||
normalize_comments = true
|
||||
wrap_comments = true
|
||||
|
||||
# Imports
|
||||
group_imports = "StdExternalCrate"
|
||||
imports_granularity = "Crate"
|
||||
imports_layout = "HorizontalVertical"
|
||||
|
||||
# Miscellaneous
|
||||
enum_discrim_align_threshold = 25
|
||||
hex_literal_case = "Upper"
|
||||
|
||||
# Length
|
||||
max_width=60
|
@ -1,6 +1,8 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use core::{cell::RefCell, cmp::min, fmt};
|
||||
|
||||
use display_interface_spi::SPIInterface;
|
||||
@ -42,6 +44,7 @@ use kolibri_embedded_gui::{
|
||||
style::medsize_rgb565_style,
|
||||
ui::{Interaction, Ui},
|
||||
};
|
||||
use lvgl::{self, Display, DrawBuffer};
|
||||
use mipidsi::{
|
||||
models::ILI9486Rgb565,
|
||||
options::{ColorInversion, ColorOrder, Orientation, Rotation},
|
||||
@ -50,6 +53,19 @@ use mipidsi::{
|
||||
use static_cell::StaticCell;
|
||||
use xpt2046::Xpt2046;
|
||||
|
||||
// fn init_heap() {
|
||||
// const HEAP_SIZE: usize = 32 * 1024;
|
||||
// static mut HEAP: MaybeUninit<[u8; HEAP_SIZE]> = MaybeUninit::uninit();
|
||||
//
|
||||
// unsafe {
|
||||
// esp_alloc::HEAP.add_region(esp_alloc::HeapRegion::new(
|
||||
// HEAP.as_mut_ptr() as *mut u8,
|
||||
// HEAP_SIZE,
|
||||
// esp_alloc::MemoryCapability::Internal.into(),
|
||||
// ));
|
||||
// }
|
||||
// }
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn touch_task(
|
||||
touch_irq: GpioPin<36>,
|
||||
@ -235,10 +251,10 @@ async fn main(spawner: Spawner) {
|
||||
|
||||
let mut display = ProfilerDisplay::new(display);
|
||||
|
||||
{
|
||||
let mut ui = Ui::new_fullscreen(&mut display, medsize_rgb565_style());
|
||||
ui.clear_background().ok();
|
||||
}
|
||||
const HOR_RES: u32 = 320;
|
||||
const VER_RES: u32 = 240;
|
||||
lvgl::init();
|
||||
{}
|
||||
backlight.set_high();
|
||||
|
||||
// init touchscreen pins
|
||||
@ -287,6 +303,7 @@ async fn main(spawner: Spawner) {
|
||||
|
||||
// Periodically feed the RWDT watchdog timer when our tasks are not running:
|
||||
let mut sm = SmartstateProvider::<20>::new();
|
||||
|
||||
loop {
|
||||
// SMART REDRAWING ENABLE / DISABLE
|
||||
// sm.force_redraw_all();
|
||||
@ -383,7 +400,7 @@ async fn main(spawner: Spawner) {
|
||||
.add_horizontal(IconButton::new(size32px::actions::AddCircle).smartstate(sm.next()))
|
||||
.clicked()
|
||||
{
|
||||
if !(appdata.timer_running() || appdata.timer_paused()) {
|
||||
if !appdata.timer_running() {
|
||||
appdata.add_secs(10);
|
||||
}
|
||||
}
|
||||
@ -392,7 +409,7 @@ async fn main(spawner: Spawner) {
|
||||
.add(IconButton::new(size32px::actions::MinusCircle).smartstate(sm.next()))
|
||||
.clicked()
|
||||
{
|
||||
if !(appdata.timer_running() || appdata.timer_paused()) {
|
||||
if !appdata.timer_running() {
|
||||
appdata.sub_secs(10);
|
||||
}
|
||||
}
|
516
app/src/bin/exapp-slint-timer.rs
Normal file
516
app/src/bin/exapp-slint-timer.rs
Normal file
@ -0,0 +1,516 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use core::{cell::RefCell, cmp::min, fmt};
|
||||
|
||||
use display_interface_spi::SPIInterface;
|
||||
use embassy_embedded_hal::shared_bus::blocking::spi::SpiDevice;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_sync::{
|
||||
blocking_mutex::{raw::NoopRawMutex, NoopMutex},
|
||||
signal::Signal,
|
||||
};
|
||||
use embassy_time::{Duration, Instant, Timer};
|
||||
use embedded_graphics::{
|
||||
mono_font::ascii,
|
||||
pixelcolor::Rgb565,
|
||||
prelude::{DrawTarget, Point, RgbColor, Size, WebColors},
|
||||
};
|
||||
use embedded_graphics_profiler_display::ProfilerDisplay;
|
||||
use esp_backtrace as _;
|
||||
use esp_hal::{
|
||||
clock::ClockControl,
|
||||
gpio::{GpioPin, Input, Io, Level, Output, Pull, NO_PIN},
|
||||
peripherals::{Peripherals, SPI2, SPI3},
|
||||
prelude::*,
|
||||
rtc_cntl::Rtc,
|
||||
spi::{master::Spi, FullDuplexMode, SpiMode},
|
||||
system::SystemControl,
|
||||
timer::timg::TimerGroup,
|
||||
};
|
||||
use esp_println::println;
|
||||
use kolibri_cyd_tester_app_embassy::Debouncer;
|
||||
use kolibri_embedded_gui::{
|
||||
button::Button,
|
||||
checkbox::Checkbox,
|
||||
icon::IconWidget,
|
||||
iconbutton::IconButton,
|
||||
icons::{size12px, size24px, size32px, size48px, size96px},
|
||||
label::Label,
|
||||
smartstate::SmartstateProvider,
|
||||
spacer::Spacer,
|
||||
style::medsize_rgb565_style,
|
||||
ui::{Interaction, Ui},
|
||||
};
|
||||
use mipidsi::{
|
||||
models::ILI9486Rgb565,
|
||||
options::{ColorInversion, ColorOrder, Orientation, Rotation},
|
||||
Builder,
|
||||
};
|
||||
use slint::platform::software_renderer::MinimalSoftwareWindow;
|
||||
use static_cell::StaticCell;
|
||||
use xpt2046::Xpt2046;
|
||||
|
||||
slint::include_modules!();
|
||||
|
||||
use esp_alloc as _;
|
||||
|
||||
fn init_heap() {
|
||||
const HEAP_SIZE: usize = 32 * 1024;
|
||||
static mut HEAP: MaybeUninit<[u8; HEAP_SIZE]> = MaybeUninit::uninit();
|
||||
|
||||
unsafe {
|
||||
esp_alloc::HEAP.add_region(esp_alloc::HeapRegion::new(
|
||||
HEAP.as_mut_ptr() as *mut u8,
|
||||
HEAP_SIZE,
|
||||
esp_alloc::MemoryCapability::Internal.into(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn touch_task(
|
||||
touch_irq: GpioPin<36>,
|
||||
spi: &'static mut NoopMutex<RefCell<Spi<'static, SPI3, FullDuplexMode>>>,
|
||||
touch_cs: GpioPin<33>,
|
||||
touch_signal: &'static Signal<NoopRawMutex, Option<Point>>,
|
||||
) -> ! {
|
||||
let mut touch_driver = Xpt2046::new(
|
||||
SpiDevice::new(spi, Output::new(touch_cs, Level::Low)),
|
||||
Input::new(touch_irq, Pull::Up),
|
||||
xpt2046::Orientation::LandscapeFlipped,
|
||||
);
|
||||
touch_driver.set_num_samples(16);
|
||||
touch_driver.init(&mut embassy_time::Delay).unwrap();
|
||||
|
||||
println!("touch task");
|
||||
|
||||
loop {
|
||||
touch_driver.run().expect("Running Touch driver failed");
|
||||
if touch_driver.is_touched() {
|
||||
let point = touch_driver.get_touch_point();
|
||||
touch_signal.signal(Some(Point::new(point.x + 25, 240 - point.y)));
|
||||
} else {
|
||||
touch_signal.signal(None);
|
||||
}
|
||||
Timer::after(Duration::from_millis(1)).await; // 100 a second
|
||||
|
||||
// Your touch handling logic here
|
||||
}
|
||||
}
|
||||
|
||||
struct AppData {
|
||||
timer_start: Instant,
|
||||
timer_set_duration: Duration,
|
||||
timer_remaining_duration: Duration,
|
||||
timer_running: bool,
|
||||
timer_paused: bool,
|
||||
}
|
||||
|
||||
impl AppData {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
timer_start: Instant::now(),
|
||||
timer_set_duration: Duration::from_secs(10),
|
||||
timer_remaining_duration: Duration::from_secs(10),
|
||||
timer_running: false,
|
||||
timer_paused: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn set_timer_duration(&mut self, duration: Duration) {
|
||||
self.timer_set_duration = duration;
|
||||
}
|
||||
|
||||
fn add_secs(&mut self, secs: u64) {
|
||||
self.set_timer_duration(
|
||||
self.timer_set_duration
|
||||
.checked_add(Duration::from_secs(secs))
|
||||
.unwrap_or(Duration::from_secs(5999))
|
||||
.min(Duration::from_secs(5999)),
|
||||
);
|
||||
}
|
||||
|
||||
fn sub_secs(&mut self, secs: u64) {
|
||||
self.set_timer_duration(
|
||||
self.timer_set_duration
|
||||
.checked_sub(Duration::from_secs(secs))
|
||||
.unwrap_or(Duration::from_secs(10))
|
||||
.max(Duration::from_secs(10)),
|
||||
);
|
||||
}
|
||||
|
||||
fn start_timer(&mut self) {
|
||||
if !self.timer_paused {
|
||||
self.timer_remaining_duration = self.timer_set_duration;
|
||||
}
|
||||
|
||||
self.timer_start = Instant::now();
|
||||
self.timer_running = true;
|
||||
self.timer_paused = false;
|
||||
}
|
||||
|
||||
fn pause_timer(&mut self) {
|
||||
self.timer_paused = true;
|
||||
self.timer_remaining_duration = self
|
||||
.timer_remaining_duration
|
||||
.checked_sub(self.timer_start.elapsed())
|
||||
.unwrap_or(Duration::from_secs(0));
|
||||
}
|
||||
|
||||
fn reset_timer(&mut self) {
|
||||
self.timer_start = Instant::now();
|
||||
self.timer_paused = false;
|
||||
self.timer_running = false;
|
||||
self.timer_remaining_duration = self.timer_set_duration;
|
||||
}
|
||||
|
||||
fn remaining(&self) -> Duration {
|
||||
if self.timer_stopped() {
|
||||
self.timer_set_duration
|
||||
} else if self.timer_paused() {
|
||||
self.timer_remaining_duration
|
||||
} else {
|
||||
self.timer_remaining_duration
|
||||
.checked_sub(self.timer_start.elapsed())
|
||||
.unwrap_or(Duration::from_secs(0))
|
||||
}
|
||||
}
|
||||
|
||||
fn timer_stopped(&self) -> bool {
|
||||
!self.timer_running
|
||||
}
|
||||
|
||||
fn timer_paused(&self) -> bool {
|
||||
self.timer_running && self.timer_paused
|
||||
}
|
||||
|
||||
fn timer_running(&self) -> bool {
|
||||
self.timer_running && !self.timer_paused
|
||||
}
|
||||
|
||||
fn timer_finished(&self) -> bool {
|
||||
self.timer_running && self.remaining() == Duration::from_secs(0)
|
||||
}
|
||||
}
|
||||
|
||||
struct MyPlatform {
|
||||
window: Rc<MinimalSoftwareWindow>,
|
||||
}
|
||||
|
||||
impl Platform for MyPlatform {
|
||||
fn create_window_adapter(&self) -> Result<Rc<dyn slint::platform::WindowAdapter>, slint::PlatformError> {
|
||||
// Since on MCUs, there can be only one window, just return a clone of self.window.
|
||||
// We'll also use the same window in the event loop.
|
||||
Ok(self.window.clone())
|
||||
}
|
||||
fn duration_since_start(&self) -> core::time::Duration {
|
||||
core::time::Duration::from_micros(self.timer.get_time())
|
||||
}
|
||||
// optional: You can put the event loop there, or in the main function, see later
|
||||
fn run_event_loop(&self) -> Result<(), slint::PlatformError> {
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
|
||||
#[main]
|
||||
async fn main(spawner: Spawner) {
|
||||
|
||||
init_heap();
|
||||
|
||||
let peripherals = Peripherals::take();
|
||||
let system = SystemControl::new(peripherals.SYSTEM);
|
||||
let mut clocks = ClockControl::boot_defaults(system.clock_control).freeze();
|
||||
|
||||
// Enable the RWDT watchdog timer:
|
||||
let mut rtc = Rtc::new(peripherals.LPWR);
|
||||
rtc.rwdt.set_timeout(2.secs());
|
||||
rtc.rwdt.enable();
|
||||
println!("RWDT watchdog enabled!");
|
||||
|
||||
// Initialize the SYSTIMER peripheral, and then Embassy:
|
||||
let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks);
|
||||
esp_hal_embassy::init(&clocks, timg0.timer0);
|
||||
println!("Embassy initialized!");
|
||||
|
||||
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
// let mut led = Output::new(io.pins.gpio5, Level::High);
|
||||
// Initialize SPI
|
||||
let sclk = io.pins.gpio14;
|
||||
let miso = io.pins.gpio12;
|
||||
let mosi = io.pins.gpio13;
|
||||
let cs = io.pins.gpio15;
|
||||
let dc = io.pins.gpio2;
|
||||
let mut backlight = Output::new(io.pins.gpio21, Level::Low);
|
||||
|
||||
// Note: RST is not initialized as it's set to -1 in the instructions
|
||||
|
||||
// up to 80MHz is possible (even tho the display driver isn't supposed to be
|
||||
// that fast) Dataseheet sais 10MHz, so we're gonna go with that
|
||||
let mut spi = Spi::new(peripherals.SPI2, 10.MHz(), SpiMode::Mode0, &mut clocks).with_pins(
|
||||
Some(sclk),
|
||||
Some(mosi),
|
||||
Some(miso),
|
||||
NO_PIN,
|
||||
);
|
||||
|
||||
static DISP_SPI_BUS: StaticCell<NoopMutex<RefCell<Spi<SPI2, FullDuplexMode>>>> =
|
||||
StaticCell::new();
|
||||
let spi_bus = NoopMutex::new(RefCell::new(spi));
|
||||
let spi_bus = DISP_SPI_BUS.init(spi_bus);
|
||||
|
||||
let di = SPIInterface::new(
|
||||
SpiDevice::new(spi_bus, Output::new(cs, Level::Low)),
|
||||
Output::new(dc, Level::Low),
|
||||
);
|
||||
let display = Builder::new(ILI9486Rgb565, di)
|
||||
.orientation(Orientation {
|
||||
rotation: Rotation::Deg90,
|
||||
mirrored: true,
|
||||
})
|
||||
.color_order(ColorOrder::Bgr)
|
||||
.invert_colors(ColorInversion::Inverted)
|
||||
.init(&mut embassy_time::Delay)
|
||||
.unwrap();
|
||||
|
||||
let mut display = ProfilerDisplay::new(display);
|
||||
|
||||
let window = MinimalSoftwareWindow::new(Default::default());
|
||||
slint::platform::set_platform(Box::new(MyPlatform {
|
||||
window: window.clone(),
|
||||
//...
|
||||
}))
|
||||
.unwrap();
|
||||
|
||||
let ui =
|
||||
|
||||
|
||||
backlight.set_high();
|
||||
|
||||
// init touchscreen pins
|
||||
let touch_irq = io.pins.gpio36;
|
||||
let touch_mosi = io.pins.gpio32;
|
||||
let touch_miso = io.pins.gpio39;
|
||||
let touch_clk = io.pins.gpio25;
|
||||
let touch_cs = io.pins.gpio33;
|
||||
|
||||
// 2MHz is the MAX! DO NOT DECREASE! This is really important.
|
||||
let mut touch_spi = Spi::new(peripherals.SPI3, 2.MHz(), SpiMode::Mode0, &mut clocks).with_pins(
|
||||
Some(touch_clk),
|
||||
Some(touch_mosi),
|
||||
Some(touch_miso),
|
||||
NO_PIN,
|
||||
);
|
||||
static TOUCH_SPI_BUS: StaticCell<NoopMutex<RefCell<Spi<SPI3, FullDuplexMode>>>> =
|
||||
StaticCell::new();
|
||||
let touch_spi_bus = NoopMutex::new(RefCell::new(touch_spi));
|
||||
let touch_spi_bus = TOUCH_SPI_BUS.init(touch_spi_bus);
|
||||
|
||||
let touch_signal = Signal::new();
|
||||
static TOUCH_SIGNAL: StaticCell<Signal<NoopRawMutex, Option<Point>>> = StaticCell::new();
|
||||
let touch_signal = &*TOUCH_SIGNAL.init(touch_signal);
|
||||
|
||||
spawner
|
||||
.spawn(touch_task(touch_irq, touch_spi_bus, touch_cs, touch_signal))
|
||||
.unwrap();
|
||||
|
||||
// TODO: Spawn some tasks
|
||||
let _ = spawner;
|
||||
|
||||
// variables
|
||||
let mut appdata = AppData::new();
|
||||
let (mut prev_mins, mut prev_secs, mut prev_millis) = (0, 0, 0);
|
||||
let mut finished = false;
|
||||
|
||||
// touchpoints
|
||||
|
||||
let mut last_touch = None;
|
||||
|
||||
static BUF_CELL: StaticCell<[Rgb565; 100 * 100]> = StaticCell::new();
|
||||
let buf = BUF_CELL.init([Rgb565::BLACK; 100 * 100]);
|
||||
|
||||
let mut textbuf = [0u8; 64];
|
||||
|
||||
// Periodically feed the RWDT watchdog timer when our tasks are not running:
|
||||
let mut sm = SmartstateProvider::<20>::new();
|
||||
loop {
|
||||
// SMART REDRAWING ENABLE / DISABLE
|
||||
// sm.force_redraw_all();
|
||||
|
||||
let start_time = embassy_time::Instant::now();
|
||||
sm.restart_counter();
|
||||
let mut ui = Ui::new_fullscreen(&mut display, medsize_rgb565_style());
|
||||
if let Some(touch) = touch_signal.try_take() {
|
||||
let interact = match (touch, last_touch) {
|
||||
(Some(point), Some(_)) => Interaction::Drag(point),
|
||||
(Some(point), None) => Interaction::Click(point),
|
||||
(None, Some(point)) => Interaction::Release(point),
|
||||
(None, None) => Interaction::None,
|
||||
};
|
||||
ui.interact(interact);
|
||||
// println!("{:?}, {:?}, {:?}", last_touch, touch, interact);
|
||||
|
||||
last_touch = touch;
|
||||
}
|
||||
|
||||
// BUFFER ENABLE/DISABLE
|
||||
ui.set_buffer(buf);
|
||||
|
||||
let start_draw_time = embassy_time::Instant::now();
|
||||
ui.sub_ui(|ui| {
|
||||
ui.style_mut().default_font = ascii::FONT_9X18_BOLD;
|
||||
ui.add(Label::new("Kolibri Timer App").smartstate(sm.next()));
|
||||
Ok(())
|
||||
})
|
||||
.ok();
|
||||
|
||||
let remaining = appdata.remaining();
|
||||
|
||||
ui.add(Spacer::new(Size::new(0, 60)));
|
||||
ui.add_horizontal(Spacer::new(Size::new(80, 0)));
|
||||
ui.sub_ui(|ui| {
|
||||
ui.style_mut().default_font = ascii::FONT_10X20;
|
||||
if remaining.as_secs() / 60 != prev_mins {
|
||||
sm.peek().force_redraw();
|
||||
prev_mins = remaining.as_secs() / 60;
|
||||
}
|
||||
ui.add_horizontal(
|
||||
Label::new(
|
||||
&format_no_std::show(
|
||||
&mut textbuf,
|
||||
format_args!("{:02}", remaining.as_secs() / 60),
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
.smartstate(sm.next()),
|
||||
);
|
||||
ui.add_horizontal(Label::new(":").smartstate(sm.next()));
|
||||
|
||||
if remaining.as_secs() % 60 != prev_secs {
|
||||
sm.peek().force_redraw();
|
||||
prev_secs = remaining.as_secs() % 60;
|
||||
}
|
||||
ui.add_horizontal(
|
||||
Label::new(
|
||||
&format_no_std::show(
|
||||
&mut textbuf,
|
||||
format_args!("{:02}", remaining.as_secs() % 60),
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
.smartstate(sm.next()),
|
||||
);
|
||||
ui.add_horizontal(Label::new(":").smartstate(sm.next()));
|
||||
|
||||
if remaining.as_millis() % 1000 != prev_millis {
|
||||
sm.peek().force_redraw();
|
||||
prev_millis = remaining.as_millis() % 1000;
|
||||
}
|
||||
ui.add(
|
||||
Label::new(
|
||||
&format_no_std::show(
|
||||
&mut textbuf,
|
||||
format_args!("{:03}", remaining.as_millis() % 1000),
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
.smartstate(sm.next()),
|
||||
);
|
||||
Ok(())
|
||||
})
|
||||
.ok();
|
||||
|
||||
ui.add_horizontal(Spacer::new(Size::new(65, 0)));
|
||||
ui.sub_ui(|ui| {
|
||||
if appdata.timer_running() {
|
||||
ui.style_mut().icon_color = Rgb565::CSS_LIGHT_GRAY;
|
||||
}
|
||||
if ui
|
||||
.add_horizontal(IconButton::new(size32px::actions::AddCircle).smartstate(sm.next()))
|
||||
.clicked()
|
||||
{
|
||||
if !appdata.timer_running() {
|
||||
appdata.add_secs(10);
|
||||
}
|
||||
}
|
||||
ui.add_horizontal(Label::new("+/- 10s").smartstate(sm.next()));
|
||||
if ui
|
||||
.add(IconButton::new(size32px::actions::MinusCircle).smartstate(sm.next()))
|
||||
.clicked()
|
||||
{
|
||||
if !appdata.timer_running() {
|
||||
appdata.sub_secs(10);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
.ok();
|
||||
|
||||
ui.add_horizontal(Spacer::new(Size::new(80, 0)));
|
||||
if ui
|
||||
.add_horizontal(IconButton::new(size48px::actions::Undo).smartstate(sm.next()))
|
||||
.clicked()
|
||||
{
|
||||
appdata.reset_timer();
|
||||
sm.force_redraw_all();
|
||||
}
|
||||
|
||||
if !finished && appdata.timer_finished() {
|
||||
sm.peek().force_redraw();
|
||||
}
|
||||
|
||||
if appdata.timer_finished() {
|
||||
if ui
|
||||
.add_horizontal(
|
||||
IconButton::new(size48px::actions::RemoveSquare).smartstate(sm.next()),
|
||||
)
|
||||
.clicked()
|
||||
{
|
||||
appdata.reset_timer();
|
||||
sm.force_redraw_all();
|
||||
}
|
||||
} else if appdata.timer_running() {
|
||||
if ui
|
||||
.add_horizontal(IconButton::new(size48px::music::Pause).smartstate(sm.next()))
|
||||
.clicked()
|
||||
{
|
||||
appdata.pause_timer();
|
||||
sm.force_redraw_all();
|
||||
}
|
||||
} else {
|
||||
if ui
|
||||
.add_horizontal(IconButton::new(size48px::music::Play).smartstate(sm.next()))
|
||||
.clicked()
|
||||
{
|
||||
appdata.start_timer();
|
||||
sm.force_redraw_all();
|
||||
}
|
||||
}
|
||||
|
||||
finished = appdata.timer_finished();
|
||||
|
||||
let end_time = embassy_time::Instant::now();
|
||||
let draw_time = display.get_time();
|
||||
let prep_time = start_draw_time - start_time;
|
||||
let proc_time = end_time - start_draw_time;
|
||||
let proc_time = proc_time - min(draw_time, proc_time);
|
||||
rtc.rwdt.feed();
|
||||
|
||||
if draw_time.as_micros() > 0 {
|
||||
println!(
|
||||
"draw time: {}.{:03}ms | prep time: {}.{:03}ms | proc time: {}.{:03}ms | total time: {}.{:03}ms",
|
||||
draw_time.as_millis(),
|
||||
draw_time.as_micros() % 100,
|
||||
prep_time.as_millis(),
|
||||
prep_time.as_micros() % 100,
|
||||
proc_time.as_millis(),
|
||||
proc_time.as_micros() % 100,
|
||||
(draw_time + prep_time + proc_time).as_millis(),
|
||||
(draw_time + prep_time + proc_time).as_micros() % 100, );
|
||||
}
|
||||
display.reset_time();
|
||||
Timer::after(Duration::from_millis(17)).await; // 60 a second
|
||||
}
|
||||
}
|
453
app/src/bin/light-control.rs
Normal file
453
app/src/bin/light-control.rs
Normal file
@ -0,0 +1,453 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use core::{cell::RefCell, cmp::min, str::FromStr};
|
||||
|
||||
use display_interface_spi::SPIInterface;
|
||||
use embassy_embedded_hal::shared_bus::blocking::spi::SpiDevice;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_sync::{
|
||||
blocking_mutex::{raw::NoopRawMutex, NoopMutex},
|
||||
signal::Signal,
|
||||
};
|
||||
use embassy_time::{Duration, Timer};
|
||||
use embedded_graphics::{
|
||||
mono_font::ascii,
|
||||
pixelcolor::Rgb565,
|
||||
prelude::{Point, RgbColor, Size, WebColors},
|
||||
};
|
||||
use embedded_graphics_profiler_display::ProfilerDisplay;
|
||||
use esp_backtrace as _;
|
||||
use esp_hal::{
|
||||
clock::ClockControl,
|
||||
gpio::{
|
||||
GpioPin,
|
||||
Input,
|
||||
Io,
|
||||
Level,
|
||||
Output,
|
||||
Pull,
|
||||
NO_PIN,
|
||||
},
|
||||
peripherals::{Peripherals, SPI2, SPI3},
|
||||
prelude::*,
|
||||
rtc_cntl::Rtc,
|
||||
spi::{master::Spi, FullDuplexMode, SpiMode},
|
||||
system::SystemControl,
|
||||
timer::timg::TimerGroup,
|
||||
};
|
||||
use esp_println::println;
|
||||
use kolibri_embedded_gui::{
|
||||
iconbutton::IconButton,
|
||||
icons::size32px,
|
||||
label::{HashLabel, Hasher, Label},
|
||||
slider::Slider,
|
||||
smartstate::SmartstateProvider,
|
||||
spacer::Spacer,
|
||||
style::medsize_rgb565_style,
|
||||
toggle_switch::ToggleSwitch,
|
||||
ui::{Interaction, Ui},
|
||||
};
|
||||
use mipidsi::{
|
||||
models::ILI9341Rgb565,
|
||||
options::{ColorOrder, Orientation, Rotation},
|
||||
Builder,
|
||||
};
|
||||
use static_cell::StaticCell;
|
||||
use xpt2046::Xpt2046;
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn touch_task(
|
||||
touch_irq: GpioPin<36>,
|
||||
spi: &'static mut NoopMutex<
|
||||
RefCell<Spi<'static, SPI3, FullDuplexMode>>,
|
||||
>,
|
||||
touch_cs: GpioPin<33>,
|
||||
touch_signal: &'static Signal<
|
||||
NoopRawMutex,
|
||||
Option<Point>,
|
||||
>,
|
||||
) -> ! {
|
||||
let mut touch_driver = Xpt2046::new(
|
||||
SpiDevice::new(
|
||||
spi,
|
||||
Output::new(touch_cs, Level::Low),
|
||||
),
|
||||
Input::new(touch_irq, Pull::Up),
|
||||
xpt2046::Orientation::LandscapeFlipped,
|
||||
);
|
||||
touch_driver.set_num_samples(16);
|
||||
touch_driver.init(&mut embassy_time::Delay).unwrap();
|
||||
|
||||
println!("touch task");
|
||||
|
||||
loop {
|
||||
touch_driver
|
||||
.run()
|
||||
.expect("Running Touch driver failed");
|
||||
if touch_driver.is_touched() {
|
||||
let point = touch_driver.get_touch_point();
|
||||
touch_signal.signal(Some(Point::new(
|
||||
point.x + 25,
|
||||
240 - point.y,
|
||||
)));
|
||||
} else {
|
||||
touch_signal.signal(None);
|
||||
}
|
||||
Timer::after(Duration::from_millis(1)).await; // 100
|
||||
// a second
|
||||
|
||||
// Your touch handling logic here
|
||||
}
|
||||
}
|
||||
|
||||
fn lerp_fixed(start: u8, end: u8, t: u8, max_t: u8) -> u8 {
|
||||
let (start, end, t, max_t) =
|
||||
(start as u16, end as u16, t as u16, max_t as u16);
|
||||
let t = t.min(max_t);
|
||||
let result = start
|
||||
+ ((end - start.min(end)) * t + (max_t / 2))
|
||||
/ max_t;
|
||||
result as u8
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Lamp {
|
||||
pub name: heapless::String<64>,
|
||||
pub on: bool,
|
||||
pub brightness: i16,
|
||||
}
|
||||
|
||||
impl Lamp {
|
||||
pub fn new(name: &str) -> Self {
|
||||
Self {
|
||||
name: heapless::String::from_str(name).unwrap(),
|
||||
on: false,
|
||||
brightness: 255,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum Page {
|
||||
Home,
|
||||
LampCtrl(usize),
|
||||
}
|
||||
struct AppData {
|
||||
lamps: heapless::Vec<Lamp, 8>,
|
||||
}
|
||||
|
||||
impl AppData {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
lamps: heapless::Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn add_lamp(&mut self, name: &str) {
|
||||
self.lamps.push(Lamp::new(name)).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[main]
|
||||
async fn main(spawner: Spawner) {
|
||||
let peripherals = Peripherals::take();
|
||||
let system = SystemControl::new(peripherals.SYSTEM);
|
||||
let mut clocks =
|
||||
ClockControl::boot_defaults(system.clock_control)
|
||||
.freeze();
|
||||
|
||||
// Enable the RWDT watchdog timer:
|
||||
let mut rtc = Rtc::new(peripherals.LPWR);
|
||||
rtc.rwdt.set_timeout(2.secs());
|
||||
rtc.rwdt.enable();
|
||||
println!("RWDT watchdog enabled!");
|
||||
|
||||
// Initialize the SYSTIMER peripheral, and then Embassy:
|
||||
let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks);
|
||||
esp_hal_embassy::init(&clocks, timg0.timer0);
|
||||
println!("Embassy initialized!");
|
||||
|
||||
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
// let mut led = Output::new(io.pins.gpio5,
|
||||
// Level::High); Initialize SPI
|
||||
let sclk = io.pins.gpio14;
|
||||
let miso = io.pins.gpio12;
|
||||
let mosi = io.pins.gpio13;
|
||||
let cs = io.pins.gpio15;
|
||||
let dc = io.pins.gpio2;
|
||||
let mut backlight =
|
||||
Output::new(io.pins.gpio21, Level::Low);
|
||||
|
||||
// Note: RST is not initialized as it's set to -1 in the
|
||||
// instructions
|
||||
|
||||
// up to 80MHz is possible (even tho the display driver
|
||||
// isn't supposed to be that fast) Dataseheet sais
|
||||
// 10MHz, so we're gonna go with that
|
||||
let mut spi = Spi::new(
|
||||
peripherals.SPI2,
|
||||
10.MHz(),
|
||||
SpiMode::Mode0,
|
||||
&mut clocks,
|
||||
)
|
||||
.with_pins(
|
||||
Some(sclk),
|
||||
Some(mosi),
|
||||
Some(miso),
|
||||
NO_PIN,
|
||||
);
|
||||
|
||||
static DISP_SPI_BUS: StaticCell<
|
||||
NoopMutex<RefCell<Spi<SPI2, FullDuplexMode>>>,
|
||||
> = StaticCell::new();
|
||||
let spi_bus = NoopMutex::new(RefCell::new(spi));
|
||||
let spi_bus = DISP_SPI_BUS.init(spi_bus);
|
||||
|
||||
let di = SPIInterface::new(
|
||||
SpiDevice::new(
|
||||
spi_bus,
|
||||
Output::new(cs, Level::Low),
|
||||
),
|
||||
Output::new(dc, Level::Low),
|
||||
);
|
||||
let display = Builder::new(ILI9341Rgb565, di)
|
||||
.orientation(Orientation {
|
||||
rotation: Rotation::Deg90,
|
||||
mirrored: true,
|
||||
})
|
||||
.color_order(ColorOrder::Bgr)
|
||||
// .invert_colors(ColorInversion::Inverted)
|
||||
.init(&mut embassy_time::Delay)
|
||||
.unwrap();
|
||||
|
||||
let mut display = ProfilerDisplay::new(display);
|
||||
let style = medsize_rgb565_style();
|
||||
|
||||
{
|
||||
let mut ui =
|
||||
Ui::new_fullscreen(&mut display, style);
|
||||
ui.clear_background().ok();
|
||||
}
|
||||
backlight.set_high();
|
||||
|
||||
// init touchscreen pins
|
||||
let touch_irq = io.pins.gpio36;
|
||||
let touch_mosi = io.pins.gpio32;
|
||||
let touch_miso = io.pins.gpio39;
|
||||
let touch_clk = io.pins.gpio25;
|
||||
let touch_cs = io.pins.gpio33;
|
||||
|
||||
// 2MHz is the MAX! DO NOT DECREASE! This is really
|
||||
// important.
|
||||
let mut touch_spi = Spi::new(
|
||||
peripherals.SPI3,
|
||||
2.MHz(),
|
||||
SpiMode::Mode0,
|
||||
&mut clocks,
|
||||
)
|
||||
.with_pins(
|
||||
Some(touch_clk),
|
||||
Some(touch_mosi),
|
||||
Some(touch_miso),
|
||||
NO_PIN,
|
||||
);
|
||||
static TOUCH_SPI_BUS: StaticCell<
|
||||
NoopMutex<RefCell<Spi<SPI3, FullDuplexMode>>>,
|
||||
> = StaticCell::new();
|
||||
let touch_spi_bus =
|
||||
NoopMutex::new(RefCell::new(touch_spi));
|
||||
let touch_spi_bus = TOUCH_SPI_BUS.init(touch_spi_bus);
|
||||
|
||||
let touch_signal = Signal::new();
|
||||
static TOUCH_SIGNAL: StaticCell<
|
||||
Signal<NoopRawMutex, Option<Point>>,
|
||||
> = StaticCell::new();
|
||||
let touch_signal = &*TOUCH_SIGNAL.init(touch_signal);
|
||||
|
||||
spawner
|
||||
.spawn(touch_task(
|
||||
touch_irq,
|
||||
touch_spi_bus,
|
||||
touch_cs,
|
||||
touch_signal,
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
// TODO: Spawn some tasks
|
||||
let _ = spawner;
|
||||
|
||||
// variables
|
||||
let mut appdata = AppData::new();
|
||||
|
||||
appdata.add_lamp("Front Door");
|
||||
appdata.add_lamp("Living Room");
|
||||
// appdata.lamps[1].on = true;
|
||||
appdata.add_lamp("Bedroom");
|
||||
// appdata.lamps[2].on = true;
|
||||
appdata.add_lamp("Bathroom");
|
||||
appdata.add_lamp("Porch");
|
||||
|
||||
let mut cur_page = Page::Home;
|
||||
|
||||
// touchpoints
|
||||
|
||||
let mut last_touch = None;
|
||||
|
||||
static BUF_CELL: StaticCell<[Rgb565; 200 * 100]> =
|
||||
StaticCell::new();
|
||||
let buf = BUF_CELL.init([Rgb565::BLACK; 200 * 100]);
|
||||
|
||||
let mut textbuf = [0u8; 64];
|
||||
let hasher = Hasher::new();
|
||||
|
||||
// Periodically feed the RWDT watchdog timer when our
|
||||
// tasks are not running:
|
||||
let mut sm = SmartstateProvider::<20>::new();
|
||||
loop {
|
||||
// SMART REDRAWING ENABLE / DISABLE
|
||||
// sm.force_redraw_all();
|
||||
|
||||
let start_time = embassy_time::Instant::now();
|
||||
sm.restart_counter();
|
||||
let mut ui =
|
||||
Ui::new_fullscreen(&mut display, style);
|
||||
if let Some(touch) = touch_signal.try_take() {
|
||||
let interact = match (touch, last_touch) {
|
||||
(Some(point), Some(_)) => {
|
||||
Interaction::Drag(point)
|
||||
}
|
||||
(Some(point), None) => {
|
||||
Interaction::Click(point)
|
||||
}
|
||||
(None, Some(point)) => {
|
||||
Interaction::Release(point)
|
||||
}
|
||||
(None, None) => Interaction::None,
|
||||
};
|
||||
ui.interact(interact);
|
||||
// println!("{:?}, {:?}, {:?}", last_touch,
|
||||
// touch, interact);
|
||||
|
||||
last_touch = touch;
|
||||
}
|
||||
|
||||
// BUFFER ENABLE/DISABLE
|
||||
ui.set_buffer(buf);
|
||||
|
||||
let start_draw_time = embassy_time::Instant::now();
|
||||
if let Page::Home = cur_page {
|
||||
ui.add_centered(
|
||||
HashLabel::new(
|
||||
"Light Control App (Kolibri)",
|
||||
sm.next(),
|
||||
&hasher,
|
||||
)
|
||||
// .smartstate(sm.next())
|
||||
.with_font(ascii::FONT_9X18_BOLD),
|
||||
);
|
||||
}
|
||||
|
||||
match cur_page {
|
||||
Page::Home => {
|
||||
for (i, lamp) in
|
||||
appdata.lamps.iter().enumerate()
|
||||
{
|
||||
let mut break_loop = false;
|
||||
ui.sub_ui(|ui| {
|
||||
ui.style_mut().icon_color = if lamp.on {
|
||||
Rgb565::CSS_GOLD
|
||||
} else {
|
||||
Rgb565::WHITE
|
||||
};
|
||||
if ui
|
||||
.add_horizontal(
|
||||
IconButton::new(size32px::home::LightBulb)
|
||||
.label(lamp.name.as_str())
|
||||
.smartstate(sm.next()),
|
||||
)
|
||||
.clicked()
|
||||
{
|
||||
cur_page = Page::LampCtrl(i);
|
||||
ui.clear_background().ok();
|
||||
sm.force_redraw_all();
|
||||
break_loop = true;
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
.ok();
|
||||
if break_loop {
|
||||
break;
|
||||
}
|
||||
if i % 3 == 2 {
|
||||
ui.new_row();
|
||||
}
|
||||
}
|
||||
}
|
||||
Page::LampCtrl(lamp) => {
|
||||
let lamp = &mut appdata.lamps[lamp];
|
||||
if ui
|
||||
.add_horizontal(
|
||||
IconButton::new(size32px::navigation::NavArrowLeft).smartstate(sm.next()),
|
||||
)
|
||||
.clicked()
|
||||
{
|
||||
cur_page = Page::Home;
|
||||
ui.clear_background().ok();
|
||||
sm.force_redraw_all();
|
||||
continue;
|
||||
}
|
||||
ui.add_horizontal(Spacer::new(Size::new(
|
||||
30, 0,
|
||||
)));
|
||||
ui.add(
|
||||
Label::new(lamp.name.as_str())
|
||||
.smartstate(sm.next())
|
||||
.with_font(ascii::FONT_9X18_BOLD),
|
||||
);
|
||||
ui.add(Spacer::new(Size::new(0, 20)));
|
||||
ui.add_centered(
|
||||
Slider::new(
|
||||
&mut lamp.brightness,
|
||||
0..=255,
|
||||
)
|
||||
.width(300)
|
||||
.label("Brightness")
|
||||
.smartstate(sm.next()),
|
||||
);
|
||||
ui.add(Spacer::new(Size::new(0, 10)));
|
||||
ui.add_centered(
|
||||
ToggleSwitch::new(&mut lamp.on)
|
||||
.smartstate(sm.next()),
|
||||
);
|
||||
ui.add_centered(
|
||||
Label::new("Turn on/off")
|
||||
.smartstate(sm.next()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let end_time = embassy_time::Instant::now();
|
||||
let draw_time = display.get_time();
|
||||
let prep_time = start_draw_time - start_time;
|
||||
let proc_time = end_time - start_draw_time;
|
||||
let proc_time =
|
||||
proc_time - min(draw_time, proc_time);
|
||||
rtc.rwdt.feed();
|
||||
|
||||
if draw_time.as_micros() > 0 {
|
||||
println!(
|
||||
"draw time: {}.{:03}ms | prep time: {}.{:03}ms | proc time: {}.{:03}ms | total time: {}.{:03}ms",
|
||||
draw_time.as_millis(),
|
||||
draw_time.as_micros() % 100,
|
||||
prep_time.as_millis(),
|
||||
prep_time.as_micros() % 100,
|
||||
proc_time.as_millis(),
|
||||
proc_time.as_micros() % 100,
|
||||
(draw_time + prep_time + proc_time).as_millis(),
|
||||
(draw_time + prep_time + proc_time).as_micros() % 100, );
|
||||
}
|
||||
display.reset_time();
|
||||
Timer::after(Duration::from_millis(17)).await; // 60
|
||||
// a second
|
||||
}
|
||||
}
|
669
app/src/bin/microwave-ui.rs
Normal file
669
app/src/bin/microwave-ui.rs
Normal file
@ -0,0 +1,669 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use core::{cell::RefCell, cmp::min};
|
||||
|
||||
use display_interface_spi::SPIInterface;
|
||||
use embassy_embedded_hal::shared_bus::blocking::spi::SpiDevice;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_sync::{
|
||||
blocking_mutex::{raw::NoopRawMutex, NoopMutex},
|
||||
signal::Signal,
|
||||
};
|
||||
use embassy_time::{Duration, Instant, Timer};
|
||||
use embedded_graphics::{
|
||||
mono_font::ascii,
|
||||
pixelcolor::Rgb565,
|
||||
prelude::{Point, RgbColor, Size, WebColors},
|
||||
};
|
||||
use embedded_graphics_profiler_display::ProfilerDisplay;
|
||||
use esp_hal::{
|
||||
clock::ClockControl,
|
||||
gpio::{
|
||||
GpioPin,
|
||||
Input,
|
||||
Io,
|
||||
Level,
|
||||
Output,
|
||||
Pull,
|
||||
NO_PIN,
|
||||
},
|
||||
peripherals::{Peripherals, SPI2, SPI3},
|
||||
prelude::*,
|
||||
rtc_cntl::Rtc,
|
||||
spi::{master::Spi, FullDuplexMode, SpiMode},
|
||||
system::SystemControl,
|
||||
timer::timg::TimerGroup,
|
||||
};
|
||||
use esp_println::println;
|
||||
use kolibri_embedded_gui::{
|
||||
iconbutton::IconButton,
|
||||
icons::{size32px, size48px},
|
||||
label::{HashLabel, Hasher, Label},
|
||||
smartstate::SmartstateProvider,
|
||||
spacer::Spacer,
|
||||
style::medsize_rgb565_style,
|
||||
ui::{Interaction, Ui},
|
||||
};
|
||||
use mipidsi::{
|
||||
models::ILI9341Rgb565,
|
||||
options::{ColorOrder, Orientation, Rotation},
|
||||
Builder,
|
||||
};
|
||||
use static_cell::StaticCell;
|
||||
use xpt2046::Xpt2046;
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn touch_task(
|
||||
touch_irq: GpioPin<36>,
|
||||
spi: &'static mut NoopMutex<
|
||||
RefCell<Spi<'static, SPI3, FullDuplexMode>>,
|
||||
>,
|
||||
touch_cs: GpioPin<33>,
|
||||
touch_signal: &'static Signal<
|
||||
NoopRawMutex,
|
||||
Option<Point>,
|
||||
>,
|
||||
) -> ! {
|
||||
let mut touch_driver = Xpt2046::new(
|
||||
SpiDevice::new(
|
||||
spi,
|
||||
Output::new(touch_cs, Level::Low),
|
||||
),
|
||||
Input::new(touch_irq, Pull::Up),
|
||||
xpt2046::Orientation::LandscapeFlipped,
|
||||
);
|
||||
touch_driver.set_num_samples(16);
|
||||
touch_driver.init(&mut embassy_time::Delay).unwrap();
|
||||
|
||||
println!("touch task");
|
||||
|
||||
loop {
|
||||
touch_driver
|
||||
.run()
|
||||
.expect("Running Touch driver failed");
|
||||
if touch_driver.is_touched() {
|
||||
let point = touch_driver.get_touch_point();
|
||||
touch_signal.signal(Some(Point::new(
|
||||
point.x + 25,
|
||||
240 - point.y,
|
||||
)));
|
||||
} else {
|
||||
touch_signal.signal(None);
|
||||
}
|
||||
Timer::after(Duration::from_millis(1)).await; // 100
|
||||
// a second
|
||||
|
||||
// Your touch handling logic here
|
||||
}
|
||||
}
|
||||
|
||||
struct AppData {
|
||||
timer_start: Instant,
|
||||
timer_set_duration: Duration,
|
||||
timer_remaining_duration: Duration,
|
||||
timer_running: bool,
|
||||
timer_paused: bool,
|
||||
wattage_level: u8,
|
||||
}
|
||||
|
||||
impl AppData {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
timer_start: Instant::now(),
|
||||
timer_set_duration: Duration::from_secs(10),
|
||||
timer_remaining_duration: Duration::from_secs(
|
||||
10,
|
||||
),
|
||||
timer_running: false,
|
||||
timer_paused: false,
|
||||
wattage_level: 5,
|
||||
}
|
||||
}
|
||||
|
||||
fn set_timer_duration(&mut self, duration: Duration) {
|
||||
self.timer_set_duration = duration;
|
||||
}
|
||||
|
||||
fn add_secs(&mut self, secs: u64) {
|
||||
self.set_timer_duration(
|
||||
self.timer_set_duration
|
||||
.checked_add(Duration::from_secs(secs))
|
||||
.unwrap_or(Duration::from_secs(5999))
|
||||
.min(Duration::from_secs(5999)),
|
||||
);
|
||||
}
|
||||
|
||||
fn sub_secs(&mut self, secs: u64) {
|
||||
self.set_timer_duration(
|
||||
self.timer_set_duration
|
||||
.checked_sub(Duration::from_secs(secs))
|
||||
.unwrap_or(Duration::from_secs(10))
|
||||
.max(Duration::from_secs(10)),
|
||||
);
|
||||
}
|
||||
|
||||
fn start_timer(&mut self) {
|
||||
if !self.timer_paused {
|
||||
self.timer_remaining_duration =
|
||||
self.timer_set_duration;
|
||||
}
|
||||
|
||||
self.timer_start = Instant::now();
|
||||
self.timer_running = true;
|
||||
self.timer_paused = false;
|
||||
}
|
||||
|
||||
fn pause_timer(&mut self) {
|
||||
self.timer_paused = true;
|
||||
self.timer_remaining_duration = self
|
||||
.timer_remaining_duration
|
||||
.checked_sub(self.timer_start.elapsed())
|
||||
.unwrap_or(Duration::from_secs(0));
|
||||
}
|
||||
|
||||
fn reset_timer(&mut self) {
|
||||
self.timer_start = Instant::now();
|
||||
self.timer_paused = false;
|
||||
self.timer_running = false;
|
||||
self.timer_remaining_duration =
|
||||
self.timer_set_duration;
|
||||
}
|
||||
|
||||
fn remaining(&self) -> Duration {
|
||||
if self.timer_stopped() {
|
||||
self.timer_set_duration
|
||||
} else if self.timer_paused() {
|
||||
self.timer_remaining_duration
|
||||
} else {
|
||||
self.timer_remaining_duration
|
||||
.checked_sub(self.timer_start.elapsed())
|
||||
.unwrap_or(Duration::from_secs(0))
|
||||
}
|
||||
}
|
||||
|
||||
fn timer_stopped(&self) -> bool {
|
||||
!self.timer_running
|
||||
}
|
||||
|
||||
fn timer_paused(&self) -> bool {
|
||||
self.timer_running && self.timer_paused
|
||||
}
|
||||
|
||||
fn timer_running(&self) -> bool {
|
||||
self.timer_running && !self.timer_paused
|
||||
}
|
||||
|
||||
fn timer_finished(&self) -> bool {
|
||||
self.timer_running
|
||||
&& self.remaining() == Duration::from_secs(0)
|
||||
}
|
||||
|
||||
fn set_wattage_level(&mut self, level: u8) {
|
||||
assert!(
|
||||
level < 6,
|
||||
"wattage level cannot be over 6"
|
||||
);
|
||||
self.wattage_level = level;
|
||||
}
|
||||
|
||||
fn get_wattage_level_str(&self) -> &'static str {
|
||||
match self.wattage_level {
|
||||
0 => "180W",
|
||||
1 => "220W",
|
||||
2 => "360W",
|
||||
3 => "480W",
|
||||
4 => "620W",
|
||||
5 => "800W",
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[main]
|
||||
async fn main(spawner: Spawner) {
|
||||
let peripherals = Peripherals::take();
|
||||
let system = SystemControl::new(peripherals.SYSTEM);
|
||||
let mut clocks =
|
||||
ClockControl::boot_defaults(system.clock_control)
|
||||
.freeze();
|
||||
|
||||
// Enable the RWDT watchdog timer:
|
||||
let mut rtc = Rtc::new(peripherals.LPWR);
|
||||
rtc.rwdt.set_timeout(2.secs());
|
||||
rtc.rwdt.enable();
|
||||
println!("RWDT watchdog enabled!");
|
||||
|
||||
// Initialize the SYSTIMER peripheral, and then Embassy:
|
||||
let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks);
|
||||
esp_hal_embassy::init(&clocks, timg0.timer0);
|
||||
println!("Embassy initialized!");
|
||||
|
||||
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
// let mut led = Output::new(io.pins.gpio5,
|
||||
// Level::High); Initialize SPI
|
||||
let sclk = io.pins.gpio14;
|
||||
let miso = io.pins.gpio12;
|
||||
let mosi = io.pins.gpio13;
|
||||
let cs = io.pins.gpio15;
|
||||
let dc = io.pins.gpio2;
|
||||
let mut backlight =
|
||||
Output::new(io.pins.gpio21, Level::Low);
|
||||
|
||||
// Note: RST is not initialized as it's set to -1 in the
|
||||
// instructions
|
||||
|
||||
// up to 80MHz is possible (even tho the display driver
|
||||
// isn't supposed to be that fast) Dataseheet sais
|
||||
// 10MHz, so we're gonna go with that
|
||||
let mut spi = Spi::new(
|
||||
peripherals.SPI2,
|
||||
10.MHz(),
|
||||
SpiMode::Mode0,
|
||||
&mut clocks,
|
||||
)
|
||||
.with_pins(
|
||||
Some(sclk),
|
||||
Some(mosi),
|
||||
Some(miso),
|
||||
NO_PIN,
|
||||
);
|
||||
|
||||
static DISP_SPI_BUS: StaticCell<
|
||||
NoopMutex<RefCell<Spi<SPI2, FullDuplexMode>>>,
|
||||
> = StaticCell::new();
|
||||
let spi_bus = NoopMutex::new(RefCell::new(spi));
|
||||
let spi_bus = DISP_SPI_BUS.init(spi_bus);
|
||||
|
||||
let di = SPIInterface::new(
|
||||
SpiDevice::new(
|
||||
spi_bus,
|
||||
Output::new(cs, Level::Low),
|
||||
),
|
||||
Output::new(dc, Level::Low),
|
||||
);
|
||||
|
||||
let display = Builder::new(ILI9341Rgb565, di)
|
||||
.orientation(Orientation {
|
||||
rotation: Rotation::Deg90,
|
||||
mirrored: true,
|
||||
})
|
||||
.color_order(ColorOrder::Bgr)
|
||||
// .invert_colors(ColorInversion::Inverted)
|
||||
.init(&mut embassy_time::Delay)
|
||||
.unwrap();
|
||||
|
||||
let mut display = ProfilerDisplay::new(display);
|
||||
|
||||
{
|
||||
let mut ui = Ui::new_fullscreen(
|
||||
&mut display,
|
||||
medsize_rgb565_style(),
|
||||
);
|
||||
ui.clear_background().ok();
|
||||
}
|
||||
backlight.set_high();
|
||||
|
||||
// init touchscreen pins
|
||||
let touch_irq = io.pins.gpio36;
|
||||
let touch_mosi = io.pins.gpio32;
|
||||
let touch_miso = io.pins.gpio39;
|
||||
let touch_clk = io.pins.gpio25;
|
||||
let touch_cs = io.pins.gpio33;
|
||||
|
||||
// 2MHz is the MAX! DO NOT DECREASE! This is really
|
||||
// important.
|
||||
let mut touch_spi = Spi::new(
|
||||
peripherals.SPI3,
|
||||
2.MHz(),
|
||||
SpiMode::Mode0,
|
||||
&mut clocks,
|
||||
)
|
||||
.with_pins(
|
||||
Some(touch_clk),
|
||||
Some(touch_mosi),
|
||||
Some(touch_miso),
|
||||
NO_PIN,
|
||||
);
|
||||
static TOUCH_SPI_BUS: StaticCell<
|
||||
NoopMutex<RefCell<Spi<SPI3, FullDuplexMode>>>,
|
||||
> = StaticCell::new();
|
||||
let touch_spi_bus =
|
||||
NoopMutex::new(RefCell::new(touch_spi));
|
||||
let touch_spi_bus = TOUCH_SPI_BUS.init(touch_spi_bus);
|
||||
|
||||
let touch_signal = Signal::new();
|
||||
static TOUCH_SIGNAL: StaticCell<
|
||||
Signal<NoopRawMutex, Option<Point>>,
|
||||
> = StaticCell::new();
|
||||
let touch_signal = &*TOUCH_SIGNAL.init(touch_signal);
|
||||
|
||||
spawner
|
||||
.spawn(touch_task(
|
||||
touch_irq,
|
||||
touch_spi_bus,
|
||||
touch_cs,
|
||||
touch_signal,
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
// TODO: Spawn some tasks
|
||||
let _ = spawner;
|
||||
|
||||
// variables
|
||||
let mut appdata = AppData::new();
|
||||
let (mut prev_mins, mut prev_secs, mut prev_millis) =
|
||||
(0, 0, 0);
|
||||
let mut finished = false;
|
||||
|
||||
// touchpoints
|
||||
|
||||
let mut last_touch = None;
|
||||
|
||||
static BUF_CELL: StaticCell<[Rgb565; 100 * 100]> =
|
||||
StaticCell::new();
|
||||
let buf = BUF_CELL.init([Rgb565::BLACK; 100 * 100]);
|
||||
|
||||
let mut textbuf = [0u8; 64];
|
||||
|
||||
// Periodically feed the RWDT watchdog timer when our
|
||||
// tasks are not running:
|
||||
let mut sm = SmartstateProvider::<20>::new();
|
||||
let hasher = Hasher::new();
|
||||
loop {
|
||||
// SMART REDRAWING ENABLE / DISABLE
|
||||
// sm.force_redraw_all();
|
||||
|
||||
let start_time = embassy_time::Instant::now();
|
||||
sm.restart_counter();
|
||||
let mut ui = Ui::new_fullscreen(
|
||||
&mut display,
|
||||
medsize_rgb565_style(),
|
||||
);
|
||||
if let Some(touch) = touch_signal.try_take() {
|
||||
let interact = match (touch, last_touch) {
|
||||
(Some(point), Some(_)) => {
|
||||
Interaction::Drag(point)
|
||||
}
|
||||
(Some(point), None) => {
|
||||
Interaction::Click(point)
|
||||
}
|
||||
(None, Some(point)) => {
|
||||
Interaction::Release(point)
|
||||
}
|
||||
(None, None) => Interaction::None,
|
||||
};
|
||||
ui.interact(interact);
|
||||
// println!("{:?}, {:?}, {:?}", last_touch,
|
||||
// touch, interact);
|
||||
|
||||
last_touch = touch;
|
||||
}
|
||||
|
||||
// BUFFER ENABLE/DISABLE
|
||||
ui.set_buffer(buf);
|
||||
|
||||
let start_draw_time = embassy_time::Instant::now();
|
||||
ui.sub_ui(|ui| {
|
||||
ui.style_mut().default_font =
|
||||
ascii::FONT_9X18_BOLD;
|
||||
ui.add(
|
||||
Label::new("Kolibri Microwave UI")
|
||||
.smartstate(sm.next()),
|
||||
);
|
||||
Ok(())
|
||||
})
|
||||
.ok();
|
||||
|
||||
let remaining = appdata.remaining();
|
||||
|
||||
ui.right_panel_ui(200, false, |ui| {
|
||||
ui.add(Spacer::new(Size::new(0, 30)));
|
||||
ui.add_horizontal(Spacer::new(Size::new(
|
||||
15, 0,
|
||||
)));
|
||||
ui.sub_ui(|ui| {
|
||||
ui.style_mut().default_font =
|
||||
ascii::FONT_10X20;
|
||||
// if remaining.as_secs() / 60 != prev_mins
|
||||
// { sm.peek().
|
||||
// force_redraw();
|
||||
// prev_mins = remaining.as_secs() / 60;
|
||||
// }
|
||||
ui.add_horizontal(HashLabel::new(
|
||||
&format_no_std::show(
|
||||
&mut textbuf,
|
||||
format_args!(
|
||||
"{:02}",
|
||||
remaining.as_secs() / 60
|
||||
),
|
||||
)
|
||||
.unwrap(),
|
||||
sm.next(),
|
||||
&hasher,
|
||||
));
|
||||
ui.add_horizontal(
|
||||
Label::new(":").smartstate(sm.next()),
|
||||
);
|
||||
|
||||
ui.add_horizontal(HashLabel::new(
|
||||
&format_no_std::show(
|
||||
&mut textbuf,
|
||||
format_args!(
|
||||
"{:02}",
|
||||
remaining.as_secs() % 60
|
||||
),
|
||||
)
|
||||
.unwrap(),
|
||||
sm.next(),
|
||||
&hasher,
|
||||
));
|
||||
ui.add_horizontal(
|
||||
Label::new(":").smartstate(sm.next()),
|
||||
);
|
||||
|
||||
ui.add(HashLabel::new(
|
||||
&format_no_std::show(
|
||||
&mut textbuf,
|
||||
format_args!(
|
||||
"{:03}",
|
||||
remaining.as_millis() % 1000
|
||||
),
|
||||
)
|
||||
.unwrap(),
|
||||
sm.next(),
|
||||
&hasher,
|
||||
));
|
||||
Ok(())
|
||||
})
|
||||
.ok();
|
||||
|
||||
// ui.add_horizontal(Spacer::new(Size::new(65,
|
||||
// 0)));
|
||||
ui.sub_ui(|ui| {
|
||||
if appdata.timer_running() {
|
||||
ui.style_mut().icon_color =
|
||||
Rgb565::CSS_LIGHT_GRAY;
|
||||
}
|
||||
if ui
|
||||
.add_horizontal(
|
||||
IconButton::new(
|
||||
size32px::actions::AddCircle,
|
||||
)
|
||||
.smartstate(sm.next()),
|
||||
)
|
||||
.clicked()
|
||||
{
|
||||
if !(appdata.timer_running()
|
||||
|| appdata.timer_paused())
|
||||
{
|
||||
appdata.add_secs(10);
|
||||
}
|
||||
}
|
||||
ui.add_horizontal(
|
||||
Label::new("+/- 10s")
|
||||
.smartstate(sm.next()),
|
||||
);
|
||||
if ui
|
||||
.add(
|
||||
IconButton::new(
|
||||
size32px::actions::MinusCircle,
|
||||
)
|
||||
.smartstate(sm.next()),
|
||||
)
|
||||
.clicked()
|
||||
{
|
||||
if !(appdata.timer_running()
|
||||
|| appdata.timer_paused())
|
||||
{
|
||||
appdata.sub_secs(10);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
.ok();
|
||||
|
||||
ui.add_horizontal(Spacer::new(Size::new(
|
||||
15, 0,
|
||||
)));
|
||||
if ui
|
||||
.add_horizontal(
|
||||
IconButton::new(
|
||||
size48px::actions::Undo,
|
||||
)
|
||||
.smartstate(sm.next()),
|
||||
)
|
||||
.clicked()
|
||||
{
|
||||
appdata.reset_timer();
|
||||
sm.force_redraw_all();
|
||||
}
|
||||
|
||||
if !finished && appdata.timer_finished() {
|
||||
sm.peek().force_redraw();
|
||||
}
|
||||
|
||||
if appdata.timer_finished() {
|
||||
if ui
|
||||
.add_horizontal(
|
||||
IconButton::new(
|
||||
size48px::actions::RemoveSquare,
|
||||
)
|
||||
.smartstate(sm.next()),
|
||||
)
|
||||
.clicked()
|
||||
{
|
||||
appdata.reset_timer();
|
||||
sm.force_redraw_all();
|
||||
}
|
||||
} else if appdata.timer_running() {
|
||||
if ui
|
||||
.add_horizontal(
|
||||
IconButton::new(
|
||||
size48px::music::Pause,
|
||||
)
|
||||
.smartstate(sm.next()),
|
||||
)
|
||||
.clicked()
|
||||
{
|
||||
appdata.pause_timer();
|
||||
sm.force_redraw_all();
|
||||
}
|
||||
} else {
|
||||
if ui
|
||||
.add_horizontal(
|
||||
IconButton::new(
|
||||
size48px::music::Play,
|
||||
)
|
||||
.smartstate(sm.next()),
|
||||
)
|
||||
.clicked()
|
||||
{
|
||||
appdata.start_timer();
|
||||
sm.force_redraw_all();
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
.ok();
|
||||
ui.add(Spacer::new(Size::new(0, 20)));
|
||||
ui.expand_row_height(65);
|
||||
ui.right_panel_ui(80, false, |ui| {
|
||||
if appdata.timer_running() {
|
||||
ui.style_mut().icon_color =
|
||||
Rgb565::CSS_LIGHT_GRAY;
|
||||
}
|
||||
if ui
|
||||
.add(
|
||||
IconButton::new(
|
||||
size32px::actions::AddCircle,
|
||||
)
|
||||
.smartstate(sm.next()),
|
||||
)
|
||||
.clicked()
|
||||
{
|
||||
if !appdata.timer_running() {
|
||||
appdata.set_wattage_level(
|
||||
(appdata.wattage_level + 1).min(5),
|
||||
);
|
||||
}
|
||||
}
|
||||
ui.expand_row_height(40);
|
||||
// ui.add_horizontal(Spacer::new(Size::new(0,
|
||||
// 40)));
|
||||
ui.add(
|
||||
HashLabel::new(
|
||||
appdata.get_wattage_level_str(),
|
||||
sm.next(),
|
||||
&hasher,
|
||||
)
|
||||
.with_font(ascii::FONT_10X20),
|
||||
);
|
||||
if ui
|
||||
.add(
|
||||
IconButton::new(
|
||||
size32px::actions::MinusCircle,
|
||||
)
|
||||
.smartstate(sm.next()),
|
||||
)
|
||||
.clicked()
|
||||
{
|
||||
if !appdata.timer_running() {
|
||||
appdata.set_wattage_level(
|
||||
appdata
|
||||
.wattage_level
|
||||
.saturating_sub(1),
|
||||
);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
.ok();
|
||||
|
||||
finished = appdata.timer_finished();
|
||||
|
||||
let end_time = embassy_time::Instant::now();
|
||||
let draw_time = display.get_time();
|
||||
let prep_time = start_draw_time - start_time;
|
||||
let proc_time = end_time - start_draw_time;
|
||||
let proc_time =
|
||||
proc_time - min(draw_time, proc_time);
|
||||
rtc.rwdt.feed();
|
||||
|
||||
if draw_time.as_micros() > 0 {
|
||||
println!(
|
||||
"draw time: {}.{:03}ms | prep time: {}.{:03}ms | proc time: {}.{:03}ms | total time: {}.{:03}ms",
|
||||
draw_time.as_millis(),
|
||||
draw_time.as_micros() % 100,
|
||||
prep_time.as_millis(),
|
||||
prep_time.as_micros() % 100,
|
||||
proc_time.as_millis(),
|
||||
proc_time.as_micros() % 100,
|
||||
(draw_time + prep_time + proc_time).as_millis(),
|
||||
(draw_time + prep_time + proc_time).as_micros() % 100, );
|
||||
}
|
||||
display.reset_time();
|
||||
Timer::after(Duration::from_millis(17)).await; // 60
|
||||
// a second
|
||||
}
|
||||
}
|
586
app/src/bin/timer.rs
Normal file
586
app/src/bin/timer.rs
Normal file
@ -0,0 +1,586 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use core::{cell::RefCell, cmp::min};
|
||||
|
||||
use display_interface_spi::SPIInterface;
|
||||
use embassy_embedded_hal::shared_bus::blocking::spi::SpiDevice;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_sync::{
|
||||
blocking_mutex::{raw::NoopRawMutex, NoopMutex},
|
||||
signal::Signal,
|
||||
};
|
||||
use embassy_time::{Duration, Instant, Timer};
|
||||
use embedded_graphics::{
|
||||
mono_font::ascii,
|
||||
pixelcolor::Rgb565,
|
||||
prelude::{Point, RgbColor, Size, WebColors},
|
||||
};
|
||||
use embedded_graphics_profiler_display::ProfilerDisplay;
|
||||
use esp_backtrace as _;
|
||||
use esp_hal::{
|
||||
clock::ClockControl,
|
||||
gpio::{
|
||||
GpioPin,
|
||||
Input,
|
||||
Io,
|
||||
Level,
|
||||
Output,
|
||||
Pull,
|
||||
NO_PIN,
|
||||
},
|
||||
peripherals::{Peripherals, SPI2, SPI3},
|
||||
prelude::*,
|
||||
rtc_cntl::Rtc,
|
||||
spi::{master::Spi, FullDuplexMode, SpiMode},
|
||||
system::SystemControl,
|
||||
timer::timg::TimerGroup,
|
||||
};
|
||||
use esp_println::println;
|
||||
use kolibri_embedded_gui::{
|
||||
iconbutton::IconButton,
|
||||
icons::{size32px, size48px},
|
||||
label::Label,
|
||||
smartstate::SmartstateProvider,
|
||||
spacer::Spacer,
|
||||
style::medsize_rgb565_style,
|
||||
ui::{Interaction, Ui},
|
||||
};
|
||||
use mipidsi::{
|
||||
models::ILI9341Rgb565,
|
||||
options::{ColorOrder, Orientation, Rotation},
|
||||
Builder,
|
||||
};
|
||||
use static_cell::StaticCell;
|
||||
use xpt2046::Xpt2046;
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn touch_task(
|
||||
touch_irq: GpioPin<36>,
|
||||
spi: &'static mut NoopMutex<
|
||||
RefCell<Spi<'static, SPI3, FullDuplexMode>>,
|
||||
>,
|
||||
touch_cs: GpioPin<33>,
|
||||
touch_signal: &'static Signal<
|
||||
NoopRawMutex,
|
||||
Option<Point>,
|
||||
>,
|
||||
) -> ! {
|
||||
let mut touch_driver = Xpt2046::new(
|
||||
SpiDevice::new(
|
||||
spi,
|
||||
Output::new(touch_cs, Level::Low),
|
||||
),
|
||||
Input::new(touch_irq, Pull::Up),
|
||||
xpt2046::Orientation::LandscapeFlipped,
|
||||
);
|
||||
touch_driver.set_num_samples(16);
|
||||
touch_driver.init(&mut embassy_time::Delay).unwrap();
|
||||
|
||||
println!("touch task");
|
||||
|
||||
loop {
|
||||
touch_driver
|
||||
.run()
|
||||
.expect("Running Touch driver failed");
|
||||
if touch_driver.is_touched() {
|
||||
let point = touch_driver.get_touch_point();
|
||||
touch_signal.signal(Some(Point::new(
|
||||
point.x + 25,
|
||||
240 - point.y,
|
||||
)));
|
||||
} else {
|
||||
touch_signal.signal(None);
|
||||
}
|
||||
Timer::after(Duration::from_millis(1)).await; // 100
|
||||
// a second
|
||||
|
||||
// Your touch handling logic here
|
||||
}
|
||||
}
|
||||
|
||||
struct AppData {
|
||||
timer_start: Instant,
|
||||
timer_set_duration: Duration,
|
||||
timer_remaining_duration: Duration,
|
||||
timer_running: bool,
|
||||
timer_paused: bool,
|
||||
}
|
||||
|
||||
impl AppData {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
timer_start: Instant::now(),
|
||||
timer_set_duration: Duration::from_secs(10),
|
||||
timer_remaining_duration: Duration::from_secs(
|
||||
10,
|
||||
),
|
||||
timer_running: false,
|
||||
timer_paused: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn set_timer_duration(&mut self, duration: Duration) {
|
||||
self.timer_set_duration = duration;
|
||||
}
|
||||
|
||||
fn add_secs(&mut self, secs: u64) {
|
||||
self.set_timer_duration(
|
||||
self.timer_set_duration
|
||||
.checked_add(Duration::from_secs(secs))
|
||||
.unwrap_or(Duration::from_secs(5999))
|
||||
.min(Duration::from_secs(5999)),
|
||||
);
|
||||
}
|
||||
|
||||
fn sub_secs(&mut self, secs: u64) {
|
||||
self.set_timer_duration(
|
||||
self.timer_set_duration
|
||||
.checked_sub(Duration::from_secs(secs))
|
||||
.unwrap_or(Duration::from_secs(10))
|
||||
.max(Duration::from_secs(10)),
|
||||
);
|
||||
}
|
||||
|
||||
fn start_timer(&mut self) {
|
||||
if !self.timer_paused {
|
||||
self.timer_remaining_duration =
|
||||
self.timer_set_duration;
|
||||
}
|
||||
|
||||
self.timer_start = Instant::now();
|
||||
self.timer_running = true;
|
||||
self.timer_paused = false;
|
||||
}
|
||||
|
||||
fn pause_timer(&mut self) {
|
||||
self.timer_paused = true;
|
||||
self.timer_remaining_duration = self
|
||||
.timer_remaining_duration
|
||||
.checked_sub(self.timer_start.elapsed())
|
||||
.unwrap_or(Duration::from_secs(0));
|
||||
}
|
||||
|
||||
fn reset_timer(&mut self) {
|
||||
self.timer_start = Instant::now();
|
||||
self.timer_paused = false;
|
||||
self.timer_running = false;
|
||||
self.timer_remaining_duration =
|
||||
self.timer_set_duration;
|
||||
}
|
||||
|
||||
fn remaining(&self) -> Duration {
|
||||
if self.timer_stopped() {
|
||||
self.timer_set_duration
|
||||
} else if self.timer_paused() {
|
||||
self.timer_remaining_duration
|
||||
} else {
|
||||
self.timer_remaining_duration
|
||||
.checked_sub(self.timer_start.elapsed())
|
||||
.unwrap_or(Duration::from_secs(0))
|
||||
}
|
||||
}
|
||||
|
||||
fn timer_stopped(&self) -> bool {
|
||||
!self.timer_running
|
||||
}
|
||||
|
||||
fn timer_paused(&self) -> bool {
|
||||
self.timer_running && self.timer_paused
|
||||
}
|
||||
|
||||
fn timer_running(&self) -> bool {
|
||||
self.timer_running && !self.timer_paused
|
||||
}
|
||||
|
||||
fn timer_finished(&self) -> bool {
|
||||
self.timer_running
|
||||
&& self.remaining() == Duration::from_secs(0)
|
||||
}
|
||||
}
|
||||
|
||||
#[main]
|
||||
async fn main(spawner: Spawner) {
|
||||
let peripherals = Peripherals::take();
|
||||
let system = SystemControl::new(peripherals.SYSTEM);
|
||||
let mut clocks =
|
||||
ClockControl::boot_defaults(system.clock_control)
|
||||
.freeze();
|
||||
|
||||
// Enable the RWDT watchdog timer:
|
||||
let mut rtc = Rtc::new(peripherals.LPWR);
|
||||
rtc.rwdt.set_timeout(2.secs());
|
||||
rtc.rwdt.enable();
|
||||
println!("RWDT watchdog enabled!");
|
||||
|
||||
// Initialize the SYSTIMER peripheral, and then Embassy:
|
||||
let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks);
|
||||
esp_hal_embassy::init(&clocks, timg0.timer0);
|
||||
println!("Embassy initialized!");
|
||||
|
||||
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
// let mut led = Output::new(io.pins.gpio5,
|
||||
// Level::High); Initialize SPI
|
||||
let sclk = io.pins.gpio14;
|
||||
let miso = io.pins.gpio12;
|
||||
let mosi = io.pins.gpio13;
|
||||
let cs = io.pins.gpio15;
|
||||
let dc = io.pins.gpio2;
|
||||
let mut backlight =
|
||||
Output::new(io.pins.gpio21, Level::Low);
|
||||
|
||||
// Note: RST is not initialized as it's set to -1 in the
|
||||
// instructions
|
||||
|
||||
// up to 80MHz is possible (even tho the display driver
|
||||
// isn't supposed to be that fast) Dataseheet sais
|
||||
// 10MHz, so we're gonna go with that
|
||||
let mut spi = Spi::new(
|
||||
peripherals.SPI2,
|
||||
10.MHz(),
|
||||
SpiMode::Mode0,
|
||||
&mut clocks,
|
||||
)
|
||||
.with_pins(
|
||||
Some(sclk),
|
||||
Some(mosi),
|
||||
Some(miso),
|
||||
NO_PIN,
|
||||
);
|
||||
|
||||
static DISP_SPI_BUS: StaticCell<
|
||||
NoopMutex<RefCell<Spi<SPI2, FullDuplexMode>>>,
|
||||
> = StaticCell::new();
|
||||
let spi_bus = NoopMutex::new(RefCell::new(spi));
|
||||
let spi_bus = DISP_SPI_BUS.init(spi_bus);
|
||||
|
||||
let di = SPIInterface::new(
|
||||
SpiDevice::new(
|
||||
spi_bus,
|
||||
Output::new(cs, Level::Low),
|
||||
),
|
||||
Output::new(dc, Level::Low),
|
||||
);
|
||||
let display = Builder::new(ILI9341Rgb565, di)
|
||||
.orientation(Orientation {
|
||||
rotation: Rotation::Deg90,
|
||||
mirrored: true,
|
||||
})
|
||||
.color_order(ColorOrder::Bgr)
|
||||
// .invert_colors(ColorInversion::Inverted)
|
||||
.init(&mut embassy_time::Delay)
|
||||
.unwrap();
|
||||
|
||||
let mut display = ProfilerDisplay::new(display);
|
||||
|
||||
{
|
||||
let mut ui = Ui::new_fullscreen(
|
||||
&mut display,
|
||||
medsize_rgb565_style(),
|
||||
);
|
||||
ui.clear_background().ok();
|
||||
}
|
||||
backlight.set_high();
|
||||
|
||||
// init touchscreen pins
|
||||
let touch_irq = io.pins.gpio36;
|
||||
let touch_mosi = io.pins.gpio32;
|
||||
let touch_miso = io.pins.gpio39;
|
||||
let touch_clk = io.pins.gpio25;
|
||||
let touch_cs = io.pins.gpio33;
|
||||
|
||||
// 2MHz is the MAX! DO NOT DECREASE! This is really
|
||||
// important.
|
||||
let mut touch_spi = Spi::new(
|
||||
peripherals.SPI3,
|
||||
2.MHz(),
|
||||
SpiMode::Mode0,
|
||||
&mut clocks,
|
||||
)
|
||||
.with_pins(
|
||||
Some(touch_clk),
|
||||
Some(touch_mosi),
|
||||
Some(touch_miso),
|
||||
NO_PIN,
|
||||
);
|
||||
static TOUCH_SPI_BUS: StaticCell<
|
||||
NoopMutex<RefCell<Spi<SPI3, FullDuplexMode>>>,
|
||||
> = StaticCell::new();
|
||||
let touch_spi_bus =
|
||||
NoopMutex::new(RefCell::new(touch_spi));
|
||||
let touch_spi_bus = TOUCH_SPI_BUS.init(touch_spi_bus);
|
||||
|
||||
let touch_signal = Signal::new();
|
||||
static TOUCH_SIGNAL: StaticCell<
|
||||
Signal<NoopRawMutex, Option<Point>>,
|
||||
> = StaticCell::new();
|
||||
let touch_signal = &*TOUCH_SIGNAL.init(touch_signal);
|
||||
|
||||
spawner
|
||||
.spawn(touch_task(
|
||||
touch_irq,
|
||||
touch_spi_bus,
|
||||
touch_cs,
|
||||
touch_signal,
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
// TODO: Spawn some tasks
|
||||
let _ = spawner;
|
||||
|
||||
// variables
|
||||
let mut appdata = AppData::new();
|
||||
let (mut prev_mins, mut prev_secs, mut prev_millis) =
|
||||
(0, 0, 0);
|
||||
let mut finished = false;
|
||||
|
||||
// touchpoints
|
||||
|
||||
let mut last_touch = None;
|
||||
|
||||
static BUF_CELL: StaticCell<[Rgb565; 100 * 100]> =
|
||||
StaticCell::new();
|
||||
let buf = BUF_CELL.init([Rgb565::BLACK; 100 * 100]);
|
||||
|
||||
let mut textbuf = [0u8; 64];
|
||||
|
||||
// Periodically feed the RWDT watchdog timer when our
|
||||
// tasks are not running:
|
||||
let mut sm = SmartstateProvider::<20>::new();
|
||||
loop {
|
||||
// SMART REDRAWING ENABLE / DISABLE
|
||||
// sm.force_redraw_all();
|
||||
|
||||
let start_time = embassy_time::Instant::now();
|
||||
sm.restart_counter();
|
||||
let mut ui = Ui::new_fullscreen(
|
||||
&mut display,
|
||||
medsize_rgb565_style(),
|
||||
);
|
||||
if let Some(touch) = touch_signal.try_take() {
|
||||
let interact = match (touch, last_touch) {
|
||||
(Some(point), Some(_)) => {
|
||||
Interaction::Drag(point)
|
||||
}
|
||||
(Some(point), None) => {
|
||||
Interaction::Click(point)
|
||||
}
|
||||
(None, Some(point)) => {
|
||||
Interaction::Release(point)
|
||||
}
|
||||
(None, None) => Interaction::None,
|
||||
};
|
||||
ui.interact(interact);
|
||||
// println!("{:?}, {:?}, {:?}", last_touch,
|
||||
// touch, interact);
|
||||
|
||||
last_touch = touch;
|
||||
}
|
||||
|
||||
// BUFFER ENABLE/DISABLE
|
||||
ui.set_buffer(buf);
|
||||
|
||||
let start_draw_time = embassy_time::Instant::now();
|
||||
ui.sub_ui(|ui| {
|
||||
ui.style_mut().default_font =
|
||||
ascii::FONT_9X18_BOLD;
|
||||
ui.add(
|
||||
Label::new("Kolibri Timer App")
|
||||
.smartstate(sm.next()),
|
||||
);
|
||||
Ok(())
|
||||
})
|
||||
.ok();
|
||||
|
||||
let remaining = appdata.remaining();
|
||||
|
||||
ui.add(Spacer::new(Size::new(0, 60)));
|
||||
ui.add_horizontal(Spacer::new(Size::new(80, 0)));
|
||||
ui.sub_ui(|ui| {
|
||||
ui.style_mut().default_font = ascii::FONT_10X20;
|
||||
if remaining.as_secs() / 60 != prev_mins {
|
||||
sm.peek().force_redraw();
|
||||
prev_mins = remaining.as_secs() / 60;
|
||||
}
|
||||
ui.add_horizontal(
|
||||
Label::new(
|
||||
&format_no_std::show(
|
||||
&mut textbuf,
|
||||
format_args!(
|
||||
"{:02}",
|
||||
remaining.as_secs() / 60
|
||||
),
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
.smartstate(sm.next()),
|
||||
);
|
||||
ui.add_horizontal(
|
||||
Label::new(":").smartstate(sm.next()),
|
||||
);
|
||||
|
||||
if remaining.as_secs() % 60 != prev_secs {
|
||||
sm.peek().force_redraw();
|
||||
prev_secs = remaining.as_secs() % 60;
|
||||
}
|
||||
ui.add_horizontal(
|
||||
Label::new(
|
||||
&format_no_std::show(
|
||||
&mut textbuf,
|
||||
format_args!(
|
||||
"{:02}",
|
||||
remaining.as_secs() % 60
|
||||
),
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
.smartstate(sm.next()),
|
||||
);
|
||||
ui.add_horizontal(
|
||||
Label::new(":").smartstate(sm.next()),
|
||||
);
|
||||
|
||||
if remaining.as_millis() % 1000 != prev_millis {
|
||||
sm.peek().force_redraw();
|
||||
prev_millis = remaining.as_millis() % 1000;
|
||||
}
|
||||
ui.add(
|
||||
Label::new(
|
||||
&format_no_std::show(
|
||||
&mut textbuf,
|
||||
format_args!(
|
||||
"{:03}",
|
||||
remaining.as_millis() % 1000
|
||||
),
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
.smartstate(sm.next()),
|
||||
);
|
||||
Ok(())
|
||||
})
|
||||
.ok();
|
||||
|
||||
ui.add_horizontal(Spacer::new(Size::new(65, 0)));
|
||||
ui.sub_ui(|ui| {
|
||||
if appdata.timer_running() {
|
||||
ui.style_mut().icon_color =
|
||||
Rgb565::CSS_LIGHT_GRAY;
|
||||
}
|
||||
if ui
|
||||
.add_horizontal(
|
||||
IconButton::new(
|
||||
size32px::actions::AddCircle,
|
||||
)
|
||||
.smartstate(sm.next()),
|
||||
)
|
||||
.clicked()
|
||||
{
|
||||
if !(appdata.timer_running()
|
||||
|| appdata.timer_paused())
|
||||
{
|
||||
appdata.add_secs(10);
|
||||
}
|
||||
}
|
||||
ui.add_horizontal(
|
||||
Label::new("+/- 10s").smartstate(sm.next()),
|
||||
);
|
||||
if ui
|
||||
.add(
|
||||
IconButton::new(
|
||||
size32px::actions::MinusCircle,
|
||||
)
|
||||
.smartstate(sm.next()),
|
||||
)
|
||||
.clicked()
|
||||
{
|
||||
if !(appdata.timer_running()
|
||||
|| appdata.timer_paused())
|
||||
{
|
||||
appdata.sub_secs(10);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
.ok();
|
||||
|
||||
ui.add_horizontal(Spacer::new(Size::new(80, 0)));
|
||||
if ui
|
||||
.add_horizontal(
|
||||
IconButton::new(size48px::actions::Undo)
|
||||
.smartstate(sm.next()),
|
||||
)
|
||||
.clicked()
|
||||
{
|
||||
appdata.reset_timer();
|
||||
sm.force_redraw_all();
|
||||
}
|
||||
|
||||
if !finished && appdata.timer_finished() {
|
||||
sm.peek().force_redraw();
|
||||
}
|
||||
|
||||
if appdata.timer_finished() {
|
||||
if ui
|
||||
.add_horizontal(
|
||||
IconButton::new(
|
||||
size48px::actions::RemoveSquare,
|
||||
)
|
||||
.smartstate(sm.next()),
|
||||
)
|
||||
.clicked()
|
||||
{
|
||||
appdata.reset_timer();
|
||||
sm.force_redraw_all();
|
||||
}
|
||||
} else if appdata.timer_running() {
|
||||
if ui
|
||||
.add_horizontal(
|
||||
IconButton::new(size48px::music::Pause)
|
||||
.smartstate(sm.next()),
|
||||
)
|
||||
.clicked()
|
||||
{
|
||||
appdata.pause_timer();
|
||||
sm.force_redraw_all();
|
||||
}
|
||||
} else {
|
||||
if ui
|
||||
.add_horizontal(
|
||||
IconButton::new(size48px::music::Play)
|
||||
.smartstate(sm.next()),
|
||||
)
|
||||
.clicked()
|
||||
{
|
||||
appdata.start_timer();
|
||||
sm.force_redraw_all();
|
||||
}
|
||||
}
|
||||
|
||||
finished = appdata.timer_finished();
|
||||
|
||||
let end_time = embassy_time::Instant::now();
|
||||
let draw_time = display.get_time();
|
||||
let prep_time = start_draw_time - start_time;
|
||||
let proc_time = end_time - start_draw_time;
|
||||
let proc_time =
|
||||
proc_time - min(draw_time, proc_time);
|
||||
rtc.rwdt.feed();
|
||||
|
||||
if draw_time.as_micros() > 0 {
|
||||
println!(
|
||||
"draw time: {}.{:03}ms | prep time: {}.{:03}ms | proc time: {}.{:03}ms | total time: {}.{:03}ms",
|
||||
draw_time.as_millis(),
|
||||
draw_time.as_micros() % 100,
|
||||
prep_time.as_millis(),
|
||||
prep_time.as_micros() % 100,
|
||||
proc_time.as_millis(),
|
||||
proc_time.as_micros() % 100,
|
||||
(draw_time + prep_time + proc_time).as_millis(),
|
||||
(draw_time + prep_time + proc_time).as_micros() % 100, );
|
||||
}
|
||||
display.reset_time();
|
||||
Timer::after(Duration::from_millis(17)).await; // 60
|
||||
// a second
|
||||
}
|
||||
}
|
@ -4,14 +4,14 @@ target = "xtensa-esp32-espidf"
|
||||
[target.xtensa-esp32-espidf]
|
||||
linker = "ldproxy"
|
||||
# runner = "espflash --monitor" # Select this runner for espflash v1.x.x
|
||||
runner = "espflash flash --monitor --baud 921600" # Select this runner for espflash v2.x.x
|
||||
runner = "espflash flash --monitor" # --baud 921600" # Select this runner for espflash v2.x.x
|
||||
rustflags = [
|
||||
# Extending time_t for ESP IDF 5: https://github.com/esp-rs/rust/issues/110
|
||||
"--cfg",
|
||||
"espidf_time64",
|
||||
# Added the following 2 entries so lvgl will build without getting string.h file not found
|
||||
"--sysroot",
|
||||
"/home/ed/.rustup/toolchains/esp/xtensa-esp32s3-elf/esp-13.2.0_20230928/xtensa-esp-elf/xtensa-esp-elf/include",
|
||||
"/home/yannik/.rustup/toolchains/esp/xtensa-esp32s3-elf/esp-13.2.0_20230928/xtensa-esp-elf/xtensa-esp-elf/include",
|
||||
]
|
||||
|
||||
[unstable]
|
||||
|
19
lvgl-based/rustfmt.toml
Normal file
19
lvgl-based/rustfmt.toml
Normal file
@ -0,0 +1,19 @@
|
||||
# Edition
|
||||
edition = "2021"
|
||||
|
||||
# Comments
|
||||
format_code_in_doc_comments = true
|
||||
normalize_comments = true
|
||||
wrap_comments = true
|
||||
|
||||
# Imports
|
||||
group_imports = "StdExternalCrate"
|
||||
imports_granularity = "Crate"
|
||||
imports_layout = "HorizontalVertical"
|
||||
|
||||
# Miscellaneous
|
||||
enum_discrim_align_threshold = 25
|
||||
hex_literal_case = "Upper"
|
||||
|
||||
# Length
|
||||
max_width=60
|
@ -9,14 +9,22 @@ use std::{
|
||||
|
||||
use cstr_core::CString;
|
||||
use display_interface_spi::SPIInterface;
|
||||
use embedded_graphics_core::{draw_target::DrawTarget, prelude::Point};
|
||||
use embedded_graphics_core::{
|
||||
draw_target::DrawTarget,
|
||||
prelude::Point,
|
||||
};
|
||||
use embedded_graphics_profiler_display::ProfilerDisplay;
|
||||
use esp_idf_hal::spi::SpiSingleDeviceDriver;
|
||||
use esp_idf_hal::{
|
||||
delay::{self, Delay},
|
||||
gpio::*,
|
||||
peripherals::Peripherals,
|
||||
spi::{config::DriverConfig, Dma, SpiConfig, SpiDeviceDriver},
|
||||
spi::{
|
||||
config::DriverConfig,
|
||||
Dma,
|
||||
SpiConfig,
|
||||
SpiDeviceDriver,
|
||||
},
|
||||
units::FromValueType, // for converting 26MHz to value
|
||||
};
|
||||
use lvgl::{
|
||||
@ -42,16 +50,24 @@ use lvgl::{
|
||||
Widget,
|
||||
};
|
||||
use mipidsi::{
|
||||
models::ILI9486Rgb565,
|
||||
options::{ColorInversion, ColorOrder, Orientation, Rotation},
|
||||
models::ILI9341Rgb565,
|
||||
options::{
|
||||
ColorInversion,
|
||||
ColorOrder,
|
||||
Orientation,
|
||||
Rotation,
|
||||
},
|
||||
Builder,
|
||||
};
|
||||
use xpt2046::Xpt2046;
|
||||
|
||||
fn lerp_fixed(start: u8, end: u8, t: u8, max_t: u8) -> u8 {
|
||||
let (start, end, t, max_t) = (start as u16, end as u16, t as u16, max_t as u16);
|
||||
let (start, end, t, max_t) =
|
||||
(start as u16, end as u16, t as u16, max_t as u16);
|
||||
let t = t.min(max_t);
|
||||
let result = start + ((end - start.min(end)) * t + (max_t / 2)) / max_t;
|
||||
let result = start
|
||||
+ ((end - start.min(end)) * t + (max_t / 2))
|
||||
/ max_t;
|
||||
result as u8
|
||||
}
|
||||
|
||||
@ -65,7 +81,9 @@ struct Lamp {
|
||||
impl Lamp {
|
||||
pub fn new(name: &str) -> Self {
|
||||
Self {
|
||||
name: heapless::String::from(heapless::String::from_str(name).unwrap()),
|
||||
name: heapless::String::from(
|
||||
heapless::String::from_str(name).unwrap(),
|
||||
),
|
||||
on: false,
|
||||
brightness: 255,
|
||||
}
|
||||
@ -97,8 +115,8 @@ fn main() -> Result<(), LvError> {
|
||||
const VER_RES: u32 = 240;
|
||||
const LINES: u32 = 20;
|
||||
|
||||
// It is necessary to call this function once. Otherwise some patches to the
|
||||
// runtime implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71
|
||||
// It is necessary to call this function once. Otherwise
|
||||
// some patches to the runtime implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71
|
||||
esp_idf_svc::sys::link_patches();
|
||||
|
||||
// Initialize lvgl
|
||||
@ -127,7 +145,9 @@ fn main() -> Result<(), LvError> {
|
||||
Some(miso), // sdi
|
||||
Some(cs), // cs
|
||||
&DriverConfig::new().dma(Dma::Channel1(4096)),
|
||||
&SpiConfig::new().write_only(true).baudrate(10.MHz().into()),
|
||||
&SpiConfig::new()
|
||||
.write_only(true)
|
||||
.baudrate(10.MHz().into()),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@ -140,8 +160,9 @@ fn main() -> Result<(), LvError> {
|
||||
bklt.set_high().unwrap();
|
||||
|
||||
// Configuration for M5Stack Core Development Kit V1.0
|
||||
// Puts display in landscape mode with the three buttons at the bottom of screen
|
||||
// let mut m5stack_display = Builder::ili9342c_rgb565(di)
|
||||
// Puts display in landscape mode with the three buttons
|
||||
// at the bottom of screen let mut m5stack_display =
|
||||
// Builder::ili9342c_rgb565(di)
|
||||
// .with_display_size(320, 240)
|
||||
// .with_color_order(ColorOrder::Bgr)
|
||||
// .with_orientation(Orientation::Portrait(false))
|
||||
@ -154,23 +175,25 @@ fn main() -> Result<(), LvError> {
|
||||
// .with_orientation(Orientation::Portrait(false))
|
||||
// .with_color_order(ColorOrder::Bgr)
|
||||
// .with_invert_colors(true)
|
||||
// .init(&mut Delay::new_default(), None::<PinDriver<AnyOutputPin, Output>>)
|
||||
// .init(&mut Delay::new_default(),
|
||||
// None::<PinDriver<AnyOutputPin, Output>>)
|
||||
// .unwrap();
|
||||
|
||||
let raw_display = Builder::new(ILI9486Rgb565, di)
|
||||
let raw_display = Builder::new(ILI9341Rgb565, di)
|
||||
.orientation(Orientation {
|
||||
rotation: Rotation::Deg90,
|
||||
mirrored: true,
|
||||
})
|
||||
.color_order(ColorOrder::Bgr)
|
||||
.invert_colors(ColorInversion::Inverted)
|
||||
// .invert_colors(ColorInversion::Inverted)
|
||||
.init(&mut Delay::new_default())
|
||||
.unwrap();
|
||||
|
||||
let mut raw_display = ProfilerDisplay::new(raw_display);
|
||||
|
||||
// Stack size value - 20,000 for 10 lines, 40,000 for 20 lines
|
||||
// let (touch_send, touch_recv) = channel();
|
||||
// Stack size value - 20,000 for 10 lines, 40,000 for
|
||||
// 20 lines let (touch_send, touch_recv) =
|
||||
// channel();
|
||||
let touch_irq = pins.gpio36;
|
||||
let touch_mosi = pins.gpio32;
|
||||
let touch_miso = pins.gpio39;
|
||||
@ -185,7 +208,9 @@ fn main() -> Result<(), LvError> {
|
||||
Some(touch_miso),
|
||||
Some(touch_cs),
|
||||
&DriverConfig::new(),
|
||||
&SpiConfig::new().write_only(true).baudrate(2.MHz().into()),
|
||||
&SpiConfig::new()
|
||||
.write_only(true)
|
||||
.baudrate(2.MHz().into()),
|
||||
)
|
||||
.unwrap(),
|
||||
PinDriver::input(touch_irq).unwrap(),
|
||||
@ -317,7 +342,7 @@ fn main() -> Result<(), LvError> {
|
||||
|
||||
cont.on_event(|_btn, event| {
|
||||
if let Event::Pressed = event {
|
||||
println!("lamp {:?}", lamp.name);
|
||||
// println!("lamp {:?}", lamp.name);
|
||||
// page = Page::LampCtrl(lamp);
|
||||
|
||||
brightness_slider.set_value(lerp_fixed(0, 100, lamp.brightness, 255).into(), AnimationState::OFF);
|
||||
|
@ -9,14 +9,22 @@ use std::{
|
||||
|
||||
use cstr_core::CString;
|
||||
use display_interface_spi::SPIInterface;
|
||||
use embedded_graphics_core::{draw_target::DrawTarget, prelude::Point};
|
||||
use embedded_graphics_core::{
|
||||
draw_target::DrawTarget,
|
||||
prelude::Point,
|
||||
};
|
||||
use embedded_graphics_profiler_display::ProfilerDisplay;
|
||||
use esp_idf_hal::spi::SpiSingleDeviceDriver;
|
||||
use esp_idf_hal::{
|
||||
delay::{self, Delay},
|
||||
gpio::*,
|
||||
peripherals::Peripherals,
|
||||
spi::{config::DriverConfig, Dma, SpiConfig, SpiDeviceDriver},
|
||||
spi::{
|
||||
config::DriverConfig,
|
||||
Dma,
|
||||
SpiConfig,
|
||||
SpiDeviceDriver,
|
||||
},
|
||||
units::FromValueType, // for converting 26MHz to value
|
||||
};
|
||||
use lvgl::{
|
||||
@ -42,25 +50,26 @@ use lvgl::{
|
||||
Widget,
|
||||
};
|
||||
use mipidsi::{
|
||||
models::ILI9486Rgb565,
|
||||
options::{ColorInversion, ColorOrder, Orientation, Rotation},
|
||||
models::ILI9341Rgb565,
|
||||
options::{
|
||||
ColorInversion,
|
||||
ColorOrder,
|
||||
Orientation,
|
||||
Rotation,
|
||||
},
|
||||
Builder,
|
||||
};
|
||||
use xpt2046::Xpt2046;
|
||||
|
||||
fn lerp_fixed(start: u8, end: u8, t: u8, max_t: u8) -> u8 {
|
||||
let (start, end, t, max_t) = (start as u16, end as u16, t as u16, max_t as u16);
|
||||
let (start, end, t, max_t) =
|
||||
(start as u16, end as u16, t as u16, max_t as u16);
|
||||
let t = t.min(max_t);
|
||||
let result = start + ((end - start.min(end)) * t + (max_t / 2)) / max_t;
|
||||
let result = start
|
||||
+ ((end - start.min(end)) * t + (max_t / 2))
|
||||
/ max_t;
|
||||
result as u8
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Lamp {
|
||||
pub name: heapless::String<64>,
|
||||
pub on: bool,
|
||||
pub brightness: u8,
|
||||
}
|
||||
struct AppData {
|
||||
timer_start: Instant,
|
||||
timer_set_duration: Duration,
|
||||
@ -75,7 +84,9 @@ impl AppData {
|
||||
Self {
|
||||
timer_start: Instant::now(),
|
||||
timer_set_duration: Duration::from_secs(10),
|
||||
timer_remaining_duration: Duration::from_secs(10),
|
||||
timer_remaining_duration: Duration::from_secs(
|
||||
10,
|
||||
),
|
||||
timer_running: false,
|
||||
timer_paused: false,
|
||||
wattage_level: 5,
|
||||
@ -106,7 +117,8 @@ impl AppData {
|
||||
|
||||
fn start_timer(&mut self) {
|
||||
if !self.timer_paused {
|
||||
self.timer_remaining_duration = self.timer_set_duration;
|
||||
self.timer_remaining_duration =
|
||||
self.timer_set_duration;
|
||||
}
|
||||
|
||||
self.timer_start = Instant::now();
|
||||
@ -126,7 +138,8 @@ impl AppData {
|
||||
self.timer_start = Instant::now();
|
||||
self.timer_paused = false;
|
||||
self.timer_running = false;
|
||||
self.timer_remaining_duration = self.timer_set_duration;
|
||||
self.timer_remaining_duration =
|
||||
self.timer_set_duration;
|
||||
}
|
||||
|
||||
fn remaining(&self) -> Duration {
|
||||
@ -154,11 +167,15 @@ impl AppData {
|
||||
}
|
||||
|
||||
fn timer_finished(&self) -> bool {
|
||||
self.timer_running && self.remaining() == Duration::from_secs(0)
|
||||
self.timer_running
|
||||
&& self.remaining() == Duration::from_secs(0)
|
||||
}
|
||||
|
||||
fn set_wattage_level(&mut self, level: u8) {
|
||||
assert!(level < 6, "wattage level cannot be over 6");
|
||||
assert!(
|
||||
level < 6,
|
||||
"wattage level cannot be over 6"
|
||||
);
|
||||
self.wattage_level = level;
|
||||
}
|
||||
|
||||
@ -180,8 +197,8 @@ fn main() -> Result<(), LvError> {
|
||||
const VER_RES: u32 = 240;
|
||||
const LINES: u32 = 20;
|
||||
|
||||
// It is necessary to call this function once. Otherwise some patches to the
|
||||
// runtime implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71
|
||||
// It is necessary to call this function once. Otherwise
|
||||
// some patches to the runtime implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71
|
||||
esp_idf_svc::sys::link_patches();
|
||||
|
||||
// Initialize lvgl
|
||||
@ -210,7 +227,9 @@ fn main() -> Result<(), LvError> {
|
||||
Some(miso), // sdi
|
||||
Some(cs), // cs
|
||||
&DriverConfig::new().dma(Dma::Channel1(4096)),
|
||||
&SpiConfig::new().write_only(true).baudrate(10.MHz().into()),
|
||||
&SpiConfig::new()
|
||||
.write_only(true)
|
||||
.baudrate(10.MHz().into()),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@ -223,8 +242,9 @@ fn main() -> Result<(), LvError> {
|
||||
bklt.set_high().unwrap();
|
||||
|
||||
// Configuration for M5Stack Core Development Kit V1.0
|
||||
// Puts display in landscape mode with the three buttons at the bottom of screen
|
||||
// let mut m5stack_display = Builder::ili9342c_rgb565(di)
|
||||
// Puts display in landscape mode with the three buttons
|
||||
// at the bottom of screen let mut m5stack_display =
|
||||
// Builder::ili9342c_rgb565(di)
|
||||
// .with_display_size(320, 240)
|
||||
// .with_color_order(ColorOrder::Bgr)
|
||||
// .with_orientation(Orientation::Portrait(false))
|
||||
@ -237,23 +257,25 @@ fn main() -> Result<(), LvError> {
|
||||
// .with_orientation(Orientation::Portrait(false))
|
||||
// .with_color_order(ColorOrder::Bgr)
|
||||
// .with_invert_colors(true)
|
||||
// .init(&mut Delay::new_default(), None::<PinDriver<AnyOutputPin, Output>>)
|
||||
// .init(&mut Delay::new_default(),
|
||||
// None::<PinDriver<AnyOutputPin, Output>>)
|
||||
// .unwrap();
|
||||
|
||||
let raw_display = Builder::new(ILI9486Rgb565, di)
|
||||
let raw_display = Builder::new(ILI9341Rgb565, di)
|
||||
.orientation(Orientation {
|
||||
rotation: Rotation::Deg90,
|
||||
mirrored: true,
|
||||
})
|
||||
.color_order(ColorOrder::Bgr)
|
||||
.invert_colors(ColorInversion::Inverted)
|
||||
// .invert_colors(ColorInversion::Inverted)
|
||||
.init(&mut Delay::new_default())
|
||||
.unwrap();
|
||||
|
||||
let mut raw_display = ProfilerDisplay::new(raw_display);
|
||||
|
||||
// Stack size value - 20,000 for 10 lines, 40,000 for 20 lines
|
||||
// let (touch_send, touch_recv) = channel();
|
||||
// Stack size value - 20,000 for 10 lines, 40,000 for
|
||||
// 20 lines let (touch_send, touch_recv) =
|
||||
// channel();
|
||||
let touch_irq = pins.gpio36;
|
||||
let touch_mosi = pins.gpio32;
|
||||
let touch_miso = pins.gpio39;
|
||||
@ -268,7 +290,9 @@ fn main() -> Result<(), LvError> {
|
||||
Some(touch_miso),
|
||||
Some(touch_cs),
|
||||
&DriverConfig::new(),
|
||||
&SpiConfig::new().write_only(true).baudrate(2.MHz().into()),
|
||||
&SpiConfig::new()
|
||||
.write_only(true)
|
||||
.baudrate(2.MHz().into()),
|
||||
)
|
||||
.unwrap(),
|
||||
PinDriver::input(touch_irq).unwrap(),
|
||||
|
@ -8,14 +8,22 @@ use std::{
|
||||
|
||||
use cstr_core::CString;
|
||||
use display_interface_spi::SPIInterface;
|
||||
use embedded_graphics_core::{draw_target::DrawTarget, prelude::Point};
|
||||
use embedded_graphics_core::{
|
||||
draw_target::DrawTarget,
|
||||
prelude::Point,
|
||||
};
|
||||
use embedded_graphics_profiler_display::ProfilerDisplay;
|
||||
use esp_idf_hal::spi::SpiSingleDeviceDriver;
|
||||
use esp_idf_hal::{
|
||||
delay::{self, Delay},
|
||||
gpio::*,
|
||||
peripherals::Peripherals,
|
||||
spi::{config::DriverConfig, Dma, SpiConfig, SpiDeviceDriver},
|
||||
spi::{
|
||||
config::DriverConfig,
|
||||
Dma,
|
||||
SpiConfig,
|
||||
SpiDeviceDriver,
|
||||
},
|
||||
units::FromValueType, // for converting 26MHz to value
|
||||
};
|
||||
use lvgl::{
|
||||
@ -38,8 +46,13 @@ use lvgl::{
|
||||
Widget,
|
||||
};
|
||||
use mipidsi::{
|
||||
models::ILI9486Rgb565,
|
||||
options::{ColorInversion, ColorOrder, Orientation, Rotation},
|
||||
models::ILI9341Rgb565,
|
||||
options::{
|
||||
ColorInversion,
|
||||
ColorOrder,
|
||||
Orientation,
|
||||
Rotation,
|
||||
},
|
||||
Builder,
|
||||
};
|
||||
use xpt2046::Xpt2046;
|
||||
@ -57,7 +70,9 @@ impl AppData {
|
||||
Self {
|
||||
timer_start: Instant::now(),
|
||||
timer_set_duration: Duration::from_secs(10),
|
||||
timer_remaining_duration: Duration::from_secs(10),
|
||||
timer_remaining_duration: Duration::from_secs(
|
||||
10,
|
||||
),
|
||||
timer_running: false,
|
||||
timer_paused: false,
|
||||
}
|
||||
@ -87,7 +102,8 @@ impl AppData {
|
||||
|
||||
fn start_timer(&mut self) {
|
||||
if !self.timer_paused {
|
||||
self.timer_remaining_duration = self.timer_set_duration;
|
||||
self.timer_remaining_duration =
|
||||
self.timer_set_duration;
|
||||
}
|
||||
|
||||
self.timer_start = Instant::now();
|
||||
@ -107,7 +123,8 @@ impl AppData {
|
||||
self.timer_start = Instant::now();
|
||||
self.timer_paused = false;
|
||||
self.timer_running = false;
|
||||
self.timer_remaining_duration = self.timer_set_duration;
|
||||
self.timer_remaining_duration =
|
||||
self.timer_set_duration;
|
||||
}
|
||||
|
||||
fn remaining(&self) -> Duration {
|
||||
@ -135,7 +152,8 @@ impl AppData {
|
||||
}
|
||||
|
||||
fn timer_finished(&self) -> bool {
|
||||
self.timer_running && self.remaining() == Duration::from_secs(0)
|
||||
self.timer_running
|
||||
&& self.remaining() == Duration::from_secs(0)
|
||||
}
|
||||
}
|
||||
|
||||
@ -144,8 +162,8 @@ fn main() -> Result<(), LvError> {
|
||||
const VER_RES: u32 = 240;
|
||||
const LINES: u32 = 20;
|
||||
|
||||
// It is necessary to call this function once. Otherwise some patches to the
|
||||
// runtime implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71
|
||||
// It is necessary to call this function once. Otherwise
|
||||
// some patches to the runtime implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71
|
||||
esp_idf_svc::sys::link_patches();
|
||||
|
||||
// Initialize lvgl
|
||||
@ -174,7 +192,9 @@ fn main() -> Result<(), LvError> {
|
||||
Some(miso), // sdi
|
||||
Some(cs), // cs
|
||||
&DriverConfig::new().dma(Dma::Channel1(4096)),
|
||||
&SpiConfig::new().write_only(true).baudrate(10.MHz().into()),
|
||||
&SpiConfig::new()
|
||||
.write_only(true)
|
||||
.baudrate(10.MHz().into()),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@ -187,8 +207,9 @@ fn main() -> Result<(), LvError> {
|
||||
bklt.set_high().unwrap();
|
||||
|
||||
// Configuration for M5Stack Core Development Kit V1.0
|
||||
// Puts display in landscape mode with the three buttons at the bottom of screen
|
||||
// let mut m5stack_display = Builder::ili9342c_rgb565(di)
|
||||
// Puts display in landscape mode with the three buttons
|
||||
// at the bottom of screen let mut m5stack_display =
|
||||
// Builder::ili9342c_rgb565(di)
|
||||
// .with_display_size(320, 240)
|
||||
// .with_color_order(ColorOrder::Bgr)
|
||||
// .with_orientation(Orientation::Portrait(false))
|
||||
@ -201,23 +222,25 @@ fn main() -> Result<(), LvError> {
|
||||
// .with_orientation(Orientation::Portrait(false))
|
||||
// .with_color_order(ColorOrder::Bgr)
|
||||
// .with_invert_colors(true)
|
||||
// .init(&mut Delay::new_default(), None::<PinDriver<AnyOutputPin, Output>>)
|
||||
// .init(&mut Delay::new_default(),
|
||||
// None::<PinDriver<AnyOutputPin, Output>>)
|
||||
// .unwrap();
|
||||
|
||||
let raw_display = Builder::new(ILI9486Rgb565, di)
|
||||
let raw_display = Builder::new(ILI9341Rgb565, di)
|
||||
.orientation(Orientation {
|
||||
rotation: Rotation::Deg90,
|
||||
mirrored: true,
|
||||
})
|
||||
.color_order(ColorOrder::Bgr)
|
||||
.invert_colors(ColorInversion::Inverted)
|
||||
// .invert_colors(ColorInversion::Inverted)
|
||||
.init(&mut Delay::new_default())
|
||||
.unwrap();
|
||||
|
||||
let mut raw_display = ProfilerDisplay::new(raw_display);
|
||||
|
||||
// Stack size value - 20,000 for 10 lines, 40,000 for 20 lines
|
||||
// let (touch_send, touch_recv) = channel();
|
||||
// Stack size value - 20,000 for 10 lines, 40,000 for
|
||||
// 20 lines let (touch_send, touch_recv) =
|
||||
// channel();
|
||||
let touch_irq = pins.gpio36;
|
||||
let touch_mosi = pins.gpio32;
|
||||
let touch_miso = pins.gpio39;
|
||||
@ -232,7 +255,9 @@ fn main() -> Result<(), LvError> {
|
||||
Some(touch_miso),
|
||||
Some(touch_cs),
|
||||
&DriverConfig::new(),
|
||||
&SpiConfig::new().write_only(true).baudrate(2.MHz().into()),
|
||||
&SpiConfig::new()
|
||||
.write_only(true)
|
||||
.baudrate(2.MHz().into()),
|
||||
)
|
||||
.unwrap(),
|
||||
PinDriver::input(touch_irq).unwrap(),
|
||||
@ -401,15 +426,18 @@ fn main() -> Result<(), LvError> {
|
||||
let mut was_finished = false;
|
||||
let mut last_rem_time: Duration = appdata.remaining() + Duration::from_millis(10);
|
||||
|
||||
let mut last_time = Instant::now();
|
||||
loop {
|
||||
let start_time = Instant::now();
|
||||
let rem_time = appdata.remaining();
|
||||
if rem_time != last_rem_time {
|
||||
let val = CString::new(format!("{:02}:{:02}:{:03}",
|
||||
rem_time.as_secs() / 60,
|
||||
rem_time.as_secs() % 60,
|
||||
rem_time.as_millis() % 1000)).unwrap();
|
||||
|
||||
time.set_text(&val).unwrap();
|
||||
}
|
||||
last_rem_time = rem_time;
|
||||
|
||||
|
||||
@ -426,7 +454,9 @@ fn main() -> Result<(), LvError> {
|
||||
// seconds
|
||||
// delay::FreeRtos::delay_ms(1);
|
||||
|
||||
lvgl::tick_inc(Instant::now().duration_since(start_time));
|
||||
let now_time = Instant::now();
|
||||
lvgl::tick_inc(now_time.duration_since(last_time));
|
||||
last_time = now_time;
|
||||
|
||||
|
||||
let end_time = Instant::now();
|
||||
|
@ -14,3 +14,6 @@ imports_layout = "HorizontalVertical"
|
||||
# Miscellaneous
|
||||
enum_discrim_align_threshold = 25
|
||||
hex_literal_case = "Upper"
|
||||
|
||||
# Length
|
||||
max_width=60
|
||||
|
@ -10,7 +10,7 @@
|
||||
#
|
||||
|
||||
# runner = "espflash --monitor" # Select this runner for espflash v1.x.x
|
||||
runner = "espflash flash --monitor --baud 921600" # Select this runner for espflash v2.x.x
|
||||
# runner = "espflash flash --monitor --baud 921600" # Select this runner for espflash v2.x.x
|
||||
|
||||
# Target specific options
|
||||
[target.thumbv6m-none-eabi]
|
||||
|
4
slint-based/Cargo.lock
generated
4
slint-based/Cargo.lock
generated
@ -2340,9 +2340,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.11"
|
||||
version = "1.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||
checksum = "540654e97a3f4470a492cd30ff187bc95d89557a903a2bbf112e2fae98104ef2"
|
||||
|
||||
[[package]]
|
||||
name = "jni"
|
||||
|
@ -12,7 +12,15 @@ build = "build.rs"
|
||||
# [[bin]]
|
||||
# name = "main"
|
||||
|
||||
[features]
|
||||
starter = []
|
||||
timer = []
|
||||
light-control = []
|
||||
microwave-ui = []
|
||||
simulator = ["slint/backend-winit"]
|
||||
|
||||
[[bin]]
|
||||
|
||||
name = "starter"
|
||||
|
||||
[[bin]]
|
||||
@ -60,19 +68,3 @@ embedded-hal-bus = "0.2.0"
|
||||
slint-build = { version = "1.8" }
|
||||
|
||||
|
||||
[features]
|
||||
simulator = ["slint/backend-winit"]
|
||||
# pico = [
|
||||
# "slint/unsafe-single-threaded",
|
||||
# "slint/libm",
|
||||
# "cortex-m",
|
||||
# "cortex-m-rt",
|
||||
# "embedded-alloc",
|
||||
# "embedded-hal",
|
||||
# "fugit",
|
||||
# "display-interface-spi",
|
||||
# "embedded-graphics-core",
|
||||
# "shared-bus",
|
||||
# "panic-halt"
|
||||
# ]
|
||||
|
||||
|
@ -1,22 +1,26 @@
|
||||
fn main() {
|
||||
#[cfg(feature = "starter")]
|
||||
slint_build::compile_with_config(
|
||||
"ui/app-window.slint",
|
||||
slint_build::CompilerConfiguration::new()
|
||||
.embed_resources(slint_build::EmbedResourcesKind::EmbedForSoftwareRenderer),
|
||||
)
|
||||
.unwrap();
|
||||
#[cfg(feature = "timer")]
|
||||
slint_build::compile_with_config(
|
||||
"ui/timer-app.slint",
|
||||
slint_build::CompilerConfiguration::new()
|
||||
.embed_resources(slint_build::EmbedResourcesKind::EmbedForSoftwareRenderer),
|
||||
)
|
||||
.unwrap();
|
||||
#[cfg(feature = "light-control")]
|
||||
slint_build::compile_with_config(
|
||||
"ui/lights-app.slint",
|
||||
slint_build::CompilerConfiguration::new()
|
||||
.embed_resources(slint_build::EmbedResourcesKind::EmbedForSoftwareRenderer),
|
||||
)
|
||||
.unwrap();
|
||||
#[cfg(feature = "microwave-ui")]
|
||||
slint_build::compile_with_config(
|
||||
"ui/microwave-ui.slint",
|
||||
slint_build::CompilerConfiguration::new()
|
||||
|
@ -1 +1,2 @@
|
||||
use_small_heuristics = "Max"
|
||||
max_width = 60
|
||||
|
@ -26,7 +26,9 @@ use esp_hal::interrupt::Priority;
|
||||
use esp_hal::{self, prelude::*};
|
||||
use esp_hal::{
|
||||
clock::ClockControl,
|
||||
gpio::{GpioPin, Input, Io, Level, Output, Pull, NO_PIN},
|
||||
gpio::{
|
||||
GpioPin, Input, Io, Level, Output, Pull, NO_PIN,
|
||||
},
|
||||
peripherals::{Peripherals, SPI2, SPI3},
|
||||
prelude::*,
|
||||
rtc_cntl::Rtc,
|
||||
@ -38,18 +40,22 @@ use esp_hal_embassy::InterruptExecutor;
|
||||
use esp_println::println;
|
||||
use mipidsi::{
|
||||
models::ILI9486Rgb565,
|
||||
options::{ColorInversion, ColorOrder, Orientation, Rotation},
|
||||
options::{
|
||||
ColorInversion, ColorOrder, Orientation, Rotation,
|
||||
},
|
||||
Builder, Display,
|
||||
};
|
||||
use slint::platform::software_renderer::MinimalSoftwareWindow;
|
||||
use slint::platform::{Platform, PointerEventButton, WindowEvent};
|
||||
use slint::platform::{
|
||||
Platform, PointerEventButton, WindowEvent,
|
||||
};
|
||||
use slint::private_unstable_api::re_exports::LogicalPoint;
|
||||
use slint::LogicalPosition;
|
||||
use static_cell::StaticCell;
|
||||
use xpt2046::Xpt2046;
|
||||
|
||||
use esp_alloc as _;
|
||||
|
||||
use mipidsi::models::ILI9341Rgb565;
|
||||
// slint::slint!{ export MyUI := Window {} }
|
||||
/*
|
||||
slint::include_modules!();
|
||||
@ -59,14 +65,18 @@ slint::include_modules!();
|
||||
|
||||
fn init_heap() {
|
||||
const HEAP_SIZE: usize = 64 * 1024;
|
||||
static mut HEAP: MaybeUninit<[u8; HEAP_SIZE]> = MaybeUninit::uninit();
|
||||
static mut HEAP: MaybeUninit<[u8; HEAP_SIZE]> =
|
||||
MaybeUninit::uninit();
|
||||
|
||||
unsafe {
|
||||
esp_alloc::HEAP.add_region(esp_alloc::HeapRegion::new(
|
||||
esp_alloc::HEAP.add_region(
|
||||
esp_alloc::HeapRegion::new(
|
||||
HEAP.as_mut_ptr() as *mut u8,
|
||||
HEAP_SIZE,
|
||||
esp_alloc::MemoryCapability::Internal.into(),
|
||||
));
|
||||
esp_alloc::MemoryCapability::Internal
|
||||
.into(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,20 +88,31 @@ async fn touch_task(
|
||||
Output<'static, GpioPin<33>>,
|
||||
&'static mut Delay,
|
||||
>,
|
||||
touch_signal: &'static Signal<NoopRawMutex, Option<Point>>,
|
||||
touch_signal: &'static Signal<
|
||||
NoopRawMutex,
|
||||
Option<Point>,
|
||||
>,
|
||||
) -> ! {
|
||||
let mut touch_driver =
|
||||
Xpt2046::new(spi, Input::new(touch_irq, Pull::Up), xpt2046::Orientation::LandscapeFlipped);
|
||||
let mut touch_driver = Xpt2046::new(
|
||||
spi,
|
||||
Input::new(touch_irq, Pull::Up),
|
||||
xpt2046::Orientation::LandscapeFlipped,
|
||||
);
|
||||
touch_driver.set_num_samples(16);
|
||||
touch_driver.init(&mut embassy_time::Delay).unwrap();
|
||||
|
||||
esp_println::println!("touch task");
|
||||
|
||||
loop {
|
||||
touch_driver.run().expect("Running Touch driver failed");
|
||||
touch_driver
|
||||
.run()
|
||||
.expect("Running Touch driver failed");
|
||||
if touch_driver.is_touched() {
|
||||
let point = touch_driver.get_touch_point();
|
||||
touch_signal.signal(Some(Point::new(point.x + 25, 240 - point.y)));
|
||||
touch_signal.signal(Some(Point::new(
|
||||
point.x + 25,
|
||||
240 - point.y,
|
||||
)));
|
||||
} else {
|
||||
touch_signal.signal(None);
|
||||
}
|
||||
@ -112,16 +133,23 @@ struct CYDPlatform {
|
||||
impl Platform for CYDPlatform {
|
||||
fn create_window_adapter(
|
||||
&self,
|
||||
) -> Result<Rc<dyn slint::platform::WindowAdapter>, slint::PlatformError> {
|
||||
) -> Result<
|
||||
Rc<dyn slint::platform::WindowAdapter>,
|
||||
slint::PlatformError,
|
||||
> {
|
||||
Ok(self.window.clone())
|
||||
}
|
||||
|
||||
fn duration_since_start(&self) -> core::time::Duration {
|
||||
embassy_time::Instant::from_millis(0).elapsed().into()
|
||||
embassy_time::Instant::from_millis(0)
|
||||
.elapsed()
|
||||
.into()
|
||||
}
|
||||
|
||||
//noinspection DuplicatedCode
|
||||
fn run_event_loop(&self) -> Result<(), slint::PlatformError> {
|
||||
fn run_event_loop(
|
||||
&self,
|
||||
) -> Result<(), slint::PlatformError> {
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
@ -131,13 +159,17 @@ async fn main(spawner: Spawner) {
|
||||
init_heap();
|
||||
let peripherals = Peripherals::take();
|
||||
let system = SystemControl::new(peripherals.SYSTEM);
|
||||
let mut clocks = ClockControl::boot_defaults(system.clock_control).freeze();
|
||||
let mut clocks =
|
||||
ClockControl::boot_defaults(system.clock_control)
|
||||
.freeze();
|
||||
|
||||
let mut rtc = Rtc::new(peripherals.LPWR);
|
||||
rtc.rwdt.disable();
|
||||
let mut timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks);
|
||||
let mut timer_group0 =
|
||||
TimerGroup::new(peripherals.TIMG0, &clocks);
|
||||
timer_group0.wdt.disable();
|
||||
let mut timer_group1 = TimerGroup::new(peripherals.TIMG1, &clocks);
|
||||
let mut timer_group1 =
|
||||
TimerGroup::new(peripherals.TIMG1, &clocks);
|
||||
timer_group1.wdt.disable();
|
||||
|
||||
esp_hal_embassy::init(&clocks, timer_group0.timer0);
|
||||
@ -151,21 +183,34 @@ async fn main(spawner: Spawner) {
|
||||
let touch_cs = io.pins.gpio33;
|
||||
|
||||
// 2MHz is the MAX! DO NOT DECREASE! This is really important.
|
||||
let mut touch_spi = Spi::new(peripherals.SPI3, 2.MHz(), SpiMode::Mode0, &mut clocks).with_pins(
|
||||
let mut touch_spi = Spi::new(
|
||||
peripherals.SPI3,
|
||||
2.MHz(),
|
||||
SpiMode::Mode0,
|
||||
&mut clocks,
|
||||
)
|
||||
.with_pins(
|
||||
Some(touch_clk),
|
||||
Some(touch_mosi),
|
||||
Some(touch_miso),
|
||||
NO_PIN,
|
||||
);
|
||||
|
||||
static TOUCH_DELAY_STATICCELL: StaticCell<Delay> = StaticCell::new();
|
||||
static TOUCH_DELAY_STATICCELL: StaticCell<Delay> =
|
||||
StaticCell::new();
|
||||
let mut delay = TOUCH_DELAY_STATICCELL.init(Delay);
|
||||
|
||||
let touch_spi =
|
||||
ExclusiveDevice::new(touch_spi, Output::new(touch_cs, Level::Low), delay).unwrap();
|
||||
let touch_spi = ExclusiveDevice::new(
|
||||
touch_spi,
|
||||
Output::new(touch_cs, Level::Low),
|
||||
delay,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let touch_signal = Signal::new();
|
||||
static TOUCH_SIGNAL: StaticCell<Signal<NoopRawMutex, Option<Point>>> = StaticCell::new();
|
||||
static TOUCH_SIGNAL: StaticCell<
|
||||
Signal<NoopRawMutex, Option<Point>>,
|
||||
> = StaticCell::new();
|
||||
let touch_signal = &*TOUCH_SIGNAL.init(touch_signal);
|
||||
|
||||
// let sw_int = system.software_interrupt_control.software_interrupt2;
|
||||
@ -174,7 +219,13 @@ async fn main(spawner: Spawner) {
|
||||
// let executor = InterruptExecutor::<2>::new(sw_int);
|
||||
// let executor = EXECUTOR.init(executor);
|
||||
|
||||
spawner.spawn(touch_task(touch_irq, touch_spi, touch_signal)).unwrap();
|
||||
spawner
|
||||
.spawn(touch_task(
|
||||
touch_irq,
|
||||
touch_spi,
|
||||
touch_signal,
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
// executor.start(Priority::Priority1);
|
||||
|
||||
@ -184,9 +235,16 @@ async fn main(spawner: Spawner) {
|
||||
let mosi = io.pins.gpio13;
|
||||
let cs = io.pins.gpio15;
|
||||
let dc = io.pins.gpio2;
|
||||
let mut backlight = Output::new(io.pins.gpio21, Level::Low);
|
||||
let mut backlight =
|
||||
Output::new(io.pins.gpio21, Level::Low);
|
||||
|
||||
let mut spi = Spi::new(peripherals.SPI2, 10u32.MHz(), SpiMode::Mode0, &clocks).with_pins(
|
||||
let mut spi = Spi::new(
|
||||
peripherals.SPI2,
|
||||
10u32.MHz(),
|
||||
SpiMode::Mode0,
|
||||
&clocks,
|
||||
)
|
||||
.with_pins(
|
||||
Some(sclk),
|
||||
Some(mosi),
|
||||
Some(miso),
|
||||
@ -197,16 +255,26 @@ async fn main(spawner: Spawner) {
|
||||
// let spi_bus = NoopMutex::new(RefCell::new(spi));
|
||||
// let spi_bus = DISP_SPI_BUS.init(spi_bus);
|
||||
|
||||
static spi_delay_staticcell: StaticCell<Delay> = StaticCell::new();
|
||||
static spi_delay_staticcell: StaticCell<Delay> =
|
||||
StaticCell::new();
|
||||
let mut delay = spi_delay_staticcell.init(Delay);
|
||||
let spi = ExclusiveDevice::new(spi, Output::new(cs, Level::Low), delay).unwrap();
|
||||
let spi = ExclusiveDevice::new(
|
||||
spi,
|
||||
Output::new(cs, Level::Low),
|
||||
delay,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let di = SPIInterface::new(spi, Output::new(dc, Level::Low));
|
||||
let di =
|
||||
SPIInterface::new(spi, Output::new(dc, Level::Low));
|
||||
|
||||
let display = Builder::new(ILI9486Rgb565, di)
|
||||
.orientation(Orientation { rotation: Rotation::Deg90, mirrored: true })
|
||||
let display = Builder::new(ILI9341Rgb565, di)
|
||||
.orientation(Orientation {
|
||||
rotation: Rotation::Deg90,
|
||||
mirrored: true,
|
||||
})
|
||||
.color_order(ColorOrder::Bgr)
|
||||
.invert_colors(ColorInversion::Inverted)
|
||||
// .invert_colors(ColorInversion::Inverted)
|
||||
.init(&mut embassy_time::Delay)
|
||||
.unwrap();
|
||||
|
||||
@ -215,10 +283,14 @@ async fn main(spawner: Spawner) {
|
||||
backlight.set_high();
|
||||
|
||||
let size = display.bounding_box().size;
|
||||
let size = slint::PhysicalSize::new(size.width as u32, size.height as u32);
|
||||
// let size = slint::PhysicalSize::new(size.width as u32, size.height as u32);
|
||||
|
||||
let window = MinimalSoftwareWindow::new(Default::default());
|
||||
slint::platform::set_platform(Box::new(CYDPlatform { window: window.clone() })).unwrap();
|
||||
let window =
|
||||
MinimalSoftwareWindow::new(Default::default());
|
||||
slint::platform::set_platform(Box::new(CYDPlatform {
|
||||
window: window.clone(),
|
||||
}))
|
||||
.unwrap();
|
||||
|
||||
let ui = create_slint_app();
|
||||
|
||||
@ -238,16 +310,28 @@ async fn main(spawner: Spawner) {
|
||||
let button = PointerEventButton::Left;
|
||||
let interact = match (touch, last_touch) {
|
||||
(Some(point), Some(_)) => {
|
||||
Some(WindowEvent::PointerMoved { position: point_to_logical_pos(point) })
|
||||
Some(WindowEvent::PointerMoved {
|
||||
position: point_to_logical_pos(
|
||||
point,
|
||||
),
|
||||
})
|
||||
}
|
||||
(Some(point), None) => Some(WindowEvent::PointerPressed {
|
||||
position: point_to_logical_pos(point),
|
||||
(Some(point), None) => {
|
||||
Some(WindowEvent::PointerPressed {
|
||||
position: point_to_logical_pos(
|
||||
point,
|
||||
),
|
||||
button,
|
||||
}),
|
||||
(None, Some(point)) => Some(WindowEvent::PointerReleased {
|
||||
position: point_to_logical_pos(point),
|
||||
})
|
||||
}
|
||||
(None, Some(point)) => {
|
||||
Some(WindowEvent::PointerReleased {
|
||||
position: point_to_logical_pos(
|
||||
point,
|
||||
),
|
||||
button,
|
||||
}),
|
||||
})
|
||||
}
|
||||
(None, None) => None,
|
||||
};
|
||||
if let Some(event) = interact {
|
||||
@ -266,8 +350,6 @@ async fn main(spawner: Spawner) {
|
||||
renderer.render_by_line(&mut buffer_provider);
|
||||
});
|
||||
|
||||
let button = PointerEventButton::Left;
|
||||
|
||||
if window.has_active_animations() {
|
||||
continue;
|
||||
}
|
||||
@ -278,7 +360,8 @@ async fn main(spawner: Spawner) {
|
||||
let draw_time = display.get_time();
|
||||
let prep_time = start_draw_time - start_time;
|
||||
let proc_time = end_time - start_draw_time;
|
||||
let proc_time = proc_time - min(draw_time, proc_time);
|
||||
let proc_time =
|
||||
proc_time - min(draw_time, proc_time);
|
||||
rtc.rwdt.feed();
|
||||
|
||||
if draw_time.as_micros() > 0 {
|
||||
@ -313,9 +396,11 @@ impl<
|
||||
E: core::fmt::Debug,
|
||||
DT: DrawTarget<Color = Rgb565, Error = E>,
|
||||
// RST: OutputPin<Error = core::convert::Infallible>,
|
||||
> slint::platform::software_renderer::LineBufferProvider for &mut DrawBuffer<'_, DT>
|
||||
> slint::platform::software_renderer::LineBufferProvider
|
||||
for &mut DrawBuffer<'_, DT>
|
||||
{
|
||||
type TargetPixel = slint::platform::software_renderer::Rgb565Pixel;
|
||||
type TargetPixel =
|
||||
slint::platform::software_renderer::Rgb565Pixel;
|
||||
|
||||
fn process_line(
|
||||
&mut self,
|
||||
|
@ -4,17 +4,12 @@ extern crate alloc;
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use alloc::rc::Rc;
|
||||
use alloc::sync::Arc;
|
||||
use core::mem::MaybeUninit;
|
||||
use core::{cell::RefCell, cmp::min, fmt};
|
||||
use core::{cell::RefCell, cmp::min};
|
||||
use display_interface_spi::SPIInterface;
|
||||
use embassy_embedded_hal::shared_bus::blocking::spi::SpiDevice;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||
use embassy_sync::{
|
||||
blocking_mutex::{raw::NoopRawMutex, NoopMutex},
|
||||
signal::Signal,
|
||||
};
|
||||
use embassy_sync::signal::Signal;
|
||||
use embassy_time::Delay;
|
||||
use embassy_time::{Duration, Instant, Timer};
|
||||
use embedded_graphics_core::pixelcolor::Rgb565;
|
||||
@ -23,35 +18,33 @@ use embedded_graphics_core::primitives::Rectangle;
|
||||
use embedded_graphics_profiler_display::ProfilerDisplay;
|
||||
use embedded_hal::digital::OutputPin;
|
||||
use embedded_hal_bus::spi::ExclusiveDevice;
|
||||
use esp_backtrace as _;
|
||||
use esp_hal::interrupt::Priority;
|
||||
use esp_hal::{self, prelude::*};
|
||||
use esp_hal::{
|
||||
clock::ClockControl,
|
||||
gpio::{GpioPin, Input, Io, Level, Output, Pull, NO_PIN},
|
||||
peripherals::{Peripherals, SPI2, SPI3},
|
||||
gpio::{
|
||||
GpioPin, Input, Io, Level, Output, Pull, NO_PIN,
|
||||
},
|
||||
peripherals::{Peripherals, SPI3},
|
||||
prelude::*,
|
||||
rtc_cntl::Rtc,
|
||||
spi::{master::Spi, FullDuplexMode, SpiMode},
|
||||
system::SystemControl,
|
||||
timer::timg::TimerGroup,
|
||||
};
|
||||
use esp_hal_embassy::InterruptExecutor;
|
||||
use esp_println::println;
|
||||
use mipidsi::{
|
||||
models::ILI9486Rgb565,
|
||||
options::{ColorInversion, ColorOrder, Orientation, Rotation},
|
||||
Builder, Display,
|
||||
options::{ColorOrder, Orientation, Rotation},
|
||||
Builder,
|
||||
};
|
||||
use slint::platform::software_renderer::MinimalSoftwareWindow;
|
||||
use slint::platform::{Platform, PointerEventButton, WindowEvent};
|
||||
use slint::private_unstable_api::re_exports::LogicalPoint;
|
||||
use slint::platform::{
|
||||
Platform, PointerEventButton, WindowEvent,
|
||||
};
|
||||
use slint::{format, LogicalPosition};
|
||||
use static_cell::StaticCell;
|
||||
use xpt2046::Xpt2046;
|
||||
|
||||
use esp_alloc as _;
|
||||
|
||||
use mipidsi::models::ILI9341Rgb565;
|
||||
// slint::slint!{ export MyUI := Window {} }
|
||||
/*
|
||||
slint::include_modules!();
|
||||
@ -61,14 +54,18 @@ slint::include_modules!();
|
||||
|
||||
fn init_heap() {
|
||||
const HEAP_SIZE: usize = 64 * 1024;
|
||||
static mut HEAP: MaybeUninit<[u8; HEAP_SIZE]> = MaybeUninit::uninit();
|
||||
static mut HEAP: MaybeUninit<[u8; HEAP_SIZE]> =
|
||||
MaybeUninit::uninit();
|
||||
|
||||
unsafe {
|
||||
esp_alloc::HEAP.add_region(esp_alloc::HeapRegion::new(
|
||||
esp_alloc::HEAP.add_region(
|
||||
esp_alloc::HeapRegion::new(
|
||||
HEAP.as_mut_ptr() as *mut u8,
|
||||
HEAP_SIZE,
|
||||
esp_alloc::MemoryCapability::Internal.into(),
|
||||
));
|
||||
esp_alloc::MemoryCapability::Internal
|
||||
.into(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,20 +77,31 @@ async fn touch_task(
|
||||
Output<'static, GpioPin<33>>,
|
||||
&'static mut Delay,
|
||||
>,
|
||||
touch_signal: &'static Signal<CriticalSectionRawMutex, Option<Point>>,
|
||||
touch_signal: &'static Signal<
|
||||
CriticalSectionRawMutex,
|
||||
Option<Point>,
|
||||
>,
|
||||
) -> ! {
|
||||
let mut touch_driver =
|
||||
Xpt2046::new(spi, Input::new(touch_irq, Pull::Up), xpt2046::Orientation::LandscapeFlipped);
|
||||
let mut touch_driver = Xpt2046::new(
|
||||
spi,
|
||||
Input::new(touch_irq, Pull::Up),
|
||||
xpt2046::Orientation::LandscapeFlipped,
|
||||
);
|
||||
touch_driver.set_num_samples(1);
|
||||
touch_driver.init(&mut embassy_time::Delay).unwrap();
|
||||
|
||||
esp_println::println!("touch task");
|
||||
|
||||
loop {
|
||||
touch_driver.run().expect("Running Touch driver failed");
|
||||
touch_driver
|
||||
.run()
|
||||
.expect("Running Touch driver failed");
|
||||
if touch_driver.is_touched() {
|
||||
let point = touch_driver.get_touch_point();
|
||||
touch_signal.signal(Some(Point::new(point.x + 25, 240 - point.y)));
|
||||
touch_signal.signal(Some(Point::new(
|
||||
point.x + 25,
|
||||
240 - point.y,
|
||||
)));
|
||||
} else {
|
||||
touch_signal.signal(None);
|
||||
}
|
||||
@ -114,16 +122,23 @@ struct CYDPlatform {
|
||||
impl Platform for CYDPlatform {
|
||||
fn create_window_adapter(
|
||||
&self,
|
||||
) -> Result<Rc<dyn slint::platform::WindowAdapter>, slint::PlatformError> {
|
||||
) -> Result<
|
||||
Rc<dyn slint::platform::WindowAdapter>,
|
||||
slint::PlatformError,
|
||||
> {
|
||||
Ok(self.window.clone())
|
||||
}
|
||||
|
||||
fn duration_since_start(&self) -> core::time::Duration {
|
||||
embassy_time::Instant::from_millis(0).elapsed().into()
|
||||
embassy_time::Instant::from_millis(0)
|
||||
.elapsed()
|
||||
.into()
|
||||
}
|
||||
|
||||
//noinspection DuplicatedCode
|
||||
fn run_event_loop(&self) -> Result<(), slint::PlatformError> {
|
||||
fn run_event_loop(
|
||||
&self,
|
||||
) -> Result<(), slint::PlatformError> {
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
@ -141,7 +156,9 @@ impl AppData {
|
||||
Self {
|
||||
timer_start: Instant::now(),
|
||||
timer_set_duration: Duration::from_secs(10),
|
||||
timer_remaining_duration: Duration::from_secs(10),
|
||||
timer_remaining_duration: Duration::from_secs(
|
||||
10,
|
||||
),
|
||||
timer_running: false,
|
||||
timer_paused: false,
|
||||
}
|
||||
@ -171,7 +188,8 @@ impl AppData {
|
||||
|
||||
fn start_timer(&mut self) {
|
||||
if !self.timer_paused {
|
||||
self.timer_remaining_duration = self.timer_set_duration;
|
||||
self.timer_remaining_duration =
|
||||
self.timer_set_duration;
|
||||
}
|
||||
|
||||
self.timer_start = Instant::now();
|
||||
@ -191,7 +209,8 @@ impl AppData {
|
||||
self.timer_start = Instant::now();
|
||||
self.timer_paused = false;
|
||||
self.timer_running = false;
|
||||
self.timer_remaining_duration = self.timer_set_duration;
|
||||
self.timer_remaining_duration =
|
||||
self.timer_set_duration;
|
||||
}
|
||||
|
||||
fn remaining(&self) -> Duration {
|
||||
@ -219,7 +238,8 @@ impl AppData {
|
||||
}
|
||||
|
||||
fn timer_finished(&self) -> bool {
|
||||
self.timer_running && self.remaining() == Duration::from_secs(0)
|
||||
self.timer_running
|
||||
&& self.remaining() == Duration::from_secs(0)
|
||||
}
|
||||
}
|
||||
|
||||
@ -228,13 +248,17 @@ async fn main(spawner: Spawner) {
|
||||
init_heap();
|
||||
let peripherals = Peripherals::take();
|
||||
let system = SystemControl::new(peripherals.SYSTEM);
|
||||
let mut clocks = ClockControl::boot_defaults(system.clock_control).freeze();
|
||||
let mut clocks =
|
||||
ClockControl::boot_defaults(system.clock_control)
|
||||
.freeze();
|
||||
|
||||
let mut rtc = Rtc::new(peripherals.LPWR);
|
||||
rtc.rwdt.disable();
|
||||
let mut timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks);
|
||||
let mut timer_group0 =
|
||||
TimerGroup::new(peripherals.TIMG0, &clocks);
|
||||
timer_group0.wdt.disable();
|
||||
let mut timer_group1 = TimerGroup::new(peripherals.TIMG1, &clocks);
|
||||
let mut timer_group1 =
|
||||
TimerGroup::new(peripherals.TIMG1, &clocks);
|
||||
timer_group1.wdt.disable();
|
||||
|
||||
esp_hal_embassy::init(&clocks, timer_group0.timer0);
|
||||
@ -248,22 +272,34 @@ async fn main(spawner: Spawner) {
|
||||
let touch_cs = io.pins.gpio33;
|
||||
|
||||
// 2MHz is the MAX! DO NOT DECREASE! This is really important.
|
||||
let mut touch_spi = Spi::new(peripherals.SPI3, 2.MHz(), SpiMode::Mode0, &mut clocks).with_pins(
|
||||
let mut touch_spi = Spi::new(
|
||||
peripherals.SPI3,
|
||||
2.MHz(),
|
||||
SpiMode::Mode0,
|
||||
&mut clocks,
|
||||
)
|
||||
.with_pins(
|
||||
Some(touch_clk),
|
||||
Some(touch_mosi),
|
||||
Some(touch_miso),
|
||||
NO_PIN,
|
||||
);
|
||||
|
||||
static TOUCH_DELAY_STATICCELL: StaticCell<Delay> = StaticCell::new();
|
||||
static TOUCH_DELAY_STATICCELL: StaticCell<Delay> =
|
||||
StaticCell::new();
|
||||
let mut delay = TOUCH_DELAY_STATICCELL.init(Delay);
|
||||
|
||||
let touch_spi =
|
||||
ExclusiveDevice::new(touch_spi, Output::new(touch_cs, Level::Low), delay).unwrap();
|
||||
let touch_spi = ExclusiveDevice::new(
|
||||
touch_spi,
|
||||
Output::new(touch_cs, Level::Low),
|
||||
delay,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let touch_signal = Signal::new();
|
||||
static TOUCH_SIGNAL: StaticCell<Signal<CriticalSectionRawMutex, Option<Point>>> =
|
||||
StaticCell::new();
|
||||
static TOUCH_SIGNAL: StaticCell<
|
||||
Signal<CriticalSectionRawMutex, Option<Point>>,
|
||||
> = StaticCell::new();
|
||||
let touch_signal = &*TOUCH_SIGNAL.init(touch_signal);
|
||||
|
||||
// let sw_int = system.software_interrupt_control.software_interrupt2;
|
||||
@ -279,7 +315,13 @@ async fn main(spawner: Spawner) {
|
||||
|
||||
// executor
|
||||
// .start(Priority::Priority2)
|
||||
spawner.spawn(touch_task(touch_irq, touch_spi, touch_signal)).unwrap();
|
||||
spawner
|
||||
.spawn(touch_task(
|
||||
touch_irq,
|
||||
touch_spi,
|
||||
touch_signal,
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
// Display setup
|
||||
let sclk = io.pins.gpio14;
|
||||
@ -287,9 +329,16 @@ async fn main(spawner: Spawner) {
|
||||
let mosi = io.pins.gpio13;
|
||||
let cs = io.pins.gpio15;
|
||||
let dc = io.pins.gpio2;
|
||||
let mut backlight = Output::new(io.pins.gpio21, Level::Low);
|
||||
let mut backlight =
|
||||
Output::new(io.pins.gpio21, Level::Low);
|
||||
|
||||
let mut spi = Spi::new(peripherals.SPI2, 10u32.MHz(), SpiMode::Mode0, &clocks).with_pins(
|
||||
let mut spi = Spi::new(
|
||||
peripherals.SPI2,
|
||||
10u32.MHz(),
|
||||
SpiMode::Mode0,
|
||||
&clocks,
|
||||
)
|
||||
.with_pins(
|
||||
Some(sclk),
|
||||
Some(mosi),
|
||||
Some(miso),
|
||||
@ -300,16 +349,26 @@ async fn main(spawner: Spawner) {
|
||||
// let spi_bus = NoopMutex::new(RefCell::new(spi));
|
||||
// let spi_bus = DISP_SPI_BUS.init(spi_bus);
|
||||
|
||||
static SPI_DELAY_STATICCELL: StaticCell<Delay> = StaticCell::new();
|
||||
static SPI_DELAY_STATICCELL: StaticCell<Delay> =
|
||||
StaticCell::new();
|
||||
let mut delay = SPI_DELAY_STATICCELL.init(Delay);
|
||||
let spi = ExclusiveDevice::new(spi, Output::new(cs, Level::Low), delay).unwrap();
|
||||
let spi = ExclusiveDevice::new(
|
||||
spi,
|
||||
Output::new(cs, Level::Low),
|
||||
delay,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let di = SPIInterface::new(spi, Output::new(dc, Level::Low));
|
||||
let di =
|
||||
SPIInterface::new(spi, Output::new(dc, Level::Low));
|
||||
|
||||
let display = Builder::new(ILI9486Rgb565, di)
|
||||
.orientation(Orientation { rotation: Rotation::Deg90, mirrored: true })
|
||||
let display = Builder::new(ILI9341Rgb565, di)
|
||||
.orientation(Orientation {
|
||||
rotation: Rotation::Deg90,
|
||||
mirrored: true,
|
||||
})
|
||||
.color_order(ColorOrder::Bgr)
|
||||
.invert_colors(ColorInversion::Inverted)
|
||||
// .invert_colors(ColorInversion::Inverted)
|
||||
.init(&mut embassy_time::Delay)
|
||||
.unwrap();
|
||||
|
||||
@ -318,10 +377,14 @@ async fn main(spawner: Spawner) {
|
||||
backlight.set_high();
|
||||
|
||||
let size = display.bounding_box().size;
|
||||
let size = slint::PhysicalSize::new(size.width as u32, size.height as u32);
|
||||
// let size = slint::PhysicalSize::new(size.width as u32, size.height as u32);
|
||||
|
||||
let window = MinimalSoftwareWindow::new(Default::default());
|
||||
slint::platform::set_platform(Box::new(CYDPlatform { window: window.clone() })).unwrap();
|
||||
let window =
|
||||
MinimalSoftwareWindow::new(Default::default());
|
||||
slint::platform::set_platform(Box::new(CYDPlatform {
|
||||
window: window.clone(),
|
||||
}))
|
||||
.unwrap();
|
||||
|
||||
let ui = create_slint_app();
|
||||
|
||||
@ -337,15 +400,25 @@ async fn main(spawner: Spawner) {
|
||||
let mut appdata = Rc::new(RefCell::new(AppData::new()));
|
||||
|
||||
let mut cl_appdata = appdata.clone();
|
||||
ui.on_add_10s(move || cl_appdata.borrow_mut().add_secs(10));
|
||||
ui.on_add_10s(move || {
|
||||
cl_appdata.borrow_mut().add_secs(10)
|
||||
});
|
||||
let mut cl_appdata = appdata.clone();
|
||||
ui.on_sub_10s(move || cl_appdata.borrow_mut().sub_secs(10));
|
||||
ui.on_sub_10s(move || {
|
||||
cl_appdata.borrow_mut().sub_secs(10)
|
||||
});
|
||||
let mut cl_appdata = appdata.clone();
|
||||
ui.on_start_timer(move || cl_appdata.borrow_mut().start_timer());
|
||||
ui.on_start_timer(move || {
|
||||
cl_appdata.borrow_mut().start_timer()
|
||||
});
|
||||
let mut cl_appdata = appdata.clone();
|
||||
ui.on_stop_timer(move || cl_appdata.borrow_mut().pause_timer());
|
||||
ui.on_stop_timer(move || {
|
||||
cl_appdata.borrow_mut().pause_timer()
|
||||
});
|
||||
let mut cl_appdata = appdata.clone();
|
||||
ui.on_reset_timer(move || cl_appdata.borrow_mut().reset_timer());
|
||||
ui.on_reset_timer(move || {
|
||||
cl_appdata.borrow_mut().reset_timer()
|
||||
});
|
||||
|
||||
loop {
|
||||
let start_time = Instant::now();
|
||||
@ -354,16 +427,28 @@ async fn main(spawner: Spawner) {
|
||||
let button = PointerEventButton::Left;
|
||||
let interact = match (touch, last_touch) {
|
||||
(Some(point), Some(_)) => {
|
||||
Some(WindowEvent::PointerMoved { position: point_to_logical_pos(point) })
|
||||
Some(WindowEvent::PointerMoved {
|
||||
position: point_to_logical_pos(
|
||||
point,
|
||||
),
|
||||
})
|
||||
}
|
||||
(Some(point), None) => Some(WindowEvent::PointerPressed {
|
||||
position: point_to_logical_pos(point),
|
||||
(Some(point), None) => {
|
||||
Some(WindowEvent::PointerPressed {
|
||||
position: point_to_logical_pos(
|
||||
point,
|
||||
),
|
||||
button,
|
||||
}),
|
||||
(None, Some(point)) => Some(WindowEvent::PointerReleased {
|
||||
position: point_to_logical_pos(point),
|
||||
})
|
||||
}
|
||||
(None, Some(point)) => {
|
||||
Some(WindowEvent::PointerReleased {
|
||||
position: point_to_logical_pos(
|
||||
point,
|
||||
),
|
||||
button,
|
||||
}),
|
||||
})
|
||||
}
|
||||
(None, None) => None,
|
||||
};
|
||||
if let Some(event) = interact {
|
||||
@ -377,11 +462,18 @@ async fn main(spawner: Spawner) {
|
||||
{
|
||||
let appdata = appdata.borrow();
|
||||
let remaining = appdata.remaining();
|
||||
ui.set_show_reset_timer(appdata.timer_finished());
|
||||
ui.set_show_start_timer(
|
||||
!appdata.timer_running() || appdata.timer_paused() && !appdata.timer_finished(),
|
||||
ui.set_show_reset_timer(
|
||||
appdata.timer_finished(),
|
||||
);
|
||||
ui.set_show_start_timer(
|
||||
!appdata.timer_running()
|
||||
|| appdata.timer_paused()
|
||||
&& !appdata.timer_finished(),
|
||||
);
|
||||
ui.set_show_stop_timer(
|
||||
appdata.timer_running()
|
||||
&& !appdata.timer_finished(),
|
||||
);
|
||||
ui.set_show_stop_timer(appdata.timer_running() && !appdata.timer_finished());
|
||||
|
||||
ui.set_timer_text(format!(
|
||||
"{:02}:{:02}:{:03}",
|
||||
@ -400,8 +492,6 @@ async fn main(spawner: Spawner) {
|
||||
renderer.render_by_line(&mut buffer_provider);
|
||||
});
|
||||
|
||||
let button = PointerEventButton::Left;
|
||||
|
||||
if window.has_active_animations() {
|
||||
continue;
|
||||
}
|
||||
@ -412,7 +502,8 @@ async fn main(spawner: Spawner) {
|
||||
let draw_time = display.get_time();
|
||||
let prep_time = start_draw_time - start_time;
|
||||
let proc_time = end_time - start_draw_time;
|
||||
let proc_time = proc_time - min(draw_time, proc_time);
|
||||
let proc_time =
|
||||
proc_time - min(draw_time, proc_time);
|
||||
rtc.rwdt.feed();
|
||||
|
||||
if draw_time.as_micros() > 0 {
|
||||
@ -456,9 +547,11 @@ impl<
|
||||
E: core::fmt::Debug,
|
||||
DT: DrawTarget<Color = Rgb565, Error = E>,
|
||||
// RST: OutputPin<Error = core::convert::Infallible>,
|
||||
> slint::platform::software_renderer::LineBufferProvider for &mut DrawBuffer<'_, DT>
|
||||
> slint::platform::software_renderer::LineBufferProvider
|
||||
for &mut DrawBuffer<'_, DT>
|
||||
{
|
||||
type TargetPixel = slint::platform::software_renderer::Rgb565Pixel;
|
||||
type TargetPixel =
|
||||
slint::platform::software_renderer::Rgb565Pixel;
|
||||
|
||||
fn process_line(
|
||||
&mut self,
|
||||
|
@ -4,17 +4,12 @@ extern crate alloc;
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use alloc::rc::Rc;
|
||||
use alloc::sync::Arc;
|
||||
use core::mem::MaybeUninit;
|
||||
use core::{cell::RefCell, cmp::min, fmt};
|
||||
use core::{cell::RefCell, cmp::min};
|
||||
use display_interface_spi::SPIInterface;
|
||||
use embassy_embedded_hal::shared_bus::blocking::spi::SpiDevice;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||
use embassy_sync::{
|
||||
blocking_mutex::{raw::NoopRawMutex, NoopMutex},
|
||||
signal::Signal,
|
||||
};
|
||||
use embassy_sync::signal::Signal;
|
||||
use embassy_time::Delay;
|
||||
use embassy_time::{Duration, Instant, Timer};
|
||||
use embedded_graphics_core::pixelcolor::Rgb565;
|
||||
@ -23,35 +18,33 @@ use embedded_graphics_core::primitives::Rectangle;
|
||||
use embedded_graphics_profiler_display::ProfilerDisplay;
|
||||
use embedded_hal::digital::OutputPin;
|
||||
use embedded_hal_bus::spi::ExclusiveDevice;
|
||||
use esp_backtrace as _;
|
||||
use esp_hal::interrupt::Priority;
|
||||
use esp_hal::{self, prelude::*};
|
||||
use esp_hal::{
|
||||
clock::ClockControl,
|
||||
gpio::{GpioPin, Input, Io, Level, Output, Pull, NO_PIN},
|
||||
peripherals::{Peripherals, SPI2, SPI3},
|
||||
gpio::{
|
||||
GpioPin, Input, Io, Level, Output, Pull, NO_PIN,
|
||||
},
|
||||
peripherals::{Peripherals, SPI3},
|
||||
prelude::*,
|
||||
rtc_cntl::Rtc,
|
||||
spi::{master::Spi, FullDuplexMode, SpiMode},
|
||||
system::SystemControl,
|
||||
timer::timg::TimerGroup,
|
||||
};
|
||||
use esp_hal_embassy::InterruptExecutor;
|
||||
use esp_println::println;
|
||||
use mipidsi::{
|
||||
models::ILI9486Rgb565,
|
||||
options::{ColorInversion, ColorOrder, Orientation, Rotation},
|
||||
Builder, Display,
|
||||
options::{ColorOrder, Orientation, Rotation},
|
||||
Builder,
|
||||
};
|
||||
use slint::platform::software_renderer::MinimalSoftwareWindow;
|
||||
use slint::platform::{Platform, PointerEventButton, WindowEvent};
|
||||
use slint::private_unstable_api::re_exports::LogicalPoint;
|
||||
use slint::platform::{
|
||||
Platform, PointerEventButton, WindowEvent,
|
||||
};
|
||||
use slint::{format, LogicalPosition};
|
||||
use static_cell::StaticCell;
|
||||
use xpt2046::Xpt2046;
|
||||
|
||||
use esp_alloc as _;
|
||||
|
||||
use mipidsi::models::ILI9341Rgb565;
|
||||
// slint::slint!{ export MyUI := Window {} }
|
||||
/*
|
||||
slint::include_modules!();
|
||||
@ -61,14 +54,18 @@ slint::include_modules!();
|
||||
|
||||
fn init_heap() {
|
||||
const HEAP_SIZE: usize = 32 * 1024;
|
||||
static mut HEAP: MaybeUninit<[u8; HEAP_SIZE]> = MaybeUninit::uninit();
|
||||
static mut HEAP: MaybeUninit<[u8; HEAP_SIZE]> =
|
||||
MaybeUninit::uninit();
|
||||
|
||||
unsafe {
|
||||
esp_alloc::HEAP.add_region(esp_alloc::HeapRegion::new(
|
||||
esp_alloc::HEAP.add_region(
|
||||
esp_alloc::HeapRegion::new(
|
||||
HEAP.as_mut_ptr() as *mut u8,
|
||||
HEAP_SIZE,
|
||||
esp_alloc::MemoryCapability::Internal.into(),
|
||||
));
|
||||
esp_alloc::MemoryCapability::Internal
|
||||
.into(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,20 +77,31 @@ async fn touch_task(
|
||||
Output<'static, GpioPin<33>>,
|
||||
&'static mut Delay,
|
||||
>,
|
||||
touch_signal: &'static Signal<CriticalSectionRawMutex, Option<Point>>,
|
||||
touch_signal: &'static Signal<
|
||||
CriticalSectionRawMutex,
|
||||
Option<Point>,
|
||||
>,
|
||||
) -> ! {
|
||||
let mut touch_driver =
|
||||
Xpt2046::new(spi, Input::new(touch_irq, Pull::Up), xpt2046::Orientation::LandscapeFlipped);
|
||||
let mut touch_driver = Xpt2046::new(
|
||||
spi,
|
||||
Input::new(touch_irq, Pull::Up),
|
||||
xpt2046::Orientation::LandscapeFlipped,
|
||||
);
|
||||
touch_driver.set_num_samples(1);
|
||||
touch_driver.init(&mut embassy_time::Delay).unwrap();
|
||||
|
||||
esp_println::println!("touch task");
|
||||
|
||||
loop {
|
||||
touch_driver.run().expect("Running Touch driver failed");
|
||||
touch_driver
|
||||
.run()
|
||||
.expect("Running Touch driver failed");
|
||||
if touch_driver.is_touched() {
|
||||
let point = touch_driver.get_touch_point();
|
||||
touch_signal.signal(Some(Point::new(point.x + 25, 240 - point.y)));
|
||||
touch_signal.signal(Some(Point::new(
|
||||
point.x + 25,
|
||||
240 - point.y,
|
||||
)));
|
||||
} else {
|
||||
touch_signal.signal(None);
|
||||
}
|
||||
@ -114,16 +122,23 @@ struct CYDPlatform {
|
||||
impl Platform for CYDPlatform {
|
||||
fn create_window_adapter(
|
||||
&self,
|
||||
) -> Result<Rc<dyn slint::platform::WindowAdapter>, slint::PlatformError> {
|
||||
) -> Result<
|
||||
Rc<dyn slint::platform::WindowAdapter>,
|
||||
slint::PlatformError,
|
||||
> {
|
||||
Ok(self.window.clone())
|
||||
}
|
||||
|
||||
fn duration_since_start(&self) -> core::time::Duration {
|
||||
embassy_time::Instant::from_millis(0).elapsed().into()
|
||||
embassy_time::Instant::from_millis(0)
|
||||
.elapsed()
|
||||
.into()
|
||||
}
|
||||
|
||||
//noinspection DuplicatedCode
|
||||
fn run_event_loop(&self) -> Result<(), slint::PlatformError> {
|
||||
fn run_event_loop(
|
||||
&self,
|
||||
) -> Result<(), slint::PlatformError> {
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
@ -141,7 +156,9 @@ impl AppData {
|
||||
Self {
|
||||
timer_start: Instant::now(),
|
||||
timer_set_duration: Duration::from_secs(10),
|
||||
timer_remaining_duration: Duration::from_secs(10),
|
||||
timer_remaining_duration: Duration::from_secs(
|
||||
10,
|
||||
),
|
||||
timer_running: false,
|
||||
timer_paused: false,
|
||||
}
|
||||
@ -171,7 +188,8 @@ impl AppData {
|
||||
|
||||
fn start_timer(&mut self) {
|
||||
if !self.timer_paused {
|
||||
self.timer_remaining_duration = self.timer_set_duration;
|
||||
self.timer_remaining_duration =
|
||||
self.timer_set_duration;
|
||||
}
|
||||
|
||||
self.timer_start = Instant::now();
|
||||
@ -191,7 +209,8 @@ impl AppData {
|
||||
self.timer_start = Instant::now();
|
||||
self.timer_paused = false;
|
||||
self.timer_running = false;
|
||||
self.timer_remaining_duration = self.timer_set_duration;
|
||||
self.timer_remaining_duration =
|
||||
self.timer_set_duration;
|
||||
}
|
||||
|
||||
fn remaining(&self) -> Duration {
|
||||
@ -219,7 +238,8 @@ impl AppData {
|
||||
}
|
||||
|
||||
fn timer_finished(&self) -> bool {
|
||||
self.timer_running && self.remaining() == Duration::from_secs(0)
|
||||
self.timer_running
|
||||
&& self.remaining() == Duration::from_secs(0)
|
||||
}
|
||||
}
|
||||
|
||||
@ -228,13 +248,17 @@ async fn main(spawner: Spawner) {
|
||||
init_heap();
|
||||
let peripherals = Peripherals::take();
|
||||
let system = SystemControl::new(peripherals.SYSTEM);
|
||||
let mut clocks = ClockControl::boot_defaults(system.clock_control).freeze();
|
||||
let mut clocks =
|
||||
ClockControl::boot_defaults(system.clock_control)
|
||||
.freeze();
|
||||
|
||||
let mut rtc = Rtc::new(peripherals.LPWR);
|
||||
rtc.rwdt.disable();
|
||||
let mut timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks);
|
||||
let mut timer_group0 =
|
||||
TimerGroup::new(peripherals.TIMG0, &clocks);
|
||||
timer_group0.wdt.disable();
|
||||
let mut timer_group1 = TimerGroup::new(peripherals.TIMG1, &clocks);
|
||||
let mut timer_group1 =
|
||||
TimerGroup::new(peripherals.TIMG1, &clocks);
|
||||
timer_group1.wdt.disable();
|
||||
|
||||
esp_hal_embassy::init(&clocks, timer_group0.timer0);
|
||||
@ -248,22 +272,34 @@ async fn main(spawner: Spawner) {
|
||||
let touch_cs = io.pins.gpio33;
|
||||
|
||||
// 2MHz is the MAX! DO NOT DECREASE! This is really important.
|
||||
let mut touch_spi = Spi::new(peripherals.SPI3, 2.MHz(), SpiMode::Mode0, &mut clocks).with_pins(
|
||||
let mut touch_spi = Spi::new(
|
||||
peripherals.SPI3,
|
||||
2.MHz(),
|
||||
SpiMode::Mode0,
|
||||
&mut clocks,
|
||||
)
|
||||
.with_pins(
|
||||
Some(touch_clk),
|
||||
Some(touch_mosi),
|
||||
Some(touch_miso),
|
||||
NO_PIN,
|
||||
);
|
||||
|
||||
static TOUCH_DELAY_STATICCELL: StaticCell<Delay> = StaticCell::new();
|
||||
static TOUCH_DELAY_STATICCELL: StaticCell<Delay> =
|
||||
StaticCell::new();
|
||||
let mut delay = TOUCH_DELAY_STATICCELL.init(Delay);
|
||||
|
||||
let touch_spi =
|
||||
ExclusiveDevice::new(touch_spi, Output::new(touch_cs, Level::Low), delay).unwrap();
|
||||
let touch_spi = ExclusiveDevice::new(
|
||||
touch_spi,
|
||||
Output::new(touch_cs, Level::Low),
|
||||
delay,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let touch_signal = Signal::new();
|
||||
static TOUCH_SIGNAL: StaticCell<Signal<CriticalSectionRawMutex, Option<Point>>> =
|
||||
StaticCell::new();
|
||||
static TOUCH_SIGNAL: StaticCell<
|
||||
Signal<CriticalSectionRawMutex, Option<Point>>,
|
||||
> = StaticCell::new();
|
||||
let touch_signal = &*TOUCH_SIGNAL.init(touch_signal);
|
||||
|
||||
// let sw_int = system.software_interrupt_control.software_interrupt2;
|
||||
@ -279,7 +315,13 @@ async fn main(spawner: Spawner) {
|
||||
|
||||
// executor
|
||||
// .start(Priority::Priority2)
|
||||
spawner.spawn(touch_task(touch_irq, touch_spi, touch_signal)).unwrap();
|
||||
spawner
|
||||
.spawn(touch_task(
|
||||
touch_irq,
|
||||
touch_spi,
|
||||
touch_signal,
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
// Display setup
|
||||
let sclk = io.pins.gpio14;
|
||||
@ -287,9 +329,16 @@ async fn main(spawner: Spawner) {
|
||||
let mosi = io.pins.gpio13;
|
||||
let cs = io.pins.gpio15;
|
||||
let dc = io.pins.gpio2;
|
||||
let mut backlight = Output::new(io.pins.gpio21, Level::Low);
|
||||
let mut backlight =
|
||||
Output::new(io.pins.gpio21, Level::Low);
|
||||
|
||||
let mut spi = Spi::new(peripherals.SPI2, 10u32.MHz(), SpiMode::Mode0, &clocks).with_pins(
|
||||
let mut spi = Spi::new(
|
||||
peripherals.SPI2,
|
||||
10u32.MHz(),
|
||||
SpiMode::Mode0,
|
||||
&clocks,
|
||||
)
|
||||
.with_pins(
|
||||
Some(sclk),
|
||||
Some(mosi),
|
||||
Some(miso),
|
||||
@ -300,16 +349,26 @@ async fn main(spawner: Spawner) {
|
||||
// let spi_bus = NoopMutex::new(RefCell::new(spi));
|
||||
// let spi_bus = DISP_SPI_BUS.init(spi_bus);
|
||||
|
||||
static SPI_DELAY_STATICCELL: StaticCell<Delay> = StaticCell::new();
|
||||
static SPI_DELAY_STATICCELL: StaticCell<Delay> =
|
||||
StaticCell::new();
|
||||
let mut delay = SPI_DELAY_STATICCELL.init(Delay);
|
||||
let spi = ExclusiveDevice::new(spi, Output::new(cs, Level::Low), delay).unwrap();
|
||||
let spi = ExclusiveDevice::new(
|
||||
spi,
|
||||
Output::new(cs, Level::Low),
|
||||
delay,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let di = SPIInterface::new(spi, Output::new(dc, Level::Low));
|
||||
let di =
|
||||
SPIInterface::new(spi, Output::new(dc, Level::Low));
|
||||
|
||||
let display = Builder::new(ILI9486Rgb565, di)
|
||||
.orientation(Orientation { rotation: Rotation::Deg90, mirrored: true })
|
||||
let display = Builder::new(ILI9341Rgb565, di)
|
||||
.orientation(Orientation {
|
||||
rotation: Rotation::Deg90,
|
||||
mirrored: true,
|
||||
})
|
||||
.color_order(ColorOrder::Bgr)
|
||||
.invert_colors(ColorInversion::Inverted)
|
||||
// .invert_colors(ColorInversion::Inverted)
|
||||
.init(&mut embassy_time::Delay)
|
||||
.unwrap();
|
||||
|
||||
@ -318,10 +377,14 @@ async fn main(spawner: Spawner) {
|
||||
backlight.set_high();
|
||||
|
||||
let size = display.bounding_box().size;
|
||||
let size = slint::PhysicalSize::new(size.width as u32, size.height as u32);
|
||||
// let size = slint::PhysicalSize::new(size.width as u32, size.height as u32);
|
||||
|
||||
let window = MinimalSoftwareWindow::new(Default::default());
|
||||
slint::platform::set_platform(Box::new(CYDPlatform { window: window.clone() })).unwrap();
|
||||
let window =
|
||||
MinimalSoftwareWindow::new(Default::default());
|
||||
slint::platform::set_platform(Box::new(CYDPlatform {
|
||||
window: window.clone(),
|
||||
}))
|
||||
.unwrap();
|
||||
|
||||
let ui = create_slint_app();
|
||||
|
||||
@ -337,15 +400,25 @@ async fn main(spawner: Spawner) {
|
||||
let mut appdata = Rc::new(RefCell::new(AppData::new()));
|
||||
|
||||
let mut cl_appdata = appdata.clone();
|
||||
ui.on_add_10s(move || cl_appdata.borrow_mut().add_secs(10));
|
||||
ui.on_add_10s(move || {
|
||||
cl_appdata.borrow_mut().add_secs(10)
|
||||
});
|
||||
let mut cl_appdata = appdata.clone();
|
||||
ui.on_sub_10s(move || cl_appdata.borrow_mut().sub_secs(10));
|
||||
ui.on_sub_10s(move || {
|
||||
cl_appdata.borrow_mut().sub_secs(10)
|
||||
});
|
||||
let mut cl_appdata = appdata.clone();
|
||||
ui.on_start_timer(move || cl_appdata.borrow_mut().start_timer());
|
||||
ui.on_start_timer(move || {
|
||||
cl_appdata.borrow_mut().start_timer()
|
||||
});
|
||||
let mut cl_appdata = appdata.clone();
|
||||
ui.on_stop_timer(move || cl_appdata.borrow_mut().pause_timer());
|
||||
ui.on_stop_timer(move || {
|
||||
cl_appdata.borrow_mut().pause_timer()
|
||||
});
|
||||
let mut cl_appdata = appdata.clone();
|
||||
ui.on_reset_timer(move || cl_appdata.borrow_mut().reset_timer());
|
||||
ui.on_reset_timer(move || {
|
||||
cl_appdata.borrow_mut().reset_timer()
|
||||
});
|
||||
|
||||
loop {
|
||||
let start_time = Instant::now();
|
||||
@ -354,16 +427,28 @@ async fn main(spawner: Spawner) {
|
||||
let button = PointerEventButton::Left;
|
||||
let interact = match (touch, last_touch) {
|
||||
(Some(point), Some(_)) => {
|
||||
Some(WindowEvent::PointerMoved { position: point_to_logical_pos(point) })
|
||||
Some(WindowEvent::PointerMoved {
|
||||
position: point_to_logical_pos(
|
||||
point,
|
||||
),
|
||||
})
|
||||
}
|
||||
(Some(point), None) => Some(WindowEvent::PointerPressed {
|
||||
position: point_to_logical_pos(point),
|
||||
(Some(point), None) => {
|
||||
Some(WindowEvent::PointerPressed {
|
||||
position: point_to_logical_pos(
|
||||
point,
|
||||
),
|
||||
button,
|
||||
}),
|
||||
(None, Some(point)) => Some(WindowEvent::PointerReleased {
|
||||
position: point_to_logical_pos(point),
|
||||
})
|
||||
}
|
||||
(None, Some(point)) => {
|
||||
Some(WindowEvent::PointerReleased {
|
||||
position: point_to_logical_pos(
|
||||
point,
|
||||
),
|
||||
button,
|
||||
}),
|
||||
})
|
||||
}
|
||||
(None, None) => None,
|
||||
};
|
||||
if let Some(event) = interact {
|
||||
@ -377,11 +462,18 @@ async fn main(spawner: Spawner) {
|
||||
{
|
||||
let appdata = appdata.borrow();
|
||||
let remaining = appdata.remaining();
|
||||
ui.set_show_reset_timer(appdata.timer_finished());
|
||||
ui.set_show_start_timer(
|
||||
!appdata.timer_running() || appdata.timer_paused() && !appdata.timer_finished(),
|
||||
ui.set_show_reset_timer(
|
||||
appdata.timer_finished(),
|
||||
);
|
||||
ui.set_show_start_timer(
|
||||
!appdata.timer_running()
|
||||
|| appdata.timer_paused()
|
||||
&& !appdata.timer_finished(),
|
||||
);
|
||||
ui.set_show_stop_timer(
|
||||
appdata.timer_running()
|
||||
&& !appdata.timer_finished(),
|
||||
);
|
||||
ui.set_show_stop_timer(appdata.timer_running() && !appdata.timer_finished());
|
||||
|
||||
ui.set_timer_text(format!(
|
||||
"{:02}:{:02}:{:03}",
|
||||
@ -400,8 +492,6 @@ async fn main(spawner: Spawner) {
|
||||
renderer.render_by_line(&mut buffer_provider);
|
||||
});
|
||||
|
||||
let button = PointerEventButton::Left;
|
||||
|
||||
if window.has_active_animations() {
|
||||
continue;
|
||||
}
|
||||
@ -412,7 +502,8 @@ async fn main(spawner: Spawner) {
|
||||
let draw_time = display.get_time();
|
||||
let prep_time = start_draw_time - start_time;
|
||||
let proc_time = end_time - start_draw_time;
|
||||
let proc_time = proc_time - min(draw_time, proc_time);
|
||||
let proc_time =
|
||||
proc_time - min(draw_time, proc_time);
|
||||
rtc.rwdt.feed();
|
||||
|
||||
if draw_time.as_micros() > 0 {
|
||||
@ -456,9 +547,11 @@ impl<
|
||||
E: core::fmt::Debug,
|
||||
DT: DrawTarget<Color = Rgb565, Error = E>,
|
||||
// RST: OutputPin<Error = core::convert::Infallible>,
|
||||
> slint::platform::software_renderer::LineBufferProvider for &mut DrawBuffer<'_, DT>
|
||||
> slint::platform::software_renderer::LineBufferProvider
|
||||
for &mut DrawBuffer<'_, DT>
|
||||
{
|
||||
type TargetPixel = slint::platform::software_renderer::Rgb565Pixel;
|
||||
type TargetPixel =
|
||||
slint::platform::software_renderer::Rgb565Pixel;
|
||||
|
||||
fn process_line(
|
||||
&mut self,
|
||||
|
0
slint/ui.slint
Normal file
0
slint/ui.slint
Normal file
Loading…
Reference in New Issue
Block a user