Compare commits
9 Commits
e9298384c2
...
main
Author | SHA1 | Date | |
---|---|---|---|
061abd74b9 | |||
d0b0de550b | |||
0bfcfd494a | |||
d91b903817 | |||
cb6b214e4d | |||
a33cb94a35 | |||
6446310023 | |||
ef99d64d08 | |||
a83535fd1e |
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,6 +2,7 @@
|
||||
# will have compiled files and executables
|
||||
debug/
|
||||
target/
|
||||
.embuild/
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
|
4
.idea/kolibri-cyd-tester-app-embassy.iml
generated
4
.idea/kolibri-cyd-tester-app-embassy.iml
generated
@ -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]
|
||||
@ -35,8 +38,13 @@ embedded-graphics = "0.8.1"
|
||||
embedded-graphics-profiler-display = { version = "0.1.0", path = "../embedded-graphics-profiler-display" }
|
||||
embedded-hal = "1.0.0"
|
||||
embedded-sdmmc = "0.8.0"
|
||||
esp-backtrace = { version = "0.14.1", features = ["esp32", "println", "exception-handler", "panic-handler"] }
|
||||
esp-hal = { version = "0.20.1", features = ["esp32", "log", "async"] }
|
||||
esp-backtrace = { version = "0.14.1", features = [
|
||||
"esp32",
|
||||
"exception-handler",
|
||||
"panic-handler",
|
||||
"println",
|
||||
] }
|
||||
esp-hal = { version = "0.20.1", features = ["async", "esp32", "log"] }
|
||||
esp-hal-embassy = { version = "0.3.0", features = ["esp32", "log"] }
|
||||
esp-println = { version = "0.11.0", features = ["esp32", "log"] }
|
||||
format_no_std = "1.2.0"
|
||||
@ -47,4 +55,3 @@ profont = "0.7.0"
|
||||
static_cell = { version = "2.1.0", features = ["nightly"] }
|
||||
ufmt = "0.2.0"
|
||||
xpt2046 = { git = "https://github.com/Yandrik/xpt2046.git", version = "0.3.1" }
|
||||
|
||||
|
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();
|
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
|
||||
}
|
||||
}
|
@ -3,6 +3,9 @@ name = "embedded-graphics-profiler-display"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[features]
|
||||
std = []
|
||||
|
||||
[dependencies]
|
||||
atomic = "0.6.0"
|
||||
embassy-time = "0.3.2"
|
||||
|
@ -1,4 +1,4 @@
|
||||
#![no_std]
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
#![no_main]
|
||||
|
||||
mod profiler;
|
||||
|
@ -1,4 +1,7 @@
|
||||
use atomic::Atomic;
|
||||
#[cfg(feature = "std")]
|
||||
use std::time::{Duration, Instant};
|
||||
#[cfg(not(feature = "std"))]
|
||||
use embassy_time::{Duration, Instant};
|
||||
use embedded_graphics::draw_target::DrawTarget;
|
||||
use embedded_graphics::{Drawable, Pixel};
|
||||
|
35
lvgl-based/.cargo/config.toml
Normal file
35
lvgl-based/.cargo/config.toml
Normal file
@ -0,0 +1,35 @@
|
||||
[build]
|
||||
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
|
||||
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/yannik/.rustup/toolchains/esp/xtensa-esp32s3-elf/esp-13.2.0_20230928/xtensa-esp-elf/xtensa-esp-elf/include",
|
||||
]
|
||||
|
||||
[unstable]
|
||||
build-std = ["std", "panic_abort"]
|
||||
|
||||
[env]
|
||||
MCU = "esp32"
|
||||
# Note: this variable is not used by the pio builder (`cargo build --features pio`)
|
||||
ESP_IDF_VERSION = "v5.1.1"
|
||||
|
||||
# The directory that has the lvgl config files - lv_conf.h, lv_drv_conf.h
|
||||
DEP_LV_CONFIG_PATH = { relative = true, value = "lvgl-configs" }
|
||||
|
||||
# Required to make lvgl build correctly otherwise get wrong file type
|
||||
CROSS_COMPILE = "xtensa-esp32-elf"
|
||||
|
||||
# Directory for custom fonts (written in C) that Lvgl can use
|
||||
LVGL_FONTS_DIR = { relative = true, value = "custom-fonts" }
|
||||
|
||||
PATH = "/home/yannik/.rustup/toolchains/esp/xtensa-esp-elf/esp-14.2.0_20240906/xtensa-esp-elf/bin:/home/yannik/.local/share/pnpm:/home/yannik/.local/share/zinit/polaris/bin:/home/yannik/.rustup/toolchains/esp/xtensa-esp-elf/esp-14.2.0_20240906/xtensa-esp-elf/bin:/home/yannik/.surrealdb:/home/yannik/.pyenv/shims:/home/yannik/.pyenv/bin:/home/yannik/.cargo/bin:/home/yannik/.local/bin:/home/yannik/bin:/usr/local/bin:/usr/lib64/ccache:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin:/var/lib/snapd/snap/bin:/home/yannik/development/flutter/bin"
|
||||
LIBCLANG_PATH = "/home/yannik/.rustup/toolchains/esp/xtensa-esp32-elf-clang/esp-15.0.0-20221201/esp-clang/lib"
|
3
lvgl-based/.gitattributes
vendored
Normal file
3
lvgl-based/.gitattributes
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
*.rs linguist-detectable=true
|
||||
*.c linguist-detectable=false
|
||||
*.h linguist-detectable=false
|
42
lvgl-based/.github/workflows/rust_ci.yml
vendored
Normal file
42
lvgl-based/.github/workflows/rust_ci.yml
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
name: Continuous Integration
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- "**/README.md"
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
jobs:
|
||||
rust-checks:
|
||||
name: Rust Checks
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
action:
|
||||
- command: build
|
||||
args: --release
|
||||
- command: fmt
|
||||
args: --all -- --check --color always
|
||||
- command: clippy
|
||||
args: --all-targets --all-features --workspace -- -D warnings
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Enable caching
|
||||
uses: Swatinem/rust-cache@v2
|
||||
- name: Install gcc-multilib
|
||||
run: sudo apt-get install gcc-multilib
|
||||
- name: Setup Rust
|
||||
uses: esp-rs/xtensa-toolchain@v1.5
|
||||
with:
|
||||
default: true
|
||||
buildtargets: esp32
|
||||
ldproxy: true
|
||||
- name: Run command
|
||||
run: cargo ${{ matrix.action.command }} ${{ matrix.action.args }}
|
4
lvgl-based/.gitignore
vendored
Normal file
4
lvgl-based/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
/.vscode
|
||||
/.embuild
|
||||
/target
|
||||
/Cargo.lock
|
77
lvgl-based/Cargo.toml
Normal file
77
lvgl-based/Cargo.toml
Normal file
@ -0,0 +1,77 @@
|
||||
[workspace]
|
||||
|
||||
[package]
|
||||
name = "rust-m5stack-lvgl-demo"
|
||||
version = "0.1.0"
|
||||
authors = ["enelson1001 <ednelson5080@gmail>"]
|
||||
edition = "2021"
|
||||
resolver = "2"
|
||||
rust-version = "1.71"
|
||||
|
||||
[profile.release]
|
||||
opt-level = "s"
|
||||
|
||||
[profile.dev]
|
||||
debug = true # Symbols are nice and they don't increase the size on Flash
|
||||
opt-level = "z"
|
||||
|
||||
[[bin]]
|
||||
name = "starter"
|
||||
|
||||
[[bin]]
|
||||
name = "timer"
|
||||
|
||||
[[bin]]
|
||||
name = "light-control"
|
||||
|
||||
[[bin]]
|
||||
name = "microwave-ui"
|
||||
|
||||
[features]
|
||||
default = ["embassy", "esp-idf-svc/native", "std"]
|
||||
|
||||
pio = ["esp-idf-svc/pio"]
|
||||
std = ["alloc", "esp-idf-svc/binstart", "esp-idf-svc/std"]
|
||||
alloc = ["esp-idf-svc/alloc"]
|
||||
nightly = ["esp-idf-svc/nightly"]
|
||||
experimental = ["esp-idf-svc/experimental"]
|
||||
embassy = [
|
||||
"esp-idf-svc/critical-section",
|
||||
"esp-idf-svc/embassy-sync",
|
||||
"esp-idf-svc/embassy-time-driver",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
log = { version = "0.4", default-features = false }
|
||||
esp-idf-svc = { version = "0.49.1", default-features = false }
|
||||
|
||||
esp-idf-hal = { version = "0.44.1" }
|
||||
esp-idf-sys = { version = "0.35.0" }
|
||||
|
||||
cstr_core = "0.2.1"
|
||||
embedded-graphics-core = "0.4.0"
|
||||
|
||||
lvgl = { version = "0.6.2", default-features = false, features = [
|
||||
"embedded_graphics",
|
||||
"unsafe_no_autoinit",
|
||||
] }
|
||||
|
||||
lvgl-sys = { version = "0.6.2" }
|
||||
|
||||
display-interface-spi = "0.5.0"
|
||||
mipidsi = "0.8.0"
|
||||
static_cell = "2.1.0"
|
||||
|
||||
xpt2046 = { git = "https://github.com/Yandrik/xpt2046.git", version = "0.3.1" }
|
||||
|
||||
embedded-graphics-profiler-display = { version = "0.1.0", path = "../embedded-graphics-profiler-display", features = ["std"] }
|
||||
|
||||
heapless = "0.8.0"
|
||||
|
||||
|
||||
[build-dependencies]
|
||||
embuild = "0.32.0"
|
||||
|
||||
[patch.crates-io]
|
||||
lvgl = { git = "https://github.com/enelson1001/lv_binding_rust" }
|
||||
lvgl-sys = { git = "https://github.com/enelson1001/lv_binding_rust" }
|
102
lvgl-based/README.md
Normal file
102
lvgl-based/README.md
Normal file
@ -0,0 +1,102 @@
|
||||
# Rust M5Stack Lvgl Demo
|
||||
|
||||
The purpose of this demo is to get lv-binding-rust (Lvgl) running on the M5Stack development board
|
||||
|
||||
## Development Board
|
||||
M5Stack Basic Development Kit V1.0 with 16M Flash
|
||||
|
||||
## Overview
|
||||
This application shows how to use lv-binding-rust crate on the M5Stack. The program displays a clock time on a blue backgound screen.
|
||||
The clock time is a simulated time of 21:00 to 21::59 where the seconds are incremented each second and repeats the 00-59 seconds forever.
|
||||
|
||||
## partition-table folder
|
||||
The partition-table folder contains a file called partitons.csv. This file increases the default factory/app partiton from the default of 1M to 3M. This allows us more space for our program and since the flash size is 16M this should not be a problem. This file will be called when we flash the device.
|
||||
|
||||
## custom-fonts folder
|
||||
The custom-fonts folder contains our custom fonts. The customs fonts are converted from TTF fonts using lvgl online font converter at https://lvgl.io/tools/fontconverter. I used https://ttfonts.net to find a font I liked and then downloaded the font. In the lvgl-online-font-converter I used the font name plus the font size for the name of the font. I chose Bpp of 2 bit-per-pixel and set the range of 0x30-0x3A since I only need numbers and the ":" character. After clicking on "Convert" the file will be downloaded. I placed this downloaded file (*.c) into the custom-fonts folder. Then I created a header file which has an extern to my *.c file, along with changing the ifndef and define names.
|
||||
To use this custom font, I added ```LVGL_FONTS_DIR = {relative = true, value = "custom-fonts"}``` to my config.toml under [env]. This allows our font to be compiled when lvgl is compiled.
|
||||
|
||||
## lvgl-configs folder
|
||||
The lvgl-configs folder holds the lv_config.h and lv_drv_conf.h files which are required by lvgl to compile. Everything in lv_drv_conf.h file is set to 0 as I am not using the lvgl drivers. I don't think I changed anything in the lv_conf.h file.
|
||||
|
||||
## Cargo.toml project file
|
||||
I added the following to the "dependencies" section.
|
||||
```
|
||||
esp-idf-hal = { version = "0.42.5" }
|
||||
esp-idf-sys = { version = "0.33.7" }
|
||||
|
||||
cstr_core = "0.2.1"
|
||||
embedded-graphics-core = "0.4.0"
|
||||
|
||||
lvgl = { version = "0.6.2", default-features = false, features = [
|
||||
"embedded_graphics",
|
||||
"unsafe_no_autoinit",
|
||||
] }
|
||||
|
||||
lvgl-sys = { version = "0.6.2" }
|
||||
|
||||
display-interface-spi = "0.4.1"
|
||||
mipidsi = "0.7.1"
|
||||
|
||||
```
|
||||
I also included patch.crates-io section to patch lvgl and lvgl-sys
|
||||
```
|
||||
[patch.crates-io]
|
||||
lvgl = { git = "https://github.com/enelson1001/lv_binding_rust"}
|
||||
lvgl-sys = { git = "https://github.com/enelson1001/lv_binding_rust"}
|
||||
|
||||
```
|
||||
|
||||
## config.toml
|
||||
To get lv-bindings-rust to comple and build I made the following changes to the config.toml file.
|
||||
```
|
||||
[build]
|
||||
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" # 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",
|
||||
]
|
||||
|
||||
[unstable]
|
||||
build-std = ["std", "panic_abort"]
|
||||
|
||||
[env]
|
||||
MCU = "esp32"
|
||||
# Note: this variable is not used by the pio builder (`cargo build --features pio`)
|
||||
ESP_IDF_VERSION = "v5.1.1"
|
||||
|
||||
# The directory that has the lvgl config files - lv_conf.h, lv_drv_conf.h
|
||||
DEP_LV_CONFIG_PATH = { relative = true, value = "lvgl-configs" }
|
||||
|
||||
# Required to make lvgl build correctly otherwise get wrong file type
|
||||
CROSS_COMPILE = "xtensa-esp32-elf"
|
||||
|
||||
# Directory for custom fonts (written in C) that Lvgl can use
|
||||
LVGL_FONTS_DIR = {relative = true, value = "custom-fonts"}
|
||||
```
|
||||
|
||||
## lv-binding-rust fork
|
||||
I updated my fork of lv-binding-rust to include PR153 ie the changes recommended by madwizard-thomas.
|
||||
|
||||
## Flashing the M5Stack
|
||||
I used the following command to flash the M5Stack.
|
||||
```
|
||||
$ cargo espflash flash --partition-table=partition-table/partitions.csv --monitor
|
||||
```
|
||||
|
||||
## Picture of M5stack running the demo
|
||||

|
||||
|
||||
# Versions
|
||||
### v1.0 :
|
||||
- initial release
|
3
lvgl-based/build.rs
Normal file
3
lvgl-based/build.rs
Normal file
@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
embuild::espidf::sysenv::output();
|
||||
}
|
951
lvgl-based/custom-fonts/gotham_bold_80.c
Normal file
951
lvgl-based/custom-fonts/gotham_bold_80.c
Normal file
@ -0,0 +1,951 @@
|
||||
/*******************************************************************************
|
||||
* Size: 80 px
|
||||
* Bpp: 2
|
||||
* Opts:
|
||||
******************************************************************************/
|
||||
|
||||
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
||||
#include "lvgl.h"
|
||||
#else
|
||||
#include "lvgl/lvgl.h"
|
||||
#endif
|
||||
|
||||
#ifndef GOTHAM_BOLD_80
|
||||
#define GOTHAM_BOLD_80 1
|
||||
#endif
|
||||
|
||||
#if GOTHAM_BOLD_80
|
||||
|
||||
/*-----------------
|
||||
* BITMAPS
|
||||
*----------------*/
|
||||
|
||||
/*Store the image of the glyphs*/
|
||||
static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
||||
/* U+0020 " " */
|
||||
|
||||
/* U+0030 "0" */
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0xa, 0xff, 0xff, 0xe4, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, 0xff,
|
||||
0xff, 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0xf, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x0,
|
||||
0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xf8, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x0, 0x0,
|
||||
0x0, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xf4, 0x0, 0x0, 0x7, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0,
|
||||
0x0, 0x0, 0x3f, 0xff, 0xff, 0xff, 0xe4, 0x1,
|
||||
0xbf, 0xff, 0xff, 0xff, 0xe0, 0x0, 0x2, 0xff,
|
||||
0xff, 0xff, 0xf8, 0x0, 0x0, 0x2f, 0xff, 0xff,
|
||||
0xff, 0xc0, 0x0, 0xf, 0xff, 0xff, 0xff, 0x40,
|
||||
0x0, 0x0, 0x1f, 0xff, 0xff, 0xff, 0x80, 0x0,
|
||||
0xbf, 0xff, 0xff, 0xf4, 0x0, 0x0, 0x0, 0x1f,
|
||||
0xff, 0xff, 0xff, 0x0, 0x3, 0xff, 0xff, 0xff,
|
||||
0x80, 0x0, 0x0, 0x0, 0x1f, 0xff, 0xff, 0xfe,
|
||||
0x0, 0x1f, 0xff, 0xff, 0xfc, 0x0, 0x0, 0x0,
|
||||
0x0, 0x2f, 0xff, 0xff, 0xfc, 0x0, 0xff, 0xff,
|
||||
0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xff,
|
||||
0xff, 0xf4, 0x3, 0xff, 0xff, 0xff, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0xbf, 0xff, 0xff, 0xe0, 0x1f,
|
||||
0xff, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0xff, 0xff, 0xff, 0xc0, 0xbf, 0xff, 0xff, 0xc0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xff, 0xff,
|
||||
0x3, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0xb, 0xff, 0xff, 0xfd, 0xf, 0xff, 0xff,
|
||||
0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xff,
|
||||
0xff, 0xf8, 0x7f, 0xff, 0xff, 0xd0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x3f, 0xff, 0xff, 0xe1, 0xff,
|
||||
0xff, 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0xff, 0xff, 0xff, 0xcb, 0xff, 0xff, 0xfc, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xff, 0xff,
|
||||
0x2f, 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0xb, 0xff, 0xff, 0xfc, 0xbf, 0xff, 0xff,
|
||||
0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xff,
|
||||
0xff, 0xf2, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0xbf, 0xff, 0xff, 0xcb, 0xff,
|
||||
0xff, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2,
|
||||
0xff, 0xff, 0xff, 0x2f, 0xff, 0xff, 0xf0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0xb, 0xff, 0xff, 0xfc,
|
||||
0xbf, 0xff, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x2f, 0xff, 0xff, 0xf2, 0xff, 0xff, 0xff,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
|
||||
0xff, 0xc7, 0xff, 0xff, 0xfd, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x3, 0xff, 0xff, 0xff, 0x1f, 0xff,
|
||||
0xff, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf,
|
||||
0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xe0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0xff, 0xd0,
|
||||
0xff, 0xff, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x2, 0xff, 0xff, 0xff, 0x42, 0xff, 0xff, 0xff,
|
||||
0x40, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff,
|
||||
0xfc, 0x7, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x3f, 0xff, 0xff, 0xf0, 0xf, 0xff,
|
||||
0xff, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff,
|
||||
0xff, 0xff, 0x80, 0x3f, 0xff, 0xff, 0xf8, 0x0,
|
||||
0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xfc, 0x0,
|
||||
0xbf, 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0,
|
||||
0xbf, 0xff, 0xff, 0xf0, 0x0, 0xff, 0xff, 0xff,
|
||||
0xf0, 0x0, 0x0, 0x0, 0x7, 0xff, 0xff, 0xff,
|
||||
0x40, 0x2, 0xff, 0xff, 0xff, 0xf0, 0x0, 0x0,
|
||||
0x0, 0x7f, 0xff, 0xff, 0xfc, 0x0, 0x3, 0xff,
|
||||
0xff, 0xff, 0xf0, 0x0, 0x0, 0x7, 0xff, 0xff,
|
||||
0xff, 0xd0, 0x0, 0xb, 0xff, 0xff, 0xff, 0xf4,
|
||||
0x0, 0x0, 0xbf, 0xff, 0xff, 0xff, 0x0, 0x0,
|
||||
0xf, 0xff, 0xff, 0xff, 0xfe, 0x41, 0x6f, 0xff,
|
||||
0xff, 0xff, 0xf4, 0x0, 0x0, 0x1f, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80,
|
||||
0x0, 0x0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xfc, 0x0, 0x0, 0x0, 0x3f,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xd0, 0x0, 0x0, 0x0, 0x3f, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xfd, 0x0, 0x0, 0x0,
|
||||
0x0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, 0xff,
|
||||
0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x1, 0xff, 0xff, 0xff, 0xff, 0x80,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x1a, 0xff, 0xfe, 0x40, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0,
|
||||
|
||||
/* U+0031 "1" */
|
||||
0x0, 0x0, 0x0, 0x1, 0xbf, 0xff, 0xd0, 0x0,
|
||||
0x0, 0x6, 0xff, 0xff, 0xfd, 0x0, 0x0, 0x2f,
|
||||
0xff, 0xff, 0xff, 0xd0, 0x1, 0xbf, 0xff, 0xff,
|
||||
0xff, 0xfd, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xd3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0x2f,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xd1, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xfd, 0xf, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xd0, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xfd, 0xb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd0,
|
||||
0x7f, 0xff, 0xff, 0xff, 0xff, 0xfd, 0x3, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xd0, 0x3f, 0xfe, 0x43,
|
||||
0xff, 0xff, 0xfd, 0x2, 0xe4, 0x0, 0x3f, 0xff,
|
||||
0xff, 0xd0, 0x0, 0x0, 0x3, 0xff, 0xff, 0xfd,
|
||||
0x0, 0x0, 0x0, 0x3f, 0xff, 0xff, 0xd0, 0x0,
|
||||
0x0, 0x3, 0xff, 0xff, 0xfd, 0x0, 0x0, 0x0,
|
||||
0x3f, 0xff, 0xff, 0xd0, 0x0, 0x0, 0x3, 0xff,
|
||||
0xff, 0xfd, 0x0, 0x0, 0x0, 0x3f, 0xff, 0xff,
|
||||
0xd0, 0x0, 0x0, 0x3, 0xff, 0xff, 0xfd, 0x0,
|
||||
0x0, 0x0, 0x3f, 0xff, 0xff, 0xd0, 0x0, 0x0,
|
||||
0x3, 0xff, 0xff, 0xfd, 0x0, 0x0, 0x0, 0x3f,
|
||||
0xff, 0xff, 0xd0, 0x0, 0x0, 0x3, 0xff, 0xff,
|
||||
0xfd, 0x0, 0x0, 0x0, 0x3f, 0xff, 0xff, 0xd0,
|
||||
0x0, 0x0, 0x3, 0xff, 0xff, 0xfd, 0x0, 0x0,
|
||||
0x0, 0x3f, 0xff, 0xff, 0xd0, 0x0, 0x0, 0x3,
|
||||
0xff, 0xff, 0xfd, 0x0, 0x0, 0x0, 0x3f, 0xff,
|
||||
0xff, 0xd0, 0x0, 0x0, 0x3, 0xff, 0xff, 0xfd,
|
||||
0x0, 0x0, 0x0, 0x3f, 0xff, 0xff, 0xd0, 0x0,
|
||||
0x0, 0x3, 0xff, 0xff, 0xfd, 0x0, 0x0, 0x0,
|
||||
0x3f, 0xff, 0xff, 0xd0, 0x0, 0x0, 0x3, 0xff,
|
||||
0xff, 0xfd, 0x0, 0x0, 0x0, 0x3f, 0xff, 0xff,
|
||||
0xd0, 0x0, 0x0, 0x3, 0xff, 0xff, 0xfd, 0x0,
|
||||
0x0, 0x0, 0x3f, 0xff, 0xff, 0xd0, 0x0, 0x0,
|
||||
0x3, 0xff, 0xff, 0xfd, 0x0, 0x0, 0x0, 0x3f,
|
||||
0xff, 0xff, 0xd0, 0x0, 0x0, 0x3, 0xff, 0xff,
|
||||
0xfd, 0x0, 0x0, 0x0, 0x3f, 0xff, 0xff, 0xd0,
|
||||
0x0, 0x0, 0x3, 0xff, 0xff, 0xfd, 0x0, 0x0,
|
||||
0x0, 0x3f, 0xff, 0xff, 0xd0, 0x0, 0x0, 0x3,
|
||||
0xff, 0xff, 0xfd, 0x0, 0x0, 0x0, 0x3f, 0xff,
|
||||
0xff, 0xd0, 0x0, 0x0, 0x3, 0xff, 0xff, 0xfd,
|
||||
0x0, 0x0, 0x0, 0x3f, 0xff, 0xff, 0xd0, 0x0,
|
||||
0x0, 0x3, 0xff, 0xff, 0xfd, 0x0, 0x0, 0x0,
|
||||
0x3f, 0xff, 0xff, 0xd0, 0x0, 0x0, 0x3, 0xff,
|
||||
0xff, 0xfd, 0x0, 0x0, 0x0, 0x3f, 0xff, 0xff,
|
||||
0xd0, 0x0, 0x0, 0x3, 0xff, 0xff, 0xfd, 0x0,
|
||||
0x0, 0x0, 0x3f, 0xff, 0xff, 0xd0, 0x0, 0x0,
|
||||
0x3, 0xff, 0xff, 0xfd, 0x0, 0x0, 0x0, 0x3f,
|
||||
0xff, 0xff, 0xd0,
|
||||
|
||||
/* U+0032 "2" */
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xbf,
|
||||
0xff, 0xf9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x2, 0xff, 0xff, 0xff, 0xff, 0xd0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0xbf, 0xff, 0xff, 0xff, 0xff,
|
||||
0xf8, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xfd, 0x0, 0x0, 0x0, 0x2,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0x0,
|
||||
0x0, 0x0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xfd, 0x0, 0x0, 0x3, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xfd, 0x0, 0x0, 0x3f,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc,
|
||||
0x0, 0x3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xf8, 0x0, 0x2f, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x2, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xe0, 0xf, 0xff, 0xff, 0xff, 0xf9, 0x0, 0x7f,
|
||||
0xff, 0xff, 0xff, 0xc0, 0x1f, 0xff, 0xff, 0xfe,
|
||||
0x0, 0x0, 0x1f, 0xff, 0xff, 0xff, 0x0, 0xf,
|
||||
0xff, 0xff, 0xc0, 0x0, 0x0, 0x1f, 0xff, 0xff,
|
||||
0xfd, 0x0, 0xb, 0xff, 0xfc, 0x0, 0x0, 0x0,
|
||||
0x2f, 0xff, 0xff, 0xf8, 0x0, 0x7, 0xff, 0xc0,
|
||||
0x0, 0x0, 0x0, 0x3f, 0xff, 0xff, 0xe0, 0x0,
|
||||
0x7, 0xfc, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
|
||||
0xff, 0xc0, 0x0, 0x3, 0xc0, 0x0, 0x0, 0x0,
|
||||
0x3, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xf8, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xff,
|
||||
0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0xff, 0xff, 0xff, 0x80, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x7, 0xff, 0xff, 0xfd, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xff,
|
||||
0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0xff, 0xff, 0xff, 0xc0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xfe, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xff,
|
||||
0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0xb, 0xff, 0xff, 0xff, 0x80, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0xbf, 0xff, 0xff, 0xfc, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, 0xff,
|
||||
0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0xbf, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0xf, 0xff, 0xff, 0xff, 0xf0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff,
|
||||
0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f,
|
||||
0xff, 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x1, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0xff,
|
||||
0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff,
|
||||
0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x3f, 0xff, 0xff, 0xff, 0xd0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x7, 0xff, 0xff, 0xff, 0xfd,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xff,
|
||||
0xff, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0xb, 0xff, 0xff, 0xff, 0xf8, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0x40,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xff, 0xff,
|
||||
0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
|
||||
0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x2f, 0xff, 0xff, 0xff, 0xe0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xff, 0xff,
|
||||
0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f,
|
||||
0xff, 0xff, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x7, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xaa,
|
||||
0xaa, 0xaa, 0xaa, 0xa9, 0x3f, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf4, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xd3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0x4f, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0x3f,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xf4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xd3, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x4f,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xfd, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xf4, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd0,
|
||||
|
||||
/* U+0033 "3" */
|
||||
0x1, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
||||
0xaa, 0xaa, 0x80, 0xb, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x2f, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc,
|
||||
0x0, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xf0, 0x2, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xb, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0x0, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xfc, 0x0, 0xbf, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x2, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xc0, 0xb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0x0, 0x2f, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xff,
|
||||
0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff,
|
||||
0xff, 0xff, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0xf, 0xff, 0xff, 0xff, 0x40, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xf4,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff,
|
||||
0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0xff, 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xff, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
|
||||
0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0xf, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xf0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff,
|
||||
0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0xff, 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0xf, 0xff, 0xff, 0xff, 0x80, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff,
|
||||
0xff, 0xf9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0, 0x0,
|
||||
0x0, 0x0, 0xb, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xe0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0,
|
||||
0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xf0, 0x0, 0x0, 0x0, 0x2, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xe0, 0x0, 0x0, 0x0,
|
||||
0x7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0x0, 0x0, 0x0, 0xa, 0xaa, 0xaf, 0xff, 0xff,
|
||||
0xff, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x1, 0xbf, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x3f, 0xff, 0xff, 0xfd,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f,
|
||||
0xff, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x3f, 0xff, 0xff, 0xf0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0xff,
|
||||
0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x3, 0xff, 0xff, 0xfc, 0x0, 0x0,
|
||||
0x80, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff,
|
||||
0xf0, 0x0, 0xf, 0xc0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x3f, 0xff, 0xff, 0xc0, 0x0, 0xff, 0xc0, 0x0,
|
||||
0x0, 0x0, 0x2, 0xff, 0xff, 0xff, 0x0, 0xf,
|
||||
0xff, 0xc0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff,
|
||||
0xf8, 0x0, 0xff, 0xff, 0xe0, 0x0, 0x0, 0x0,
|
||||
0xbf, 0xff, 0xff, 0xd0, 0xf, 0xff, 0xff, 0xf4,
|
||||
0x0, 0x0, 0xf, 0xff, 0xff, 0xff, 0x0, 0xff,
|
||||
0xff, 0xff, 0xfe, 0x50, 0x6, 0xff, 0xff, 0xff,
|
||||
0xfc, 0xf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xd0, 0xbf, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xf0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0x80, 0x0, 0xbf, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x0, 0x0,
|
||||
0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xc0, 0x0, 0x0, 0x3f, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x1f, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x40, 0x0, 0x0,
|
||||
0x0, 0xb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x1, 0xbf, 0xff, 0xff,
|
||||
0xff, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x6, 0xbf, 0xff, 0xe4, 0x0, 0x0, 0x0, 0x0,
|
||||
|
||||
/* U+0034 "4" */
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3,
|
||||
0xff, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xfe, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x2f, 0xff, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0xb, 0xff, 0xff, 0xfe,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x1, 0xff, 0xff, 0xff, 0xe0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0xff,
|
||||
0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0xf, 0xff, 0xff, 0xff, 0xe0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xff,
|
||||
0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xff,
|
||||
0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0xb, 0xff, 0xff, 0xff, 0xff, 0xe0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xff,
|
||||
0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x7f, 0xff, 0xff, 0xff, 0xff,
|
||||
0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf,
|
||||
0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x3, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0xb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x1, 0xff, 0xff, 0xff,
|
||||
0xcf, 0xff, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x7f, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xfe,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff,
|
||||
0xfc, 0xf, 0xff, 0xff, 0xe0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x3, 0xff, 0xff, 0xff, 0x40, 0xff, 0xff,
|
||||
0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
|
||||
0xff, 0xd0, 0xf, 0xff, 0xff, 0xe0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x2f, 0xff, 0xff, 0xf8, 0x0, 0xff,
|
||||
0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xb, 0xff,
|
||||
0xff, 0xfe, 0x0, 0xf, 0xff, 0xff, 0xe0, 0x0,
|
||||
0x0, 0x0, 0x1, 0xff, 0xff, 0xff, 0xc0, 0x0,
|
||||
0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x7f,
|
||||
0xff, 0xff, 0xf0, 0x0, 0xf, 0xff, 0xff, 0xe0,
|
||||
0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xfc, 0x0,
|
||||
0x0, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x3,
|
||||
0xff, 0xff, 0xff, 0x40, 0x0, 0xf, 0xff, 0xff,
|
||||
0xe0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xe0,
|
||||
0x0, 0x0, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0,
|
||||
0x2f, 0xff, 0xff, 0xf8, 0x0, 0x0, 0xf, 0xff,
|
||||
0xff, 0xe0, 0x0, 0x0, 0xb, 0xff, 0xff, 0xff,
|
||||
0x0, 0x0, 0x0, 0xff, 0xff, 0xfe, 0x0, 0x0,
|
||||
0x1, 0xff, 0xff, 0xff, 0xc0, 0x0, 0x0, 0xf,
|
||||
0xff, 0xff, 0xe0, 0x0, 0x0, 0x3f, 0xff, 0xff,
|
||||
0xf0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xfe, 0x0,
|
||||
0x0, 0xf, 0xff, 0xff, 0xfd, 0x0, 0x0, 0x0,
|
||||
0xf, 0xff, 0xff, 0xe0, 0x0, 0x3, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xfc, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xc1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xfc, 0xf, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xb, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff,
|
||||
0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0xff, 0xff, 0xfe, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf,
|
||||
0xff, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xfe, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0xf, 0xff, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xfe,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0xf, 0xff, 0xff, 0xe0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
|
||||
0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0xf, 0xff, 0xff, 0xe0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff,
|
||||
0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xe0, 0x0,
|
||||
0x0,
|
||||
|
||||
/* U+0035 "5" */
|
||||
0x0, 0xf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0x0, 0x0, 0x7f, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xfc, 0x0, 0x1, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0,
|
||||
0x0, 0x7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xc0, 0x0, 0x1f, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0xbf,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc,
|
||||
0x0, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xf0, 0x0, 0xb, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0, 0x2f,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xfc, 0x0, 0x3, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0, 0xf,
|
||||
0xff, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x3f, 0xff, 0xff, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xfc,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3,
|
||||
0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0xf, 0xff, 0xff, 0xc0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xff, 0xff,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0xff, 0xff, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x7, 0xff, 0xff, 0xf0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xff, 0xff,
|
||||
0xc1, 0xab, 0xea, 0x50, 0x0, 0x0, 0x0, 0x0,
|
||||
0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0,
|
||||
0x0, 0x0, 0x1, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0x80, 0x0, 0x0, 0xb, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x0, 0x0,
|
||||
0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xf0, 0x0, 0x0, 0xbf, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xf0, 0x0, 0x2, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0,
|
||||
0xb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xe0, 0x0, 0x1f, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xd0, 0x0, 0xf, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0x0, 0xb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0x40, 0x0, 0x3, 0xff, 0xe5, 0x0,
|
||||
0x17, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x2,
|
||||
0xe4, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xfc,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf,
|
||||
0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0xbf, 0xff, 0xff, 0xd0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff,
|
||||
0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2,
|
||||
0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0xb, 0xff, 0xff, 0xf8, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xff, 0xff,
|
||||
0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x7f, 0xff, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x2, 0xff, 0xff, 0xfe, 0x0, 0x3,
|
||||
0xc0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff,
|
||||
0xf4, 0x0, 0x2f, 0xd0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x3f, 0xff, 0xff, 0xd0, 0x2, 0xff, 0xe0, 0x0,
|
||||
0x0, 0x0, 0x3, 0xff, 0xff, 0xff, 0x0, 0x1f,
|
||||
0xff, 0xf4, 0x0, 0x0, 0x0, 0x2f, 0xff, 0xff,
|
||||
0xfc, 0x0, 0xff, 0xff, 0xfd, 0x0, 0x0, 0x7,
|
||||
0xff, 0xff, 0xff, 0xe0, 0xf, 0xff, 0xff, 0xff,
|
||||
0xa5, 0x56, 0xff, 0xff, 0xff, 0xff, 0x0, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xf8, 0xb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xc0, 0x7f, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x7f,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xf0, 0x0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0x0, 0x0, 0x3f, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0, 0x0,
|
||||
0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0x0, 0x0, 0x0, 0xb, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x2, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xf8, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x7f, 0xff, 0xff, 0xff, 0xfe, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0xbf, 0xff,
|
||||
0xe9, 0x0, 0x0, 0x0, 0x0,
|
||||
|
||||
/* U+0036 "6" */
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x50, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2,
|
||||
0xff, 0xff, 0xff, 0x90, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x2f, 0xff, 0xff, 0xff, 0xff, 0x90,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0x40, 0x0, 0x0, 0x0, 0x1,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x0,
|
||||
0x0, 0x0, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xd0, 0x0, 0x0, 0x3, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0,
|
||||
0x3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xc0, 0x0, 0x2, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xd0, 0x0, 0x2, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0,
|
||||
0x0, 0x1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xf0, 0x0, 0x0, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x0, 0x0,
|
||||
0x7f, 0xff, 0xff, 0xff, 0xd0, 0x1, 0xbf, 0xff,
|
||||
0xf8, 0x0, 0x0, 0x3f, 0xff, 0xff, 0xff, 0x40,
|
||||
0x0, 0x0, 0xbf, 0xfc, 0x0, 0x0, 0x1f, 0xff,
|
||||
0xff, 0xff, 0x0, 0x0, 0x0, 0x3, 0xfd, 0x0,
|
||||
0x0, 0xf, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0,
|
||||
0x0, 0x2e, 0x0, 0x0, 0x7, 0xff, 0xff, 0xff,
|
||||
0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x2,
|
||||
0xff, 0xff, 0xff, 0x40, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xc0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xff,
|
||||
0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x1f, 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0xb, 0xff, 0xff, 0xfc,
|
||||
0x0, 0x0, 0x54, 0x0, 0x0, 0x0, 0x0, 0x3,
|
||||
0xff, 0xff, 0xfe, 0x0, 0x6f, 0xff, 0xff, 0x90,
|
||||
0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x42, 0xff,
|
||||
0xff, 0xff, 0xff, 0xd0, 0x0, 0x0, 0x3f, 0xff,
|
||||
0xff, 0xd7, 0xff, 0xff, 0xff, 0xff, 0xff, 0x40,
|
||||
0x0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xf8, 0x0, 0x7, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x2,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xfc, 0x0, 0xbf, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x2f, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xf8, 0xb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0x42, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0,
|
||||
0xbf, 0xff, 0xff, 0xff, 0xf9, 0x0, 0x1b, 0xff,
|
||||
0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xd0,
|
||||
0x0, 0x0, 0x1f, 0xff, 0xff, 0xff, 0x8b, 0xff,
|
||||
0xff, 0xff, 0xc0, 0x0, 0x0, 0x0, 0xff, 0xff,
|
||||
0xff, 0xf2, 0xff, 0xff, 0xff, 0xd0, 0x0, 0x0,
|
||||
0x0, 0x1f, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff,
|
||||
0xe0, 0x0, 0x0, 0x0, 0x2, 0xff, 0xff, 0xff,
|
||||
0x1f, 0xff, 0xff, 0xf4, 0x0, 0x0, 0x0, 0x0,
|
||||
0x3f, 0xff, 0xff, 0xd7, 0xff, 0xff, 0xfc, 0x0,
|
||||
0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xf4, 0xff,
|
||||
0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff,
|
||||
0xff, 0xfd, 0x3f, 0xff, 0xff, 0xc0, 0x0, 0x0,
|
||||
0x0, 0x0, 0xff, 0xff, 0xff, 0x4f, 0xff, 0xff,
|
||||
0xf0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xff, 0xff,
|
||||
0xd2, 0xff, 0xff, 0xfc, 0x0, 0x0, 0x0, 0x0,
|
||||
0xf, 0xff, 0xff, 0xf4, 0x7f, 0xff, 0xff, 0x80,
|
||||
0x0, 0x0, 0x0, 0x7, 0xff, 0xff, 0xfc, 0xf,
|
||||
0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x3, 0xff,
|
||||
0xff, 0xff, 0x2, 0xff, 0xff, 0xff, 0x0, 0x0,
|
||||
0x0, 0x2, 0xff, 0xff, 0xff, 0x80, 0x3f, 0xff,
|
||||
0xff, 0xf0, 0x0, 0x0, 0x3, 0xff, 0xff, 0xff,
|
||||
0xc0, 0xf, 0xff, 0xff, 0xff, 0x90, 0x0, 0xb,
|
||||
0xff, 0xff, 0xff, 0xf0, 0x1, 0xff, 0xff, 0xff,
|
||||
0xff, 0xea, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x0,
|
||||
0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xf8, 0x0, 0x3, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xfc, 0x0, 0x0, 0x7f,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd,
|
||||
0x0, 0x0, 0x7, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xfd, 0x0, 0x0, 0x0, 0x7f, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0x0, 0x0,
|
||||
0x0, 0x7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xfd, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x0,
|
||||
0x1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x6, 0xff, 0xff, 0xff,
|
||||
0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x6, 0xbf, 0xff, 0xe4, 0x0, 0x0, 0x0, 0x0,
|
||||
|
||||
/* U+0037 "7" */
|
||||
0x6a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
||||
0xaa, 0xaa, 0xaf, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xeb, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f,
|
||||
0xff, 0xff, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0xf, 0xff, 0xff, 0xfc, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0xb, 0xff, 0xff, 0xfe, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xff,
|
||||
0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2,
|
||||
0xff, 0xff, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x1, 0xff, 0xff, 0xff, 0xc0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xe0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff,
|
||||
0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x3f, 0xff, 0xff, 0xf4, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x1f, 0xff, 0xff, 0xfc, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xfd,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xff,
|
||||
0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x3, 0xff, 0xff, 0xff, 0x40, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x2, 0xff, 0xff, 0xff, 0xc0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff,
|
||||
0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff,
|
||||
0xff, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x7f, 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x3f, 0xff, 0xff, 0xf8, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xff, 0xff,
|
||||
0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf,
|
||||
0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0xb, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x3, 0xff, 0xff, 0xff, 0x80,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, 0xff,
|
||||
0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0xff, 0xff, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0xbf, 0xff, 0xff, 0xf0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0xff, 0xf4,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xff,
|
||||
0xff, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x1f, 0xff, 0xff, 0xfd, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0xf, 0xff, 0xff, 0xff, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x7, 0xff, 0xff, 0xff,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff,
|
||||
0xff, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x2, 0xff, 0xff, 0xff, 0xc0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xe0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xff, 0xff,
|
||||
0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f,
|
||||
0xff, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x3f, 0xff, 0xff, 0xfc, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x1f, 0xff, 0xff, 0xfd, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff,
|
||||
0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7,
|
||||
0xff, 0xff, 0xff, 0x40, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x3, 0xff, 0xff, 0xff, 0xc0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x2, 0xff, 0xff, 0xff, 0xd0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
|
||||
0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0xbf, 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x3f, 0xff, 0xff, 0xf8, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0xfc,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, 0x55,
|
||||
0x55, 0x55, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0,
|
||||
|
||||
/* U+0038 "8" */
|
||||
0x0, 0x0, 0x0, 0x0, 0x6f, 0xff, 0xf9, 0x40,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xff,
|
||||
0xff, 0xff, 0xf9, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xfc, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x40, 0x0, 0x0,
|
||||
0x3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xe0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xf4, 0x0, 0x0, 0x3f, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0x0,
|
||||
0x0, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x40, 0x2, 0xff,
|
||||
0xff, 0xff, 0xfe, 0x55, 0x6f, 0xff, 0xff, 0xff,
|
||||
0xc0, 0x3, 0xff, 0xff, 0xff, 0xd0, 0x0, 0x3,
|
||||
0xff, 0xff, 0xff, 0xc0, 0x3, 0xff, 0xff, 0xff,
|
||||
0x0, 0x0, 0x0, 0xbf, 0xff, 0xff, 0xe0, 0x7,
|
||||
0xff, 0xff, 0xfd, 0x0, 0x0, 0x0, 0x3f, 0xff,
|
||||
0xff, 0xe0, 0x7, 0xff, 0xff, 0xf8, 0x0, 0x0,
|
||||
0x0, 0x1f, 0xff, 0xff, 0xf0, 0x7, 0xff, 0xff,
|
||||
0xf4, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xf0,
|
||||
0x7, 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, 0xf,
|
||||
0xff, 0xff, 0xf0, 0x7, 0xff, 0xff, 0xf4, 0x0,
|
||||
0x0, 0x0, 0xf, 0xff, 0xff, 0xf0, 0x3, 0xff,
|
||||
0xff, 0xf4, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff,
|
||||
0xe0, 0x3, 0xff, 0xff, 0xf8, 0x0, 0x0, 0x0,
|
||||
0x1f, 0xff, 0xff, 0xd0, 0x3, 0xff, 0xff, 0xfc,
|
||||
0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0xc0, 0x1,
|
||||
0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x7f, 0xff,
|
||||
0xff, 0xc0, 0x0, 0xff, 0xff, 0xff, 0xc0, 0x0,
|
||||
0x2, 0xff, 0xff, 0xff, 0x40, 0x0, 0x7f, 0xff,
|
||||
0xff, 0xf9, 0x0, 0x6f, 0xff, 0xff, 0xfe, 0x0,
|
||||
0x0, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xfc, 0x0, 0x0, 0xb, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xf0, 0x0, 0x0, 0x2,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
|
||||
0x0, 0x0, 0x0, 0x7f, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xfd, 0x0, 0x0, 0x0,
|
||||
0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xc0, 0x0, 0x0, 0x1f, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xf8, 0x0, 0x0, 0x7f, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0,
|
||||
0x1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0x80, 0x3, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xf, 0xff,
|
||||
0xff, 0xff, 0xe4, 0x0, 0x7, 0xff, 0xff, 0xff,
|
||||
0xf0, 0x1f, 0xff, 0xff, 0xfd, 0x0, 0x0, 0x0,
|
||||
0x7f, 0xff, 0xff, 0xf8, 0x2f, 0xff, 0xff, 0xf4,
|
||||
0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xfc, 0x3f,
|
||||
0xff, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x3, 0xff,
|
||||
0xff, 0xfd, 0x3f, 0xff, 0xff, 0xc0, 0x0, 0x0,
|
||||
0x0, 0x2, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff,
|
||||
0x80, 0x0, 0x0, 0x0, 0x1, 0xff, 0xff, 0xfe,
|
||||
0x7f, 0xff, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0,
|
||||
0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0x80, 0x0,
|
||||
0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x7f, 0xff,
|
||||
0xff, 0xc0, 0x0, 0x0, 0x0, 0x1, 0xff, 0xff,
|
||||
0xfe, 0x7f, 0xff, 0xff, 0xc0, 0x0, 0x0, 0x0,
|
||||
0x3, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xf0,
|
||||
0x0, 0x0, 0x0, 0x7, 0xff, 0xff, 0xfd, 0x3f,
|
||||
0xff, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x1f, 0xff,
|
||||
0xff, 0xfd, 0x2f, 0xff, 0xff, 0xff, 0x40, 0x0,
|
||||
0x0, 0xbf, 0xff, 0xff, 0xfc, 0xf, 0xff, 0xff,
|
||||
0xff, 0xf9, 0x55, 0x6f, 0xff, 0xff, 0xff, 0xf8,
|
||||
0xb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xf0, 0x3, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x1, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xc0, 0x0, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0x0, 0x0, 0x2f, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x0, 0x0,
|
||||
0x7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xe0, 0x0, 0x0, 0x0, 0xbf, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0x40, 0x0, 0x0, 0x0, 0xb,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x7f, 0xff, 0xff, 0xff, 0xfe,
|
||||
0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xaf,
|
||||
0xff, 0xfa, 0x40, 0x0, 0x0, 0x0,
|
||||
|
||||
/* U+0039 "9" */
|
||||
0x0, 0x0, 0x0, 0x0, 0x16, 0xaa, 0x94, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff,
|
||||
0xff, 0xff, 0xf9, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0xbf,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0,
|
||||
0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xf0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xf0, 0x0, 0x0, 0xbf, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x7f, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd0,
|
||||
0x0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xfc, 0x0, 0x2f, 0xff, 0xff, 0xff,
|
||||
0xe4, 0x0, 0x6f, 0xff, 0xff, 0xff, 0x80, 0xf,
|
||||
0xff, 0xff, 0xff, 0x40, 0x0, 0x0, 0xbf, 0xff,
|
||||
0xff, 0xf0, 0x7, 0xff, 0xff, 0xff, 0x0, 0x0,
|
||||
0x0, 0xb, 0xff, 0xff, 0xfd, 0x2, 0xff, 0xff,
|
||||
0xff, 0x40, 0x0, 0x0, 0x0, 0xbf, 0xff, 0xff,
|
||||
0xc0, 0xff, 0xff, 0xff, 0x80, 0x0, 0x0, 0x0,
|
||||
0xf, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xd0,
|
||||
0x0, 0x0, 0x0, 0x2, 0xff, 0xff, 0xfd, 0x1f,
|
||||
0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x7f,
|
||||
0xff, 0xff, 0x87, 0xff, 0xff, 0xfc, 0x0, 0x0,
|
||||
0x0, 0x0, 0xf, 0xff, 0xff, 0xf1, 0xff, 0xff,
|
||||
0xff, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xff,
|
||||
0xfc, 0xbf, 0xff, 0xff, 0xc0, 0x0, 0x0, 0x0,
|
||||
0x0, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xf0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x3f, 0xff, 0xff, 0xd7,
|
||||
0xff, 0xff, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x1f,
|
||||
0xff, 0xff, 0xf5, 0xff, 0xff, 0xff, 0x40, 0x0,
|
||||
0x0, 0x0, 0xb, 0xff, 0xff, 0xfd, 0x3f, 0xff,
|
||||
0xff, 0xf0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xff,
|
||||
0xff, 0x8f, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0,
|
||||
0x3, 0xff, 0xff, 0xff, 0xe2, 0xff, 0xff, 0xff,
|
||||
0xe0, 0x0, 0x0, 0x2, 0xff, 0xff, 0xff, 0xf8,
|
||||
0x7f, 0xff, 0xff, 0xff, 0x40, 0x0, 0x7, 0xff,
|
||||
0xff, 0xff, 0xfe, 0xf, 0xff, 0xff, 0xff, 0xfe,
|
||||
0x55, 0x6f, 0xff, 0xff, 0xff, 0xff, 0x82, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xe0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xf8, 0x7, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
|
||||
0x0, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0x40, 0xb, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd0, 0x0,
|
||||
0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xf0, 0x0, 0x7, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xfb, 0xff, 0xff, 0xfc, 0x0, 0x0, 0x2f,
|
||||
0xff, 0xff, 0xff, 0xff, 0xe1, 0xff, 0xff, 0xff,
|
||||
0x0, 0x0, 0x0, 0x7f, 0xff, 0xff, 0xff, 0x80,
|
||||
0xbf, 0xff, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x6b,
|
||||
0xff, 0xf9, 0x0, 0x3f, 0xff, 0xff, 0xe0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff,
|
||||
0xff, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x7, 0xff, 0xff, 0xfc, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xff, 0xff,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
|
||||
0xff, 0xff, 0xff, 0x40, 0x0, 0x2, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xc0, 0x0,
|
||||
0x3, 0xf4, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
|
||||
0xff, 0xe0, 0x0, 0x2, 0xff, 0x80, 0x0, 0x0,
|
||||
0x0, 0xff, 0xff, 0xff, 0xf4, 0x0, 0x0, 0xff,
|
||||
0xfe, 0x40, 0x0, 0x1, 0xff, 0xff, 0xff, 0xfc,
|
||||
0x0, 0x0, 0xff, 0xff, 0xfe, 0x95, 0x5b, 0xff,
|
||||
0xff, 0xff, 0xfc, 0x0, 0x0, 0xbf, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0,
|
||||
0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0x0, 0x0, 0x3f, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0x40, 0x0, 0x2f, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x40,
|
||||
0x0, 0xf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0x80, 0x0, 0x0, 0xbf, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x40, 0x0, 0x0,
|
||||
0x7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0x40, 0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0xbf, 0xff, 0xff, 0xff, 0xff, 0xfd, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x1, 0xff, 0xff, 0xff, 0xff,
|
||||
0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
|
||||
0xaf, 0xff, 0xf9, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
|
||||
/* U+003A ":" */
|
||||
0xbf, 0xff, 0xff, 0xdb, 0xff, 0xff, 0xfd, 0xbf,
|
||||
0xff, 0xff, 0xdb, 0xff, 0xff, 0xfd, 0xbf, 0xff,
|
||||
0xff, 0xdb, 0xff, 0xff, 0xfd, 0xbf, 0xff, 0xff,
|
||||
0xdb, 0xff, 0xff, 0xfd, 0xbf, 0xff, 0xff, 0xdb,
|
||||
0xff, 0xff, 0xfd, 0xbf, 0xff, 0xff, 0xdb, 0xff,
|
||||
0xff, 0xfd, 0xbf, 0xff, 0xff, 0xd0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0xbf, 0xff, 0xff, 0xdb, 0xff, 0xff, 0xfd,
|
||||
0xbf, 0xff, 0xff, 0xdb, 0xff, 0xff, 0xfd, 0xbf,
|
||||
0xff, 0xff, 0xdb, 0xff, 0xff, 0xfd, 0xbf, 0xff,
|
||||
0xff, 0xdb, 0xff, 0xff, 0xfd, 0xbf, 0xff, 0xff,
|
||||
0xdb, 0xff, 0xff, 0xfd, 0xbf, 0xff, 0xff, 0xdb,
|
||||
0xff, 0xff, 0xfd, 0xbf, 0xff, 0xff, 0xd0
|
||||
};
|
||||
|
||||
|
||||
/*---------------------
|
||||
* GLYPH DESCRIPTION
|
||||
*--------------------*/
|
||||
|
||||
static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
|
||||
{.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */,
|
||||
{.bitmap_index = 0, .adv_w = 384, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 0, .adv_w = 934, .box_w = 51, .box_h = 59, .ofs_x = 4, .ofs_y = -1},
|
||||
{.bitmap_index = 753, .adv_w = 540, .box_w = 26, .box_h = 57, .ofs_x = 1, .ofs_y = 0},
|
||||
{.bitmap_index = 1124, .adv_w = 797, .box_w = 43, .box_h = 58, .ofs_x = 3, .ofs_y = 0},
|
||||
{.bitmap_index = 1748, .adv_w = 795, .box_w = 43, .box_h = 58, .ofs_x = 3, .ofs_y = -1},
|
||||
{.bitmap_index = 2372, .adv_w = 882, .box_w = 50, .box_h = 57, .ofs_x = 2, .ofs_y = 0},
|
||||
{.bitmap_index = 3085, .adv_w = 806, .box_w = 43, .box_h = 57, .ofs_x = 3, .ofs_y = -1},
|
||||
{.bitmap_index = 3698, .adv_w = 847, .box_w = 45, .box_h = 59, .ofs_x = 4, .ofs_y = -1},
|
||||
{.bitmap_index = 4362, .adv_w = 792, .box_w = 41, .box_h = 57, .ofs_x = 5, .ofs_y = 0},
|
||||
{.bitmap_index = 4947, .adv_w = 806, .box_w = 44, .box_h = 58, .ofs_x = 3, .ofs_y = -1},
|
||||
{.bitmap_index = 5585, .adv_w = 847, .box_w = 45, .box_h = 59, .ofs_x = 4, .ofs_y = -1},
|
||||
{.bitmap_index = 6249, .adv_w = 379, .box_w = 14, .box_h = 43, .ofs_x = 5, .ofs_y = 0}
|
||||
};
|
||||
|
||||
/*---------------------
|
||||
* CHARACTER MAPPING
|
||||
*--------------------*/
|
||||
|
||||
|
||||
|
||||
/*Collect the unicode lists and glyph_id offsets*/
|
||||
static const lv_font_fmt_txt_cmap_t cmaps[] =
|
||||
{
|
||||
{
|
||||
.range_start = 32, .range_length = 1, .glyph_id_start = 1,
|
||||
.unicode_list = NULL, .glyph_id_ofs_list = NULL, .list_length = 0, .type = LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY
|
||||
},
|
||||
{
|
||||
.range_start = 48, .range_length = 11, .glyph_id_start = 2,
|
||||
.unicode_list = NULL, .glyph_id_ofs_list = NULL, .list_length = 0, .type = LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*--------------------
|
||||
* ALL CUSTOM DATA
|
||||
*--------------------*/
|
||||
|
||||
#if LVGL_VERSION_MAJOR >= 8
|
||||
/*Store all the custom data of the font*/
|
||||
static lv_font_fmt_txt_glyph_cache_t cache;
|
||||
static const lv_font_fmt_txt_dsc_t font_dsc = {
|
||||
#else
|
||||
static lv_font_fmt_txt_dsc_t font_dsc = {
|
||||
#endif
|
||||
.glyph_bitmap = glyph_bitmap,
|
||||
.glyph_dsc = glyph_dsc,
|
||||
.cmaps = cmaps,
|
||||
.kern_dsc = NULL,
|
||||
.kern_scale = 0,
|
||||
.cmap_num = 2,
|
||||
.bpp = 2,
|
||||
.kern_classes = 0,
|
||||
.bitmap_format = 0,
|
||||
#if LVGL_VERSION_MAJOR >= 8
|
||||
.cache = &cache
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/*-----------------
|
||||
* PUBLIC FONT
|
||||
*----------------*/
|
||||
|
||||
/*Initialize a public general font descriptor*/
|
||||
#if LVGL_VERSION_MAJOR >= 8
|
||||
const lv_font_t gotham_bold_80 = {
|
||||
#else
|
||||
lv_font_t gotham_bold_80 = {
|
||||
#endif
|
||||
.get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/
|
||||
.get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/
|
||||
.line_height = 59, /*The maximum line height required by the font*/
|
||||
.base_line = 1, /*Baseline measured from the bottom of the line*/
|
||||
#if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0)
|
||||
.subpx = LV_FONT_SUBPX_NONE,
|
||||
#endif
|
||||
#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8
|
||||
.underline_position = -11,
|
||||
.underline_thickness = 2,
|
||||
#endif
|
||||
.dsc = &font_dsc, /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */
|
||||
.fallback = NULL,
|
||||
.user_data = NULL
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif /*#if GOTHAM_BOLD_80*/
|
||||
|
25
lvgl-based/custom-fonts/gotham_bold_80.h
Normal file
25
lvgl-based/custom-fonts/gotham_bold_80.h
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Koen Zandberg <koen@bergzand.net>
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
#ifndef _APP_FONTS_GOTHAM_BOLD_80_H
|
||||
#define _APP_FONTS_GOTHAM_BOLD_80_H
|
||||
|
||||
#include "lvgl/lvgl.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
extern lv_font_t gotham_bold_80;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
704
lvgl-based/lvgl-configs/lv_conf.h
Normal file
704
lvgl-based/lvgl-configs/lv_conf.h
Normal file
@ -0,0 +1,704 @@
|
||||
/**
|
||||
* @file lv_conf.h
|
||||
* Configuration file for v8.3.0-dev
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copy this file as `lv_conf.h`
|
||||
* 1. simply next to the `lvgl` folder
|
||||
* 2. or any other places and
|
||||
* - define `LV_CONF_INCLUDE_SIMPLE`
|
||||
* - add the path as include path
|
||||
*/
|
||||
|
||||
/* clang-format off */
|
||||
#if 1 /*Set it to "1" to enable content*/
|
||||
|
||||
#ifndef LV_CONF_H
|
||||
#define LV_CONF_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
/*====================
|
||||
COLOR SETTINGS
|
||||
*====================*/
|
||||
|
||||
/*Color depth: 1 (1 byte per pixel), 8 (RGB332), 16 (RGB565), 32 (ARGB8888)*/
|
||||
#define LV_COLOR_DEPTH 16
|
||||
|
||||
/*Swap the 2 bytes of RGB565 color. Useful if the display has an 8-bit interface (e.g. SPI)*/
|
||||
#define LV_COLOR_16_SWAP 0
|
||||
|
||||
/*Enable more complex drawing routines to manage screens transparency.
|
||||
*Can be used if the UI is above another layer, e.g. an OSD menu or video player.
|
||||
*Requires `LV_COLOR_DEPTH = 32` colors and the screen's `bg_opa` should be set to non LV_OPA_COVER value*/
|
||||
#define LV_COLOR_SCREEN_TRANSP 0
|
||||
|
||||
/* Adjust color mix functions rounding. GPUs might calculate color mix (blending) differently.
|
||||
* 0: round down, 64: round up from x.75, 128: round up from half, 192: round up from x.25, 254: round up */
|
||||
#define LV_COLOR_MIX_ROUND_OFS (LV_COLOR_DEPTH == 32 ? 0: 128)
|
||||
|
||||
/*Images pixels with this color will not be drawn if they are chroma keyed)*/
|
||||
#define LV_COLOR_CHROMA_KEY lv_color_hex(0x00ff00) /*pure green*/
|
||||
|
||||
/*=========================
|
||||
MEMORY SETTINGS
|
||||
*=========================*/
|
||||
|
||||
/*1: use custom malloc/free, 0: use the built-in `lv_mem_alloc()` and `lv_mem_free()`*/
|
||||
#define LV_MEM_CUSTOM 0
|
||||
#if LV_MEM_CUSTOM == 0
|
||||
/*Size of the memory available for `lv_mem_alloc()` in bytes (>= 2kB)*/
|
||||
#define LV_MEM_SIZE (48U * 1024U) /*[bytes]*/
|
||||
|
||||
/*Set an address for the memory pool instead of allocating it as a normal array. Can be in external SRAM too.*/
|
||||
#define LV_MEM_ADR 0 /*0: unused*/
|
||||
/*Instead of an address give a memory allocator that will be called to get a memory pool for LVGL. E.g. my_malloc*/
|
||||
#if LV_MEM_ADR == 0
|
||||
//#define LV_MEM_POOL_INCLUDE your_alloc_library /* Uncomment if using an external allocator*/
|
||||
//#define LV_MEM_POOL_ALLOC your_alloc /* Uncomment if using an external allocator*/
|
||||
#endif
|
||||
|
||||
#else /*LV_MEM_CUSTOM*/
|
||||
#define LV_MEM_CUSTOM_INCLUDE <stdlib.h> /*Header for the dynamic memory function*/
|
||||
#define LV_MEM_CUSTOM_ALLOC malloc
|
||||
#define LV_MEM_CUSTOM_FREE free
|
||||
#define LV_MEM_CUSTOM_REALLOC realloc
|
||||
#endif /*LV_MEM_CUSTOM*/
|
||||
|
||||
/*Number of the intermediate memory buffer used during rendering and other internal processing mechanisms.
|
||||
*You will see an error log message if there wasn't enough buffers. */
|
||||
#define LV_MEM_BUF_MAX_NUM 32
|
||||
|
||||
/*Use the standard `memcpy` and `memset` instead of LVGL's own functions. (Might or might not be faster).*/
|
||||
#define LV_MEMCPY_MEMSET_STD 0
|
||||
|
||||
/*====================
|
||||
HAL SETTINGS
|
||||
*====================*/
|
||||
|
||||
/*Default display refresh period. LVG will redraw changed areas with this period time*/
|
||||
#define LV_DISP_DEF_REFR_PERIOD 30 /*[ms]*/ //15
|
||||
|
||||
/*Input device read period in milliseconds*/
|
||||
#define LV_INDEV_DEF_READ_PERIOD 30 /*[ms]*///30
|
||||
|
||||
/*Use a custom tick source that tells the elapsed time in milliseconds.
|
||||
*It removes the need to manually update the tick with `lv_tick_inc()`)*/
|
||||
#define LV_TICK_CUSTOM 0
|
||||
#if LV_TICK_CUSTOM
|
||||
#define LV_TICK_CUSTOM_INCLUDE "Arduino.h" /*Header for the system time function*/
|
||||
#define LV_TICK_CUSTOM_SYS_TIME_EXPR (millis()) /*Expression evaluating to current system time in ms*/
|
||||
#endif /*LV_TICK_CUSTOM*/
|
||||
|
||||
/*Default Dot Per Inch. Used to initialize default sizes such as widgets sized, style paddings.
|
||||
*(Not so important, you can adjust it to modify default sizes and spaces)*/
|
||||
#define LV_DPI_DEF 130 /*[px/inch]*/
|
||||
|
||||
/*=======================
|
||||
* FEATURE CONFIGURATION
|
||||
*=======================*/
|
||||
|
||||
/*-------------
|
||||
* Drawing
|
||||
*-----------*/
|
||||
|
||||
/*Enable complex draw engine.
|
||||
*Required to draw shadow, gradient, rounded corners, circles, arc, skew lines, image transformations or any masks*/
|
||||
#define LV_DRAW_COMPLEX 1
|
||||
#if LV_DRAW_COMPLEX != 0
|
||||
|
||||
/*Allow buffering some shadow calculation.
|
||||
*LV_SHADOW_CACHE_SIZE is the max. shadow size to buffer, where shadow size is `shadow_width + radius`
|
||||
*Caching has LV_SHADOW_CACHE_SIZE^2 RAM cost*/
|
||||
#define LV_SHADOW_CACHE_SIZE 0
|
||||
|
||||
/* Set number of maximally cached circle data.
|
||||
* The circumference of 1/4 circle are saved for anti-aliasing
|
||||
* radius * 4 bytes are used per circle (the most often used radiuses are saved)
|
||||
* 0: to disable caching */
|
||||
#define LV_CIRCLE_CACHE_SIZE 4
|
||||
#endif /*LV_DRAW_COMPLEX*/
|
||||
|
||||
/*Default image cache size. Image caching keeps the images opened.
|
||||
*If only the built-in image formats are used there is no real advantage of caching. (I.e. if no new image decoder is added)
|
||||
*With complex image decoders (e.g. PNG or JPG) caching can save the continuous open/decode of images.
|
||||
*However the opened images might consume additional RAM.
|
||||
*0: to disable caching*/
|
||||
#define LV_IMG_CACHE_DEF_SIZE 0
|
||||
|
||||
/*Number of stops allowed per gradient. Increase this to allow more stops.
|
||||
*This adds (sizeof(lv_color_t) + 1) bytes per additional stop*/
|
||||
#define LV_GRADIENT_MAX_STOPS 2
|
||||
|
||||
/*Default gradient buffer size.
|
||||
*When LVGL calculates the gradient "maps" it can save them into a cache to avoid calculating them again.
|
||||
*LV_GRAD_CACHE_DEF_SIZE sets the size of this cache in bytes.
|
||||
*If the cache is too small the map will be allocated only while it's required for the drawing.
|
||||
*0 mean no caching.*/
|
||||
#define LV_GRAD_CACHE_DEF_SIZE 0
|
||||
|
||||
/*Allow dithering the gradients (to achieve visual smooth color gradients on limited color depth display)
|
||||
*LV_DITHER_GRADIENT implies allocating one or two more lines of the object's rendering surface
|
||||
*The increase in memory consumption is (32 bits * object width) plus 24 bits * object width if using error diffusion */
|
||||
#define LV_DITHER_GRADIENT 0
|
||||
#if LV_DITHER_GRADIENT
|
||||
/*Add support for error diffusion dithering.
|
||||
*Error diffusion dithering gets a much better visual result, but implies more CPU consumption and memory when drawing.
|
||||
*The increase in memory consumption is (24 bits * object's width)*/
|
||||
#define LV_DITHER_ERROR_DIFFUSION 0
|
||||
#endif
|
||||
|
||||
/*Maximum buffer size to allocate for rotation.
|
||||
*Only used if software rotation is enabled in the display driver.*/
|
||||
#define LV_DISP_ROT_MAX_BUF (10*1024)
|
||||
|
||||
/*-------------
|
||||
* GPU
|
||||
*-----------*/
|
||||
|
||||
/*Use STM32's DMA2D (aka Chrom Art) GPU*/
|
||||
#define LV_USE_GPU_STM32_DMA2D 0
|
||||
#if LV_USE_GPU_STM32_DMA2D
|
||||
/*Must be defined to include path of CMSIS header of target processor
|
||||
e.g. "stm32f769xx.h" or "stm32f429xx.h"*/
|
||||
#define LV_GPU_DMA2D_CMSIS_INCLUDE
|
||||
#endif
|
||||
|
||||
/*Use NXP's PXP GPU iMX RTxxx platforms*/
|
||||
#define LV_USE_GPU_NXP_PXP 0
|
||||
#if LV_USE_GPU_NXP_PXP
|
||||
/*1: Add default bare metal and FreeRTOS interrupt handling routines for PXP (lv_gpu_nxp_pxp_osa.c)
|
||||
* and call lv_gpu_nxp_pxp_init() automatically during lv_init(). Note that symbol SDK_OS_FREE_RTOS
|
||||
* has to be defined in order to use FreeRTOS OSA, otherwise bare-metal implementation is selected.
|
||||
*0: lv_gpu_nxp_pxp_init() has to be called manually before lv_init()
|
||||
*/
|
||||
#define LV_USE_GPU_NXP_PXP_AUTO_INIT 0
|
||||
#endif
|
||||
|
||||
/*Use NXP's VG-Lite GPU iMX RTxxx platforms*/
|
||||
#define LV_USE_GPU_NXP_VG_LITE 0
|
||||
|
||||
/*Use SDL renderer API*/
|
||||
#define LV_USE_GPU_SDL 0
|
||||
#if LV_USE_GPU_SDL
|
||||
#define LV_GPU_SDL_INCLUDE_PATH <SDL2/SDL.h>
|
||||
/*Texture cache size, 8MB by default*/
|
||||
#define LV_GPU_SDL_LRU_SIZE (1024 * 1024 * 8)
|
||||
/*Custom blend mode for mask drawing, disable if you need to link with older SDL2 lib*/
|
||||
#define LV_GPU_SDL_CUSTOM_BLEND_MODE (SDL_VERSION_ATLEAST(2, 0, 6))
|
||||
#endif
|
||||
|
||||
/*-------------
|
||||
* Logging
|
||||
*-----------*/
|
||||
|
||||
/*Enable the log module*/
|
||||
#define LV_USE_LOG 1
|
||||
#if LV_USE_LOG
|
||||
|
||||
/*How important log should be added:
|
||||
*LV_LOG_LEVEL_TRACE A lot of logs to give detailed information
|
||||
*LV_LOG_LEVEL_INFO Log important events
|
||||
*LV_LOG_LEVEL_WARN Log if something unwanted happened but didn't cause a problem
|
||||
*LV_LOG_LEVEL_ERROR Only critical issue, when the system may fail
|
||||
*LV_LOG_LEVEL_USER Only logs added by the user
|
||||
*LV_LOG_LEVEL_NONE Do not log anything*/
|
||||
#define LV_LOG_LEVEL LV_LOG_LEVEL_INFO
|
||||
|
||||
/*1: Print the log with 'printf';
|
||||
*0: User need to register a callback with `lv_log_register_print_cb()`*/
|
||||
#define LV_LOG_PRINTF 0
|
||||
|
||||
/*Enable/disable LV_LOG_TRACE in modules that produces a huge number of logs*/
|
||||
#define LV_LOG_TRACE_MEM 1
|
||||
#define LV_LOG_TRACE_TIMER 1
|
||||
#define LV_LOG_TRACE_INDEV 1
|
||||
#define LV_LOG_TRACE_DISP_REFR 1
|
||||
#define LV_LOG_TRACE_EVENT 1
|
||||
#define LV_LOG_TRACE_OBJ_CREATE 1
|
||||
#define LV_LOG_TRACE_LAYOUT 1
|
||||
#define LV_LOG_TRACE_ANIM 1
|
||||
|
||||
#endif /*LV_USE_LOG*/
|
||||
|
||||
/*-------------
|
||||
* Asserts
|
||||
*-----------*/
|
||||
|
||||
/*Enable asserts if an operation is failed or an invalid data is found.
|
||||
*If LV_USE_LOG is enabled an error message will be printed on failure*/
|
||||
#define LV_USE_ASSERT_NULL 1 /*Check if the parameter is NULL. (Very fast, recommended)*/
|
||||
#define LV_USE_ASSERT_MALLOC 1 /*Checks is the memory is successfully allocated or no. (Very fast, recommended)*/
|
||||
#define LV_USE_ASSERT_STYLE 0 /*Check if the styles are properly initialized. (Very fast, recommended)*/
|
||||
#define LV_USE_ASSERT_MEM_INTEGRITY 0 /*Check the integrity of `lv_mem` after critical operations. (Slow)*/
|
||||
#define LV_USE_ASSERT_OBJ 0 /*Check the object's type and existence (e.g. not deleted). (Slow)*/
|
||||
|
||||
/*Add a custom handler when assert happens e.g. to restart the MCU*/
|
||||
#define LV_ASSERT_HANDLER_INCLUDE <stdint.h>
|
||||
#define LV_ASSERT_HANDLER while(1); /*Halt by default*/
|
||||
|
||||
/*-------------
|
||||
* Others
|
||||
*-----------*/
|
||||
|
||||
/*1: Show CPU usage and FPS count*/
|
||||
#define LV_USE_PERF_MONITOR 0
|
||||
#if LV_USE_PERF_MONITOR
|
||||
#define LV_USE_PERF_MONITOR_POS LV_ALIGN_BOTTOM_RIGHT
|
||||
#endif
|
||||
|
||||
/*1: Show the used memory and the memory fragmentation
|
||||
* Requires LV_MEM_CUSTOM = 0*/
|
||||
#define LV_USE_MEM_MONITOR 0
|
||||
#if LV_USE_MEM_MONITOR
|
||||
#define LV_USE_MEM_MONITOR_POS LV_ALIGN_BOTTOM_LEFT
|
||||
#endif
|
||||
|
||||
/*1: Draw random colored rectangles over the redrawn areas*/
|
||||
#define LV_USE_REFR_DEBUG 0
|
||||
|
||||
/*Change the built in (v)snprintf functions*/
|
||||
#define LV_SPRINTF_CUSTOM 0
|
||||
#if LV_SPRINTF_CUSTOM
|
||||
#define LV_SPRINTF_INCLUDE <stdio.h>
|
||||
#define lv_snprintf snprintf
|
||||
#define lv_vsnprintf vsnprintf
|
||||
#else /*LV_SPRINTF_CUSTOM*/
|
||||
#define LV_SPRINTF_USE_FLOAT 0
|
||||
#endif /*LV_SPRINTF_CUSTOM*/
|
||||
|
||||
#define LV_USE_USER_DATA 1
|
||||
|
||||
/*Garbage Collector settings
|
||||
*Used if lvgl is bound to higher level language and the memory is managed by that language*/
|
||||
#define LV_ENABLE_GC 0
|
||||
#if LV_ENABLE_GC != 0
|
||||
#define LV_GC_INCLUDE "gc.h" /*Include Garbage Collector related things*/
|
||||
#endif /*LV_ENABLE_GC*/
|
||||
|
||||
/*=====================
|
||||
* COMPILER SETTINGS
|
||||
*====================*/
|
||||
|
||||
/*For big endian systems set to 1*/
|
||||
#define LV_BIG_ENDIAN_SYSTEM 0
|
||||
|
||||
/*Define a custom attribute to `lv_tick_inc` function*/
|
||||
#define LV_ATTRIBUTE_TICK_INC
|
||||
|
||||
/*Define a custom attribute to `lv_timer_handler` function*/
|
||||
#define LV_ATTRIBUTE_TIMER_HANDLER
|
||||
|
||||
/*Define a custom attribute to `lv_disp_flush_ready` function*/
|
||||
#define LV_ATTRIBUTE_FLUSH_READY
|
||||
|
||||
/*Required alignment size for buffers*/
|
||||
#define LV_ATTRIBUTE_MEM_ALIGN_SIZE 1
|
||||
|
||||
/*Will be added where memories needs to be aligned (with -Os data might not be aligned to boundary by default).
|
||||
* E.g. __attribute__((aligned(4)))*/
|
||||
#define LV_ATTRIBUTE_MEM_ALIGN
|
||||
|
||||
/*Attribute to mark large constant arrays for example font's bitmaps*/
|
||||
#define LV_ATTRIBUTE_LARGE_CONST
|
||||
|
||||
/*Compiler prefix for a big array declaration in RAM*/
|
||||
#define LV_ATTRIBUTE_LARGE_RAM_ARRAY
|
||||
|
||||
/*Place performance critical functions into a faster memory (e.g RAM)*/
|
||||
#define LV_ATTRIBUTE_FAST_MEM
|
||||
|
||||
/*Prefix variables that are used in GPU accelerated operations, often these need to be placed in RAM sections that are DMA accessible*/
|
||||
#define LV_ATTRIBUTE_DMA
|
||||
|
||||
/*Export integer constant to binding. This macro is used with constants in the form of LV_<CONST> that
|
||||
*should also appear on LVGL binding API such as Micropython.*/
|
||||
#define LV_EXPORT_CONST_INT(int_value) struct _silence_gcc_warning /*The default value just prevents GCC warning*/
|
||||
|
||||
/*Extend the default -32k..32k coordinate range to -4M..4M by using int32_t for coordinates instead of int16_t*/
|
||||
#define LV_USE_LARGE_COORD 0
|
||||
|
||||
/*==================
|
||||
* FONT USAGE
|
||||
*===================*/
|
||||
|
||||
/*Montserrat fonts with ASCII range and some symbols using bpp = 4
|
||||
*https://fonts.google.com/specimen/Montserrat*/
|
||||
#define LV_FONT_MONTSERRAT_8 0
|
||||
#define LV_FONT_MONTSERRAT_10 0
|
||||
#define LV_FONT_MONTSERRAT_12 1
|
||||
#define LV_FONT_MONTSERRAT_14 1
|
||||
#define LV_FONT_MONTSERRAT_16 1
|
||||
#define LV_FONT_MONTSERRAT_18 0
|
||||
#define LV_FONT_MONTSERRAT_20 0
|
||||
#define LV_FONT_MONTSERRAT_22 0
|
||||
#define LV_FONT_MONTSERRAT_24 1
|
||||
#define LV_FONT_MONTSERRAT_26 0
|
||||
#define LV_FONT_MONTSERRAT_28 0
|
||||
#define LV_FONT_MONTSERRAT_30 0
|
||||
#define LV_FONT_MONTSERRAT_32 1
|
||||
#define LV_FONT_MONTSERRAT_34 0
|
||||
#define LV_FONT_MONTSERRAT_36 0
|
||||
#define LV_FONT_MONTSERRAT_38 0
|
||||
#define LV_FONT_MONTSERRAT_40 0
|
||||
#define LV_FONT_MONTSERRAT_42 0
|
||||
#define LV_FONT_MONTSERRAT_44 0
|
||||
#define LV_FONT_MONTSERRAT_46 0
|
||||
#define LV_FONT_MONTSERRAT_48 0
|
||||
|
||||
/*Demonstrate special features*/
|
||||
#define LV_FONT_MONTSERRAT_12_SUBPX 0
|
||||
#define LV_FONT_MONTSERRAT_28_COMPRESSED 0 /*bpp = 3*/
|
||||
#define LV_FONT_DEJAVU_16_PERSIAN_HEBREW 0 /*Hebrew, Arabic, Persian letters and all their forms*/
|
||||
#define LV_FONT_SIMSUN_16_CJK 0 /*1000 most common CJK radicals*/
|
||||
|
||||
/*Pixel perfect monospace fonts*/
|
||||
#define LV_FONT_UNSCII_8 0
|
||||
#define LV_FONT_UNSCII_16 0
|
||||
|
||||
/*Optionally declare custom fonts here.
|
||||
*You can use these fonts as default font too and they will be available globally.
|
||||
*E.g. #define LV_FONT_CUSTOM_DECLARE LV_FONT_DECLARE(my_font_1) LV_FONT_DECLARE(my_font_2)*/
|
||||
#define LV_FONT_CUSTOM_DECLARE
|
||||
|
||||
/*Always set a default font*/
|
||||
#define LV_FONT_DEFAULT &lv_font_montserrat_14
|
||||
|
||||
/*Enable handling large font and/or fonts with a lot of characters.
|
||||
*The limit depends on the font size, font face and bpp.
|
||||
*Compiler error will be triggered if a font needs it.*/
|
||||
#define LV_FONT_FMT_TXT_LARGE 0
|
||||
|
||||
/*Enables/disables support for compressed fonts.*/
|
||||
#define LV_USE_FONT_COMPRESSED 0
|
||||
|
||||
/*Enable subpixel rendering*/
|
||||
#define LV_USE_FONT_SUBPX 0
|
||||
#if LV_USE_FONT_SUBPX
|
||||
/*Set the pixel order of the display. Physical order of RGB channels. Doesn't matter with "normal" fonts.*/
|
||||
#define LV_FONT_SUBPX_BGR 0 /*0: RGB; 1:BGR order*/
|
||||
#endif
|
||||
|
||||
/*=================
|
||||
* TEXT SETTINGS
|
||||
*=================*/
|
||||
|
||||
/**
|
||||
* Select a character encoding for strings.
|
||||
* Your IDE or editor should have the same character encoding
|
||||
* - LV_TXT_ENC_UTF8
|
||||
* - LV_TXT_ENC_ASCII
|
||||
*/
|
||||
#define LV_TXT_ENC LV_TXT_ENC_UTF8
|
||||
|
||||
/*Can break (wrap) texts on these chars*/
|
||||
#define LV_TXT_BREAK_CHARS " ,.;:-_"
|
||||
|
||||
/*If a word is at least this long, will break wherever "prettiest"
|
||||
*To disable, set to a value <= 0*/
|
||||
#define LV_TXT_LINE_BREAK_LONG_LEN 0
|
||||
|
||||
/*Minimum number of characters in a long word to put on a line before a break.
|
||||
*Depends on LV_TXT_LINE_BREAK_LONG_LEN.*/
|
||||
#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3
|
||||
|
||||
/*Minimum number of characters in a long word to put on a line after a break.
|
||||
*Depends on LV_TXT_LINE_BREAK_LONG_LEN.*/
|
||||
#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 3
|
||||
|
||||
/*The control character to use for signalling text recoloring.*/
|
||||
#define LV_TXT_COLOR_CMD "#"
|
||||
|
||||
/*Support bidirectional texts. Allows mixing Left-to-Right and Right-to-Left texts.
|
||||
*The direction will be processed according to the Unicode Bidirectional Algorithm:
|
||||
*https://www.w3.org/International/articles/inline-bidi-markup/uba-basics*/
|
||||
#define LV_USE_BIDI 0
|
||||
#if LV_USE_BIDI
|
||||
/*Set the default direction. Supported values:
|
||||
*`LV_BASE_DIR_LTR` Left-to-Right
|
||||
*`LV_BASE_DIR_RTL` Right-to-Left
|
||||
*`LV_BASE_DIR_AUTO` detect texts base direction*/
|
||||
#define LV_BIDI_BASE_DIR_DEF LV_BASE_DIR_AUTO
|
||||
#endif
|
||||
|
||||
/*Enable Arabic/Persian processing
|
||||
*In these languages characters should be replaced with an other form based on their position in the text*/
|
||||
#define LV_USE_ARABIC_PERSIAN_CHARS 0
|
||||
|
||||
/*==================
|
||||
* WIDGET USAGE
|
||||
*================*/
|
||||
|
||||
/*Documentation of the widgets: https://docs.lvgl.io/latest/en/html/widgets/index.html*/
|
||||
|
||||
#define LV_USE_ARC 1
|
||||
|
||||
#define LV_USE_ANIMIMG 1
|
||||
|
||||
#define LV_USE_BAR 1
|
||||
|
||||
#define LV_USE_BTN 1
|
||||
|
||||
#define LV_USE_BTNMATRIX 1
|
||||
|
||||
#define LV_USE_CANVAS 1
|
||||
|
||||
#define LV_USE_CHECKBOX 1
|
||||
|
||||
#define LV_USE_DROPDOWN 1 /*Requires: lv_label*/
|
||||
|
||||
#define LV_USE_IMG 1 /*Requires: lv_label*/
|
||||
|
||||
#define LV_USE_LABEL 1
|
||||
#if LV_USE_LABEL
|
||||
#define LV_LABEL_TEXT_SELECTION 1 /*Enable selecting text of the label*/
|
||||
#define LV_LABEL_LONG_TXT_HINT 1 /*Store some extra info in labels to speed up drawing of very long texts*/
|
||||
#endif
|
||||
|
||||
#define LV_USE_LINE 1
|
||||
|
||||
#define LV_USE_ROLLER 1 /*Requires: lv_label*/
|
||||
#if LV_USE_ROLLER
|
||||
#define LV_ROLLER_INF_PAGES 7 /*Number of extra "pages" when the roller is infinite*/
|
||||
#endif
|
||||
|
||||
#define LV_USE_SLIDER 1 /*Requires: lv_bar*/
|
||||
|
||||
#define LV_USE_SWITCH 1
|
||||
|
||||
#define LV_USE_TEXTAREA 1 /*Requires: lv_label*/
|
||||
#if LV_USE_TEXTAREA != 0
|
||||
#define LV_TEXTAREA_DEF_PWD_SHOW_TIME 1500 /*ms*/
|
||||
#endif
|
||||
|
||||
#define LV_USE_TABLE 1
|
||||
|
||||
/*==================
|
||||
* EXTRA COMPONENTS
|
||||
*==================*/
|
||||
|
||||
/*-----------
|
||||
* Widgets
|
||||
*----------*/
|
||||
#define LV_USE_CALENDAR 1
|
||||
#if LV_USE_CALENDAR
|
||||
#define LV_CALENDAR_WEEK_STARTS_MONDAY 0
|
||||
#if LV_CALENDAR_WEEK_STARTS_MONDAY
|
||||
#define LV_CALENDAR_DEFAULT_DAY_NAMES {"Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"}
|
||||
#else
|
||||
#define LV_CALENDAR_DEFAULT_DAY_NAMES {"Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"}
|
||||
#endif
|
||||
|
||||
#define LV_CALENDAR_DEFAULT_MONTH_NAMES {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}
|
||||
#define LV_USE_CALENDAR_HEADER_ARROW 1
|
||||
#define LV_USE_CALENDAR_HEADER_DROPDOWN 1
|
||||
#endif /*LV_USE_CALENDAR*/
|
||||
|
||||
#define LV_USE_CHART 1
|
||||
|
||||
#define LV_USE_COLORWHEEL 1
|
||||
|
||||
#define LV_USE_IMGBTN 1
|
||||
|
||||
#define LV_USE_KEYBOARD 1
|
||||
|
||||
#define LV_USE_LED 1
|
||||
|
||||
#define LV_USE_LIST 1
|
||||
|
||||
#define LV_USE_MENU 1
|
||||
|
||||
#define LV_USE_METER 1
|
||||
|
||||
#define LV_USE_MSGBOX 1
|
||||
|
||||
#define LV_USE_SPINBOX 1
|
||||
|
||||
#define LV_USE_SPINNER 1
|
||||
|
||||
#define LV_USE_TABVIEW 1
|
||||
|
||||
#define LV_USE_TILEVIEW 1
|
||||
|
||||
#define LV_USE_WIN 1
|
||||
|
||||
#define LV_USE_SPAN 1
|
||||
#if LV_USE_SPAN
|
||||
/*A line text can contain maximum num of span descriptor */
|
||||
#define LV_SPAN_SNIPPET_STACK_SIZE 64
|
||||
#endif
|
||||
|
||||
/*-----------
|
||||
* Themes
|
||||
*----------*/
|
||||
|
||||
/*A simple, impressive and very complete theme*/
|
||||
#define LV_USE_THEME_DEFAULT 1
|
||||
#if LV_USE_THEME_DEFAULT
|
||||
|
||||
/*0: Light mode; 1: Dark mode*/
|
||||
#define LV_THEME_DEFAULT_DARK 0
|
||||
|
||||
/*1: Enable grow on press*/
|
||||
#define LV_THEME_DEFAULT_GROW 1
|
||||
|
||||
/*Default transition time in [ms]*/
|
||||
#define LV_THEME_DEFAULT_TRANSITION_TIME 80
|
||||
#endif /*LV_USE_THEME_DEFAULT*/
|
||||
|
||||
/*A very simple theme that is a good starting point for a custom theme*/
|
||||
#define LV_USE_THEME_BASIC 1
|
||||
|
||||
/*A theme designed for monochrome displays*/
|
||||
#define LV_USE_THEME_MONO 1
|
||||
|
||||
/*-----------
|
||||
* Layouts
|
||||
*----------*/
|
||||
|
||||
/*A layout similar to Flexbox in CSS.*/
|
||||
#define LV_USE_FLEX 1
|
||||
|
||||
/*A layout similar to Grid in CSS.*/
|
||||
#define LV_USE_GRID 1
|
||||
|
||||
/*---------------------
|
||||
* 3rd party libraries
|
||||
*--------------------*/
|
||||
|
||||
/*File system interfaces for common APIs */
|
||||
|
||||
/*API for fopen, fread, etc*/
|
||||
#define LV_USE_FS_STDIO 0
|
||||
#if LV_USE_FS_STDIO
|
||||
#define LV_FS_STDIO_LETTER '\0' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/
|
||||
#define LV_FS_STDIO_PATH "" /*Set the working directory. File/directory paths will be appended to it.*/
|
||||
#define LV_FS_STDIO_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/
|
||||
#endif
|
||||
|
||||
/*API for open, read, etc*/
|
||||
#define LV_USE_FS_POSIX 0
|
||||
#if LV_USE_FS_POSIX
|
||||
#define LV_FS_POSIX_LETTER '\0' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/
|
||||
#define LV_FS_POSIX_PATH "" /*Set the working directory. File/directory paths will be appended to it.*/
|
||||
#define LV_FS_POSIX_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/
|
||||
#endif
|
||||
|
||||
/*API for CreateFile, ReadFile, etc*/
|
||||
#define LV_USE_FS_WIN32 0
|
||||
#if LV_USE_FS_WIN32
|
||||
#define LV_FS_WIN32_LETTER '\0' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/
|
||||
#define LV_FS_WIN32_PATH "" /*Set the working directory. File/directory paths will be appended to it.*/
|
||||
#define LV_FS_WIN32_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/
|
||||
#endif
|
||||
|
||||
/*API for FATFS (needs to be added separately). Uses f_open, f_read, etc*/
|
||||
#define LV_USE_FS_FATFS 0
|
||||
#if LV_USE_FS_FATFS
|
||||
#define LV_FS_FATFS_LETTER '\0' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/
|
||||
#define LV_FS_FATFS_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/
|
||||
#endif
|
||||
|
||||
/*PNG decoder library*/
|
||||
#define LV_USE_PNG 0
|
||||
|
||||
/*BMP decoder library*/
|
||||
#define LV_USE_BMP 0
|
||||
|
||||
/* JPG + split JPG decoder library.
|
||||
* Split JPG is a custom format optimized for embedded systems. */
|
||||
#define LV_USE_SJPG 0
|
||||
|
||||
/*GIF decoder library*/
|
||||
#define LV_USE_GIF 0
|
||||
|
||||
/*QR code library*/
|
||||
#define LV_USE_QRCODE 0
|
||||
|
||||
/*FreeType library*/
|
||||
#define LV_USE_FREETYPE 0
|
||||
#if LV_USE_FREETYPE
|
||||
/*Memory used by FreeType to cache characters [bytes] (-1: no caching)*/
|
||||
#define LV_FREETYPE_CACHE_SIZE (16 * 1024)
|
||||
#if LV_FREETYPE_CACHE_SIZE >= 0
|
||||
/* 1: bitmap cache use the sbit cache, 0:bitmap cache use the image cache. */
|
||||
/* sbit cache:it is much more memory efficient for small bitmaps(font size < 256) */
|
||||
/* if font size >= 256, must be configured as image cache */
|
||||
#define LV_FREETYPE_SBIT_CACHE 0
|
||||
/* Maximum number of opened FT_Face/FT_Size objects managed by this cache instance. */
|
||||
/* (0:use system defaults) */
|
||||
#define LV_FREETYPE_CACHE_FT_FACES 0
|
||||
#define LV_FREETYPE_CACHE_FT_SIZES 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*Rlottie library*/
|
||||
#define LV_USE_RLOTTIE 0
|
||||
|
||||
/*FFmpeg library for image decoding and playing videos
|
||||
*Supports all major image formats so do not enable other image decoder with it*/
|
||||
#define LV_USE_FFMPEG 0
|
||||
#if LV_USE_FFMPEG
|
||||
/*Dump input information to stderr*/
|
||||
#define LV_FFMPEG_AV_DUMP_FORMAT 0
|
||||
#endif
|
||||
|
||||
/*-----------
|
||||
* Others
|
||||
*----------*/
|
||||
|
||||
/*1: Enable API to take snapshot for object*/
|
||||
#define LV_USE_SNAPSHOT 0
|
||||
|
||||
/*1: Enable Monkey test*/
|
||||
#define LV_USE_MONKEY 0
|
||||
|
||||
/*1: Enable grid navigation*/
|
||||
#define LV_USE_GRIDNAV 0
|
||||
|
||||
/*1: Enable lv_obj fragment*/
|
||||
#define LV_USE_FRAGMENT 0
|
||||
|
||||
/*==================
|
||||
* EXAMPLES
|
||||
*==================*/
|
||||
|
||||
/*Enable the examples to be built with the library*/
|
||||
#define LV_BUILD_EXAMPLES 0
|
||||
|
||||
/*===================
|
||||
* DEMO USAGE
|
||||
====================*/
|
||||
|
||||
/*Show some widget. It might be required to increase `LV_MEM_SIZE` */
|
||||
#define LV_USE_DEMO_WIDGETS 0
|
||||
#if LV_USE_DEMO_WIDGETS
|
||||
#define LV_DEMO_WIDGETS_SLIDESHOW 0
|
||||
#endif
|
||||
|
||||
/*Demonstrate the usage of encoder and keyboard*/
|
||||
#define LV_USE_DEMO_KEYPAD_AND_ENCODER 0
|
||||
|
||||
/*Benchmark your system*/
|
||||
#define LV_USE_DEMO_BENCHMARK 0
|
||||
|
||||
/*Stress test for LVGL*/
|
||||
#define LV_USE_DEMO_STRESS 0
|
||||
|
||||
/*Music player demo*/
|
||||
#define LV_USE_DEMO_MUSIC 0
|
||||
#if LV_USE_DEMO_MUSIC
|
||||
# define LV_DEMO_MUSIC_SQUARE 0
|
||||
# define LV_DEMO_MUSIC_LANDSCAPE 0
|
||||
# define LV_DEMO_MUSIC_ROUND 0
|
||||
# define LV_DEMO_MUSIC_LARGE 0
|
||||
# define LV_DEMO_MUSIC_AUTO_PLAY 0
|
||||
#endif
|
||||
|
||||
/*--END OF LV_CONF_H--*/
|
||||
|
||||
#endif /*LV_CONF_H*/
|
||||
|
||||
#endif /*End of "Content enable"*/
|
436
lvgl-based/lvgl-configs/lv_drv_conf.h
Normal file
436
lvgl-based/lvgl-configs/lv_drv_conf.h
Normal file
@ -0,0 +1,436 @@
|
||||
/**
|
||||
* @file lv_drv_conf.h
|
||||
* Configuration file for v8.1.0-dev
|
||||
*/
|
||||
|
||||
/*
|
||||
* COPY THIS FILE AS lv_drv_conf.h
|
||||
*/
|
||||
|
||||
#if 1 /*Set it to "1" to enable the content*/
|
||||
|
||||
#ifndef LV_DRV_CONF_H
|
||||
#define LV_DRV_CONF_H
|
||||
|
||||
#include <lv_conf.h>
|
||||
|
||||
/*********************
|
||||
* DELAY INTERFACE
|
||||
*********************/
|
||||
#define LV_DRV_DELAY_INCLUDE <stdint.h> /*Dummy include by default*/
|
||||
#define LV_DRV_DELAY_US(us) /*delay_us(us)*/ /*Delay the given number of microseconds*/
|
||||
#define LV_DRV_DELAY_MS(ms) /*delay_ms(ms)*/ /*Delay the given number of milliseconds*/
|
||||
|
||||
/*********************
|
||||
* DISPLAY INTERFACE
|
||||
*********************/
|
||||
|
||||
/*------------
|
||||
* Common
|
||||
*------------*/
|
||||
#define LV_DRV_DISP_INCLUDE <stdint.h> /*Dummy include by default*/
|
||||
#define LV_DRV_DISP_CMD_DATA(val) /*pin_x_set(val)*/ /*Set the command/data pin to 'val'*/
|
||||
#define LV_DRV_DISP_RST(val) /*pin_x_set(val)*/ /*Set the reset pin to 'val'*/
|
||||
|
||||
/*---------
|
||||
* SPI
|
||||
*---------*/
|
||||
#define LV_DRV_DISP_SPI_CS(val) /*spi_cs_set(val)*/ /*Set the SPI's Chip select to 'val'*/
|
||||
#define LV_DRV_DISP_SPI_WR_BYTE(data) /*spi_wr(data)*/ /*Write a byte the SPI bus*/
|
||||
#define LV_DRV_DISP_SPI_WR_ARRAY(adr, n) /*spi_wr_mem(adr, n)*/ /*Write 'n' bytes to SPI bus from 'adr'*/
|
||||
|
||||
/*------------------
|
||||
* Parallel port
|
||||
*-----------------*/
|
||||
#define LV_DRV_DISP_PAR_CS(val) /*par_cs_set(val)*/ /*Set the Parallel port's Chip select to 'val'*/
|
||||
#define LV_DRV_DISP_PAR_SLOW /*par_slow()*/ /*Set low speed on the parallel port*/
|
||||
#define LV_DRV_DISP_PAR_FAST /*par_fast()*/ /*Set high speed on the parallel port*/
|
||||
#define LV_DRV_DISP_PAR_WR_WORD(data) /*par_wr(data)*/ /*Write a word to the parallel port*/
|
||||
#define LV_DRV_DISP_PAR_WR_ARRAY(adr, n) /*par_wr_mem(adr,n)*/ /*Write 'n' bytes to Parallel ports from 'adr'*/
|
||||
|
||||
/***************************
|
||||
* INPUT DEVICE INTERFACE
|
||||
***************************/
|
||||
|
||||
/*----------
|
||||
* Common
|
||||
*----------*/
|
||||
#define LV_DRV_INDEV_INCLUDE <stdint.h> /*Dummy include by default*/
|
||||
#define LV_DRV_INDEV_RST(val) /*pin_x_set(val)*/ /*Set the reset pin to 'val'*/
|
||||
#define LV_DRV_INDEV_IRQ_READ 0 /*pn_x_read()*/ /*Read the IRQ pin*/
|
||||
|
||||
/*---------
|
||||
* SPI
|
||||
*---------*/
|
||||
#define LV_DRV_INDEV_SPI_CS(val) /*spi_cs_set(val)*/ /*Set the SPI's Chip select to 'val'*/
|
||||
#define LV_DRV_INDEV_SPI_XCHG_BYTE(data) 0 /*spi_xchg(val)*/ /*Write 'val' to SPI and give the read value*/
|
||||
|
||||
/*---------
|
||||
* I2C
|
||||
*---------*/
|
||||
#define LV_DRV_INDEV_I2C_START /*i2c_start()*/ /*Make an I2C start*/
|
||||
#define LV_DRV_INDEV_I2C_STOP /*i2c_stop()*/ /*Make an I2C stop*/
|
||||
#define LV_DRV_INDEV_I2C_RESTART /*i2c_restart()*/ /*Make an I2C restart*/
|
||||
#define LV_DRV_INDEV_I2C_WR(data) /*i2c_wr(data)*/ /*Write a byte to the I1C bus*/
|
||||
#define LV_DRV_INDEV_I2C_READ(last_read) 0 /*i2c_rd()*/ /*Read a byte from the I2C bud*/
|
||||
|
||||
|
||||
/*********************
|
||||
* DISPLAY DRIVERS
|
||||
*********************/
|
||||
|
||||
/*-------------------
|
||||
* Monitor of PC
|
||||
*-------------------*/
|
||||
#ifndef USE_MONITOR
|
||||
# define USE_MONITOR 0
|
||||
#endif
|
||||
|
||||
#if USE_MONITOR
|
||||
# define MONITOR_HOR_RES 480
|
||||
# define MONITOR_VER_RES 320
|
||||
|
||||
/* Scale window by this factor (useful when simulating small screens) */
|
||||
# define MONITOR_ZOOM 1
|
||||
|
||||
/* Used to test true double buffering with only address changing.
|
||||
* Use 2 draw buffers, bith with MONITOR_HOR_RES x MONITOR_VER_RES size*/
|
||||
# define MONITOR_DOUBLE_BUFFERED 0
|
||||
|
||||
/*Eclipse: <SDL2/SDL.h> Visual Studio: <SDL.h>*/
|
||||
# define MONITOR_SDL_INCLUDE_PATH <SDL2/SDL.h>
|
||||
|
||||
/*Open two windows to test multi display support*/
|
||||
# define MONITOR_DUAL 0
|
||||
#endif
|
||||
|
||||
/*-----------------------------------
|
||||
* Native Windows (including mouse)
|
||||
*----------------------------------*/
|
||||
#ifndef USE_WINDOWS
|
||||
# define USE_WINDOWS 0
|
||||
#endif
|
||||
|
||||
#if USE_WINDOWS
|
||||
# define WINDOW_HOR_RES 480
|
||||
# define WINDOW_VER_RES 320
|
||||
#endif
|
||||
|
||||
/*----------------------------
|
||||
* Native Windows (win32drv)
|
||||
*---------------------------*/
|
||||
#ifndef USE_WIN32DRV
|
||||
# define USE_WIN32DRV 0
|
||||
#endif
|
||||
|
||||
#if USE_WIN32DRV
|
||||
/* Scale window by this factor (useful when simulating small screens) */
|
||||
# define WIN32DRV_MONITOR_ZOOM 1
|
||||
#endif
|
||||
|
||||
/*----------------------------------------
|
||||
* GTK drivers (monitor, mouse, keyboard
|
||||
*---------------------------------------*/
|
||||
#ifndef USE_GTK
|
||||
# define USE_GTK 0
|
||||
#endif
|
||||
|
||||
/*----------------------------------------
|
||||
* Wayland drivers (monitor, mouse, keyboard, touchscreen)
|
||||
*---------------------------------------*/
|
||||
#ifndef USE_WAYLAND
|
||||
# define USE_WAYLAND 0
|
||||
#endif
|
||||
|
||||
#if USE_WAYLAND
|
||||
# define WAYLAND_HOR_RES 480
|
||||
# define WAYLAND_VER_RES 320
|
||||
# define WAYLAND_SURF_TITLE "LVGL"
|
||||
#endif
|
||||
|
||||
/*----------------
|
||||
* SSD1963
|
||||
*--------------*/
|
||||
#ifndef USE_SSD1963
|
||||
# define USE_SSD1963 0
|
||||
#endif
|
||||
|
||||
#if USE_SSD1963
|
||||
# define SSD1963_HOR_RES LV_HOR_RES
|
||||
# define SSD1963_VER_RES LV_VER_RES
|
||||
# define SSD1963_HT 531
|
||||
# define SSD1963_HPS 43
|
||||
# define SSD1963_LPS 8
|
||||
# define SSD1963_HPW 10
|
||||
# define SSD1963_VT 288
|
||||
# define SSD1963_VPS 12
|
||||
# define SSD1963_FPS 4
|
||||
# define SSD1963_VPW 10
|
||||
# define SSD1963_HS_NEG 0 /*Negative hsync*/
|
||||
# define SSD1963_VS_NEG 0 /*Negative vsync*/
|
||||
# define SSD1963_ORI 0 /*0, 90, 180, 270*/
|
||||
# define SSD1963_COLOR_DEPTH 16
|
||||
#endif
|
||||
|
||||
/*----------------
|
||||
* R61581
|
||||
*--------------*/
|
||||
#ifndef USE_R61581
|
||||
# define USE_R61581 0
|
||||
#endif
|
||||
|
||||
#if USE_R61581
|
||||
# define R61581_HOR_RES LV_HOR_RES
|
||||
# define R61581_VER_RES LV_VER_RES
|
||||
# define R61581_HSPL 0 /*HSYNC signal polarity*/
|
||||
# define R61581_HSL 10 /*HSYNC length (Not Implemented)*/
|
||||
# define R61581_HFP 10 /*Horitontal Front poarch (Not Implemented)*/
|
||||
# define R61581_HBP 10 /*Horitontal Back poarch (Not Implemented */
|
||||
# define R61581_VSPL 0 /*VSYNC signal polarity*/
|
||||
# define R61581_VSL 10 /*VSYNC length (Not Implemented)*/
|
||||
# define R61581_VFP 8 /*Vertical Front poarch*/
|
||||
# define R61581_VBP 8 /*Vertical Back poarch */
|
||||
# define R61581_DPL 0 /*DCLK signal polarity*/
|
||||
# define R61581_EPL 1 /*ENABLE signal polarity*/
|
||||
# define R61581_ORI 0 /*0, 180*/
|
||||
# define R61581_LV_COLOR_DEPTH 16 /*Fix 16 bit*/
|
||||
#endif
|
||||
|
||||
/*------------------------------
|
||||
* ST7565 (Monochrome, low res.)
|
||||
*-----------------------------*/
|
||||
#ifndef USE_ST7565
|
||||
# define USE_ST7565 0
|
||||
#endif
|
||||
|
||||
#if USE_ST7565
|
||||
/*No settings*/
|
||||
#endif /*USE_ST7565*/
|
||||
|
||||
/*------------------------------
|
||||
* GC9A01 (color, low res.)
|
||||
*-----------------------------*/
|
||||
#ifndef USE_GC9A01
|
||||
# define USE_GC9A01 0
|
||||
#endif
|
||||
|
||||
#if USE_GC9A01
|
||||
/*No settings*/
|
||||
#endif /*USE_GC9A01*/
|
||||
|
||||
/*------------------------------------------
|
||||
* UC1610 (4 gray 160*[104|128])
|
||||
* (EA DOGXL160 160x104 tested)
|
||||
*-----------------------------------------*/
|
||||
#ifndef USE_UC1610
|
||||
# define USE_UC1610 0
|
||||
#endif
|
||||
|
||||
#if USE_UC1610
|
||||
# define UC1610_HOR_RES LV_HOR_RES
|
||||
# define UC1610_VER_RES LV_VER_RES
|
||||
# define UC1610_INIT_CONTRAST 33 /* init contrast, values in [%] */
|
||||
# define UC1610_INIT_HARD_RST 0 /* 1 : hardware reset at init, 0 : software reset */
|
||||
# define UC1610_TOP_VIEW 0 /* 0 : Bottom View, 1 : Top View */
|
||||
#endif /*USE_UC1610*/
|
||||
|
||||
/*-------------------------------------------------
|
||||
* SHARP memory in pixel monochrome display series
|
||||
* LS012B7DD01 (184x38 pixels.)
|
||||
* LS013B7DH03 (128x128 pixels.)
|
||||
* LS013B7DH05 (144x168 pixels.)
|
||||
* LS027B7DH01 (400x240 pixels.) (tested)
|
||||
* LS032B7DD02 (336x536 pixels.)
|
||||
* LS044Q7DH01 (320x240 pixels.)
|
||||
*------------------------------------------------*/
|
||||
#ifndef USE_SHARP_MIP
|
||||
# define USE_SHARP_MIP 0
|
||||
#endif
|
||||
|
||||
#if USE_SHARP_MIP
|
||||
# define SHARP_MIP_HOR_RES LV_HOR_RES
|
||||
# define SHARP_MIP_VER_RES LV_VER_RES
|
||||
# define SHARP_MIP_SOFT_COM_INVERSION 0
|
||||
# define SHARP_MIP_REV_BYTE(b) /*((uint8_t) __REV(__RBIT(b)))*/ /*Architecture / compiler dependent byte bits order reverse*/
|
||||
#endif /*USE_SHARP_MIP*/
|
||||
|
||||
/*-------------------------------------------------
|
||||
* ILI9341 240X320 TFT LCD
|
||||
*------------------------------------------------*/
|
||||
#ifndef USE_ILI9341
|
||||
# define USE_ILI9341 0
|
||||
#endif
|
||||
|
||||
#if USE_ILI9341
|
||||
# define ILI9341_HOR_RES LV_HOR_RES
|
||||
# define ILI9341_VER_RES LV_VER_RES
|
||||
# define ILI9341_GAMMA 1
|
||||
# define ILI9341_TEARING 0
|
||||
#endif /*USE_ILI9341*/
|
||||
|
||||
/*-----------------------------------------
|
||||
* Linux frame buffer device (/dev/fbx)
|
||||
*-----------------------------------------*/
|
||||
#ifndef USE_FBDEV
|
||||
# define USE_FBDEV 0
|
||||
#endif
|
||||
|
||||
#if USE_FBDEV
|
||||
# define FBDEV_PATH "/dev/fb0"
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------
|
||||
* FreeBSD frame buffer device (/dev/fbx)
|
||||
*.........................................*/
|
||||
#ifndef USE_BSD_FBDEV
|
||||
# define USE_BSD_FBDEV 0
|
||||
#endif
|
||||
|
||||
#if USE_BSD_FBDEV
|
||||
# define FBDEV_PATH "/dev/fb0"
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------
|
||||
* DRM/KMS device (/dev/dri/cardX)
|
||||
*-----------------------------------------*/
|
||||
#ifndef USE_DRM
|
||||
# define USE_DRM 0
|
||||
#endif
|
||||
|
||||
#if USE_DRM
|
||||
# define DRM_CARD "/dev/dri/card0"
|
||||
# define DRM_CONNECTOR_ID -1 /* -1 for the first connected one */
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INPUT DEVICES
|
||||
*********************/
|
||||
|
||||
/*--------------
|
||||
* XPT2046
|
||||
*--------------*/
|
||||
#ifndef USE_XPT2046
|
||||
# define USE_XPT2046 0
|
||||
#endif
|
||||
|
||||
#if USE_XPT2046
|
||||
# define XPT2046_HOR_RES 480
|
||||
# define XPT2046_VER_RES 320
|
||||
# define XPT2046_X_MIN 200
|
||||
# define XPT2046_Y_MIN 200
|
||||
# define XPT2046_X_MAX 3800
|
||||
# define XPT2046_Y_MAX 3800
|
||||
# define XPT2046_AVG 4
|
||||
# define XPT2046_X_INV 0
|
||||
# define XPT2046_Y_INV 0
|
||||
# define XPT2046_XY_SWAP 0
|
||||
#endif
|
||||
|
||||
/*-----------------
|
||||
* FT5406EE8
|
||||
*-----------------*/
|
||||
#ifndef USE_FT5406EE8
|
||||
# define USE_FT5406EE8 0
|
||||
#endif
|
||||
|
||||
#if USE_FT5406EE8
|
||||
# define FT5406EE8_I2C_ADR 0x38 /*7 bit address*/
|
||||
#endif
|
||||
|
||||
/*---------------
|
||||
* AD TOUCH
|
||||
*--------------*/
|
||||
#ifndef USE_AD_TOUCH
|
||||
# define USE_AD_TOUCH 0
|
||||
#endif
|
||||
|
||||
#if USE_AD_TOUCH
|
||||
/*No settings*/
|
||||
#endif
|
||||
|
||||
|
||||
/*---------------------------------------
|
||||
* Mouse or touchpad on PC (using SDL)
|
||||
*-------------------------------------*/
|
||||
#ifndef USE_MOUSE
|
||||
# define USE_MOUSE 0
|
||||
#endif
|
||||
|
||||
#if USE_MOUSE
|
||||
/*No settings*/
|
||||
#endif
|
||||
|
||||
/*---------------
|
||||
* LINUX MICE
|
||||
*--------------*/
|
||||
#ifndef USE_LINMICE
|
||||
# define USE_LINMICE 0
|
||||
#endif
|
||||
|
||||
#if USE_LINMICE
|
||||
#define LINMICE_INV_AXES 0
|
||||
#define LINMICE_INV_X 0
|
||||
#define LINMICE_INV_Y 1
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------
|
||||
* Mousewheel as encoder on PC (using SDL)
|
||||
*------------------------------------------*/
|
||||
#ifndef USE_MOUSEWHEEL
|
||||
# define USE_MOUSEWHEEL 0
|
||||
#endif
|
||||
|
||||
#if USE_MOUSEWHEEL
|
||||
/*No settings*/
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------
|
||||
* Touchscreen as libinput interface (for Linux based systems)
|
||||
*------------------------------------------------*/
|
||||
#ifndef USE_LIBINPUT
|
||||
# define USE_LIBINPUT 0
|
||||
#endif
|
||||
|
||||
#if USE_LIBINPUT
|
||||
# define LIBINPUT_NAME "/dev/input/event0" /*You can use the "evtest" Linux tool to get the list of devices and test them*/
|
||||
#endif /*USE_LIBINPUT*/
|
||||
|
||||
/*-------------------------------------------------
|
||||
* Mouse or touchpad as evdev interface (for Linux based systems)
|
||||
*------------------------------------------------*/
|
||||
#ifndef USE_EVDEV
|
||||
# define USE_EVDEV 0
|
||||
#endif
|
||||
|
||||
#ifndef USE_BSD_EVDEV
|
||||
# define USE_BSD_EVDEV 0
|
||||
#endif
|
||||
|
||||
#if USE_EVDEV || USE_BSD_EVDEV
|
||||
# define EVDEV_NAME "/dev/input/event5" /*You can use the "evtest" Linux tool to get the list of devices and test them*/
|
||||
# define EVDEV_SWAP_AXES 1 /*Swap the x and y axes of the touchscreen*/
|
||||
|
||||
# define EVDEV_CALIBRATE 1 /*Scale and offset the touchscreen coordinates by using maximum and minimum values for each axis*/
|
||||
|
||||
# if EVDEV_CALIBRATE
|
||||
# define EVDEV_HOR_MIN 0 /*to invert axis swap EVDEV_XXX_MIN by EVDEV_XXX_MAX*/
|
||||
# define EVDEV_HOR_MAX 4096 /*"evtest" Linux tool can help to get the correct calibraion values>*/
|
||||
# define EVDEV_VER_MIN 0
|
||||
# define EVDEV_VER_MAX 4096
|
||||
# endif /*EVDEV_CALIBRATE*/
|
||||
#endif /*USE_EVDEV*/
|
||||
|
||||
/*-------------------------------
|
||||
* Keyboard of a PC (using SDL)
|
||||
*------------------------------*/
|
||||
#ifndef USE_KEYBOARD
|
||||
# define USE_KEYBOARD 0
|
||||
#endif
|
||||
|
||||
#if USE_KEYBOARD
|
||||
/*No settings*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRV_CONF_H*/
|
||||
|
||||
#endif /*End of "Content enable"*/
|
11
lvgl-based/partition-table/partitions.csv
Normal file
11
lvgl-based/partition-table/partitions.csv
Normal file
@ -0,0 +1,11 @@
|
||||
# http://esp-idf.readthedocs.io/en/latest/api-guides/partition-tables.html
|
||||
# This file uses a 3M factory instead of the default 1M
|
||||
|
||||
# Espressif ESP32 Partition Table
|
||||
# Name, Type, SubType, Offset, Size
|
||||
nvs, data, nvs, 0x9000, 0x6000
|
||||
phy_init, data, phy, 0xf000, 0x1000
|
||||
factory, app, factory, 0x10000, 3M
|
||||
# The size 528k isn't arbitrary - it is the minumim size when
|
||||
# wear leveling sector size is 4k
|
||||
app_storage, data, fat, , 528k
|
|
BIN
lvgl-based/photos/demo.jpg
Normal file
BIN
lvgl-based/photos/demo.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.7 MiB |
2
lvgl-based/rust-toolchain.toml
Normal file
2
lvgl-based/rust-toolchain.toml
Normal file
@ -0,0 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "esp"
|
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
|
11
lvgl-based/sdkconfig.defaults
Normal file
11
lvgl-based/sdkconfig.defaults
Normal file
@ -0,0 +1,11 @@
|
||||
# Rust often needs a bit of an extra main task stack size compared to C (the default is 3K)
|
||||
CONFIG_ESP_MAIN_TASK_STACK_SIZE=8000
|
||||
CONFIG_ESP_MAIN_TASK_STACK_SIZE=48000
|
||||
|
||||
# Use this to set FreeRTOS kernel tick frequency to 1000 Hz (100 Hz by default).
|
||||
# This allows to use 1 ms granuality for thread sleeps (10 ms by default).
|
||||
#CONFIG_FREERTOS_HZ=1000
|
||||
|
||||
# Workaround for https://github.com/espressif/esp-idf/issues/7631
|
||||
#CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=n
|
||||
#CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL=n
|
568
lvgl-based/src/bin/light-control.rs
Normal file
568
lvgl-based/src/bin/light-control.rs
Normal file
@ -0,0 +1,568 @@
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
cmp::min,
|
||||
str::FromStr,
|
||||
sync::mpsc::channel,
|
||||
thread,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
use cstr_core::CString;
|
||||
use display_interface_spi::SPIInterface;
|
||||
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,
|
||||
},
|
||||
units::FromValueType, // for converting 26MHz to value
|
||||
};
|
||||
use lvgl::{
|
||||
font::Font,
|
||||
input_device::{
|
||||
pointer::{Pointer, PointerInputData},
|
||||
InputDriver,
|
||||
},
|
||||
style::{FlexAlign, FlexFlow, Layout, Style},
|
||||
widgets::{Btn, Label, Slider, Switch},
|
||||
Align,
|
||||
AnimationState,
|
||||
Color,
|
||||
Display,
|
||||
DrawBuffer,
|
||||
Event,
|
||||
LvError,
|
||||
NativeObject,
|
||||
Obj,
|
||||
Part,
|
||||
Screen,
|
||||
TextAlign,
|
||||
Widget,
|
||||
};
|
||||
use mipidsi::{
|
||||
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 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: u8,
|
||||
}
|
||||
|
||||
impl Lamp {
|
||||
pub fn new(name: &str) -> Self {
|
||||
Self {
|
||||
name: heapless::String::from(
|
||||
heapless::String::from_str(name).unwrap(),
|
||||
),
|
||||
on: false,
|
||||
brightness: 255,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum Page<'a> {
|
||||
Home,
|
||||
LampCtrl(&'a Lamp),
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<(), LvError> {
|
||||
const HOR_RES: u32 = 320;
|
||||
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
|
||||
esp_idf_svc::sys::link_patches();
|
||||
|
||||
// Initialize lvgl
|
||||
lvgl::init();
|
||||
|
||||
// Bind the log crate to the ESP Logging facilities
|
||||
esp_idf_svc::log::EspLogger::initialize_default();
|
||||
|
||||
log::info!("================= Starting App =======================");
|
||||
|
||||
let peripherals = Peripherals::take().unwrap();
|
||||
|
||||
// #[allow(unused)]
|
||||
let pins = peripherals.pins;
|
||||
|
||||
let sclk = pins.gpio14;
|
||||
let miso = pins.gpio12;
|
||||
let mosi = pins.gpio13;
|
||||
let cs = pins.gpio15;
|
||||
let dc = pins.gpio2;
|
||||
|
||||
let spi = SpiDeviceDriver::new_single(
|
||||
peripherals.spi2,
|
||||
sclk, // sclk
|
||||
mosi, // sdo
|
||||
Some(miso), // sdi
|
||||
Some(cs), // cs
|
||||
&DriverConfig::new().dma(Dma::Channel1(4096)),
|
||||
&SpiConfig::new()
|
||||
.write_only(true)
|
||||
.baudrate(10.MHz().into()),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// let rst = PinDriver::output(pins.gpio33).unwrap();
|
||||
let dc = PinDriver::output(dc).unwrap();
|
||||
let di = SPIInterface::new(spi, dc);
|
||||
|
||||
// Turn backlight on
|
||||
let mut bklt = PinDriver::output(pins.gpio21).unwrap();
|
||||
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)
|
||||
// .with_display_size(320, 240)
|
||||
// .with_color_order(ColorOrder::Bgr)
|
||||
// .with_orientation(Orientation::Portrait(false))
|
||||
// .with_invert_colors(mipidsi::ColorInversion::Inverted)
|
||||
// .init(&mut delay::Ets, Some(rst))
|
||||
// .unwrap();
|
||||
|
||||
// 0.6.0
|
||||
// let mut raw_display = Builder::ili9342c_rgb565(di)
|
||||
// .with_orientation(Orientation::Portrait(false))
|
||||
// .with_color_order(ColorOrder::Bgr)
|
||||
// .with_invert_colors(true)
|
||||
// .init(&mut Delay::new_default(),
|
||||
// None::<PinDriver<AnyOutputPin, Output>>)
|
||||
// .unwrap();
|
||||
|
||||
let raw_display = Builder::new(ILI9341Rgb565, di)
|
||||
.orientation(Orientation {
|
||||
rotation: Rotation::Deg90,
|
||||
mirrored: true,
|
||||
})
|
||||
.color_order(ColorOrder::Bgr)
|
||||
// .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();
|
||||
let touch_irq = pins.gpio36;
|
||||
let touch_mosi = pins.gpio32;
|
||||
let touch_miso = pins.gpio39;
|
||||
let touch_clk = pins.gpio25;
|
||||
let touch_cs = pins.gpio33;
|
||||
|
||||
let mut touch_driver = Xpt2046::new(
|
||||
SpiDeviceDriver::new_single(
|
||||
peripherals.spi3,
|
||||
touch_clk,
|
||||
touch_mosi,
|
||||
Some(touch_miso),
|
||||
Some(touch_cs),
|
||||
&DriverConfig::new(),
|
||||
&SpiConfig::new()
|
||||
.write_only(true)
|
||||
.baudrate(2.MHz().into()),
|
||||
)
|
||||
.unwrap(),
|
||||
PinDriver::input(touch_irq).unwrap(),
|
||||
xpt2046::Orientation::LandscapeFlipped,
|
||||
);
|
||||
touch_driver.set_num_samples(1);
|
||||
touch_driver.init(&mut Delay::new_default()).unwrap();
|
||||
|
||||
let touch_driver = RefCell::new(touch_driver);
|
||||
|
||||
let _lvgl_thread = thread::Builder::new()
|
||||
.stack_size(40_000)
|
||||
.spawn(move || {
|
||||
println!("thread started");
|
||||
|
||||
let mut appdata = AppData::new();
|
||||
|
||||
let buffer = DrawBuffer::<{ (HOR_RES * LINES) as usize }>::default();
|
||||
let display = Display::register(buffer, HOR_RES, VER_RES, |refresh| {
|
||||
raw_display.draw_iter(refresh.as_pixels()).unwrap();
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
// Register a new input device that's capable of reading the current state of
|
||||
// the input
|
||||
// let mut last_touch = RefCell::new(None);
|
||||
let _touch_screen = Pointer::register(
|
||||
|| {
|
||||
let mut td_ref = touch_driver.borrow_mut();
|
||||
td_ref.run().expect("Running Touch driver failed");
|
||||
if td_ref.is_touched() {
|
||||
let point = td_ref.get_touch_point();
|
||||
// println!("touched {:?}", point);
|
||||
PointerInputData::Touch(Point::new(point.x + 20, 240 - point.y)).pressed().once()
|
||||
} else {
|
||||
// println!("untouched");
|
||||
PointerInputData::Touch(Point::new(0, 0)).released().once()
|
||||
}
|
||||
},
|
||||
&display,
|
||||
);
|
||||
|
||||
// Create screen and widgets
|
||||
let mut screen = display.get_scr_act().unwrap();
|
||||
let mut screen_style = Style::default();
|
||||
screen_style.set_bg_color(Color::from_rgb((0, 0, 0)));
|
||||
screen_style.set_radius(0);
|
||||
screen_style.set_layout(Layout::flex());
|
||||
screen_style.set_flex_flow(FlexFlow::ROW_WRAP);
|
||||
screen_style.set_flex_main_place(FlexAlign::CENTER);
|
||||
screen_style.set_flex_cross_place(FlexAlign::CENTER);
|
||||
screen.add_style(Part::Main, &mut screen_style);
|
||||
|
||||
|
||||
appdata.add_lamp("Front Door");
|
||||
appdata.add_lamp("Living Room");
|
||||
appdata.add_lamp("Bedroom");
|
||||
appdata.add_lamp("Bathroom");
|
||||
appdata.add_lamp("Porch");
|
||||
|
||||
let mut light_page = Screen::blank().unwrap();
|
||||
light_page.set_size(320, 240);
|
||||
let mut light_page_style = Style::default();
|
||||
light_page_style.set_bg_color(Color::from_rgb((0, 0, 0)));
|
||||
light_page_style.set_radius(0);
|
||||
light_page.add_style(Part::Main, &mut light_page_style);
|
||||
|
||||
let mut light_page_title_label = Label::create(&mut light_page).unwrap();
|
||||
let mut light_page_title_style = Style::default();
|
||||
light_page_title_style.set_text_color(Color::from_rgb((255, 255, 255)));
|
||||
unsafe { light_page_title_style.set_text_font(Font::new_raw(lvgl_sys::lv_font_montserrat_24)) };
|
||||
light_page_title_label.add_style(Part::Main, &mut light_page_title_style);
|
||||
light_page_title_label.set_align(Align::TopMid, 0, 6);
|
||||
|
||||
|
||||
let mut brightness_slider = Slider::create(&mut light_page).unwrap();
|
||||
brightness_slider.set_size(250, 10);
|
||||
// brightness_slider.range(0..255);
|
||||
brightness_slider.set_value(0, AnimationState::OFF);
|
||||
brightness_slider.set_align(Align::Center, 0, -20);
|
||||
|
||||
let mut brightness_slider_label = Label::create(&mut light_page).unwrap();
|
||||
// no text for now
|
||||
let mut white_text_style = Style::default();
|
||||
white_text_style.set_text_color(Color::from_rgb((255, 255, 255)));
|
||||
unsafe { white_text_style.set_text_font(Font::new_raw(lvgl_sys::lv_font_montserrat_14)) };
|
||||
brightness_slider_label.add_style(Part::Main, &mut white_text_style);
|
||||
brightness_slider_label.set_text(CString::new("Brightness").unwrap().as_c_str());
|
||||
brightness_slider_label.set_align(Align::Center, 0, -50);
|
||||
|
||||
|
||||
// Add switch
|
||||
let mut light_switch = Switch::create(&mut light_page).unwrap();
|
||||
light_switch.set_align(Align::Center, 0, 40);
|
||||
|
||||
let mut light_switch_label = Label::create(&mut light_page).unwrap();
|
||||
// no text for now
|
||||
let mut lslabel_style = Style::default();
|
||||
lslabel_style.set_text_color(Color::from_rgb((255, 255, 255)));
|
||||
unsafe { lslabel_style.set_text_font(Font::new_raw(lvgl_sys::lv_font_montserrat_14)) };
|
||||
light_switch_label.add_style(Part::Main, &mut lslabel_style);
|
||||
light_switch_label.set_text(CString::new("On/Off").unwrap().as_c_str());
|
||||
light_switch_label.set_align(Align::Center, 0, 10);
|
||||
|
||||
// Add back button
|
||||
let mut back_btn = Btn::create(&mut light_page).unwrap();
|
||||
back_btn.set_size(40, 40);
|
||||
back_btn.set_align(Align::TopLeft, 10, 10);
|
||||
back_btn.on_event(|_btn, event| {
|
||||
if let Event::Pressed = event {
|
||||
display.set_scr_act(&mut screen);
|
||||
}
|
||||
});
|
||||
|
||||
let mut back_label = Label::create(&mut back_btn).unwrap();
|
||||
back_label.set_text(CString::new(b"\xef\x81\x93").unwrap().as_c_str()); // Font Awesome left arrow
|
||||
let mut back_style = Style::default();
|
||||
unsafe { back_style.set_text_font(Font::new_raw(lvgl_sys::lv_font_montserrat_24)) };
|
||||
back_label.add_style(Part::Main, &mut back_style);
|
||||
|
||||
let mut light_ctrls = heapless::Vec::<(Btn, Label, Label), 8>::new();
|
||||
|
||||
let mut page = Page::Home;
|
||||
|
||||
for lamp in appdata.lamps.iter_mut() {
|
||||
let mut cont = Btn::new().unwrap();
|
||||
cont.set_size(100, 110);
|
||||
// cont.set_align(Align::TopLeft, 0, 0);
|
||||
|
||||
cont.on_event(|_btn, event| {
|
||||
if let Event::Pressed = event {
|
||||
// println!("lamp {:?}", lamp.name);
|
||||
// page = Page::LampCtrl(lamp);
|
||||
|
||||
brightness_slider.set_value(lerp_fixed(0, 100, lamp.brightness, 255).into(), AnimationState::OFF);
|
||||
unsafe {
|
||||
if lamp.on {
|
||||
lvgl_sys::lv_obj_add_state(light_switch.raw().as_ptr(), lvgl_sys::LV_STATE_CHECKED as u16);
|
||||
} else {
|
||||
lvgl_sys::lv_obj_clear_state(light_switch.raw().as_ptr(), lvgl_sys::LV_STATE_CHECKED as u16);
|
||||
}
|
||||
}
|
||||
light_switch.on_event(|_ls, event| {
|
||||
if let Event::ValueChanged | Event::Released = event {
|
||||
let on = unsafe { lvgl_sys::lv_obj_has_state(_ls.raw().as_ptr(), lvgl_sys::LV_STATE_CHECKED as u16) };
|
||||
lamp.on = on;
|
||||
}
|
||||
});
|
||||
brightness_slider.on_event(|_sldr, event| {
|
||||
// println!("event: {:?}", event);
|
||||
if let Event::ValueChanged | Event::Released = event {
|
||||
let brightness = _sldr.get_value();
|
||||
println!("brightness: {}", brightness);
|
||||
lamp.brightness = lerp_fixed(0, 255, brightness as u8, 100);
|
||||
println!("brightness: {}", lamp.brightness);
|
||||
}
|
||||
});
|
||||
light_page_title_label.set_text(CString::new(lamp.name.as_str()).unwrap().as_c_str());
|
||||
|
||||
display.set_scr_act(&mut light_page);
|
||||
}
|
||||
});
|
||||
|
||||
let mut style_name = Style::default();
|
||||
style_name.set_text_align(TextAlign::Center);
|
||||
style_name.set_text_color(Color::from_rgb((255, 255, 255)));
|
||||
unsafe { style_name.set_text_font(Font::new_raw(lvgl_sys::lv_font_montserrat_14)) };
|
||||
|
||||
let mut style_icon = Style::default();
|
||||
style_icon.set_text_color(Color::from_rgb((255, 255, 255)));
|
||||
unsafe { style_icon.set_text_font(Font::new_raw(lvgl_sys::lv_font_montserrat_32)) };
|
||||
style_icon.set_text_align(TextAlign::Center);
|
||||
|
||||
|
||||
let mut icon = Label::create(&mut cont).unwrap();
|
||||
icon.set_text(CString::new(b"\xef\x84\xa4").unwrap().as_c_str());
|
||||
icon.add_style(Part::Main, Box::leak(Box::new(style_icon)));
|
||||
icon.set_align(Align::Center, 0, 0);
|
||||
|
||||
let mut name = Label::create(&mut cont).unwrap();
|
||||
name.set_text(CString::new(lamp.name.as_str()).unwrap().as_c_str());
|
||||
// style_name.set_text_color(Color::from_rgb((255, 255, 255))); // white
|
||||
name.add_style(Part::Main, Box::leak(Box::new(style_name)));
|
||||
name.set_align(Align::BottomMid, 0, -4);
|
||||
|
||||
light_ctrls.push((cont, icon, name))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
|
||||
// let mut time = Label::new().unwrap();
|
||||
// time.set_text(CString::new("00:10:000").unwrap().as_c_str());
|
||||
// let mut style_time = Style::default();
|
||||
// style_time.set_text_color(Color::from_rgb((255, 255, 255))); // white
|
||||
// style_time.set_text_align(TextAlign::Center);
|
||||
// unsafe { style_time.set_text_font(Font::new_raw(lvgl_sys::lv_font_montserrat_24)) };
|
||||
// time.add_style(Part::Main, &mut style_time);
|
||||
// time.set_align(Align::Center, 0, 0);
|
||||
|
||||
/*
|
||||
|
||||
|
||||
// let mut cont = Obj::new().unwrap();
|
||||
// cont.set_size(320, 50);
|
||||
// let mut style = Style::default();
|
||||
// style.set_flex_flow(FlexFlow::ROW);
|
||||
// style.set_flex_main_place(FlexAlign::SPACE_EVENLY);
|
||||
// style.set_flex_cross_place(FlexAlign::CENTER);
|
||||
// // style.set_bg_opa(0);
|
||||
// style.set_border_width(0);
|
||||
// cont.add_style(Part::Any, &mut style);
|
||||
// cont.set_align(Align::Center, 0, 40);
|
||||
|
||||
let mut button_add = Btn::create(&mut screen).unwrap();
|
||||
button_add.set_align(Align::Center, -50, 32);
|
||||
// button_add.set_pos(130, 150);
|
||||
button_add.set_size(30, 30);
|
||||
// button_add.set_align(Align::Center, 0, 0);
|
||||
let mut btn_lbl1 = Label::create(&mut button_add).unwrap();
|
||||
btn_lbl1.set_text(CString::new(b"+").unwrap().as_c_str());
|
||||
|
||||
button_add.on_event(|_btn, event| {
|
||||
if let Event::Pressed = event {
|
||||
println!("pressed");
|
||||
if appdata.timer_stopped() {
|
||||
appdata.add_secs(10);
|
||||
}
|
||||
}
|
||||
// println!("Button received event: {:?}", event);
|
||||
});
|
||||
|
||||
let mut button_sub = Btn::create(&mut screen).unwrap();
|
||||
// button_sub.set_pos(170, 150);
|
||||
button_sub.set_size(30, 30);
|
||||
button_sub.set_align(Align::Center, 50, 35);
|
||||
// button_sub.set_align(Align::Center, 0, 0);
|
||||
let mut btn_lbl2 = Label::create(&mut button_sub).unwrap();
|
||||
btn_lbl2.set_text(CString::new(b"-").unwrap().as_c_str());
|
||||
|
||||
button_sub.on_event(|_btn, event| {
|
||||
if let Event::Pressed = event {
|
||||
if appdata.timer_stopped() {
|
||||
appdata.sub_secs(10);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let mut center_label = Label::new().unwrap();
|
||||
center_label.set_text(CString::new(b"+/- 10s").unwrap().as_c_str());
|
||||
center_label.set_align(Align::Center, 0, 35);
|
||||
let mut cl_style = Style::default();
|
||||
cl_style.set_text_color(Color::from_rgb((255, 255, 255)));
|
||||
center_label.add_style(Part::Main, &mut cl_style);
|
||||
|
||||
let mut button_reset = Btn::create(&mut screen).unwrap();
|
||||
//button_reset.set_pos(123, 190);
|
||||
button_reset.set_align(Align::Center, -22, 70);
|
||||
button_reset.set_size(35, 35);
|
||||
let mut btn_lbl3 = Label::create(&mut button_reset).unwrap();
|
||||
btn_lbl3.set_text(CString::new(b"\xEF\x80\xA1").unwrap().as_c_str());
|
||||
|
||||
|
||||
const PLAY: &'static [u8; 3] = b"\xEF\x81\x8B";
|
||||
const PAUSE: &'static [u8; 3] = b"\xEF\x81\x8C";
|
||||
const STOP: &'static [u8; 3] = b"\xEF\x81\x8D";
|
||||
|
||||
let mut button_start_stop = Btn::create(&mut screen).unwrap();
|
||||
// button_start_stop.set_pos(173, 190);
|
||||
button_start_stop.set_align(Align::Center, 22, 70);
|
||||
button_start_stop.set_size(35, 35);
|
||||
let mut btn_lbl4 = Label::create(&mut button_start_stop).unwrap();
|
||||
btn_lbl4.set_text(CString::new(b"\xEF\x81\x8B").unwrap().as_c_str());
|
||||
|
||||
button_reset.on_event(|_btn, event| {
|
||||
if let Event::Pressed = event {
|
||||
appdata.reset_timer();
|
||||
btn_lbl4.set_text(CString::new(PLAY).unwrap().as_c_str());
|
||||
}
|
||||
});
|
||||
|
||||
button_start_stop.on_event(|_btn, event| {
|
||||
if let Event::Pressed = event {
|
||||
if appdata.timer_finished() {
|
||||
// println!("Resetting finished timer");
|
||||
appdata.reset_timer();
|
||||
btn_lbl4.set_text(CString::new(PLAY).unwrap().as_c_str());
|
||||
} else if appdata.timer_running() {
|
||||
// println!("Pausing timer");
|
||||
appdata.pause_timer();
|
||||
btn_lbl4.set_text(CString::new(PLAY).unwrap().as_c_str());
|
||||
} else {
|
||||
// println!("Starting timer");
|
||||
appdata.start_timer();
|
||||
if appdata.timer_finished() {
|
||||
// println!("Timer already finished");
|
||||
btn_lbl4.set_text(CString::new(STOP).unwrap().as_c_str());
|
||||
} else {
|
||||
// println!("Timer running");
|
||||
btn_lbl4.set_text(CString::new(PAUSE).unwrap().as_c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
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 start_draw_time = Instant::now();
|
||||
lvgl::task_handler();
|
||||
|
||||
// Simulate clock - so sleep for one second so time text is incremented in
|
||||
// seconds
|
||||
// delay::FreeRtos::delay_ms(1);
|
||||
|
||||
let now_time = Instant::now();
|
||||
lvgl::tick_inc(now_time.duration_since(last_time));
|
||||
last_time = now_time;
|
||||
|
||||
|
||||
let end_time = Instant::now();
|
||||
let draw_time = raw_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);
|
||||
|
||||
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, );
|
||||
}
|
||||
raw_display.reset_time();
|
||||
|
||||
delay::FreeRtos::delay_ms(2);
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
loop {
|
||||
// Don't exit application
|
||||
delay::FreeRtos::delay_ms(1_000_000);
|
||||
}
|
||||
}
|
546
lvgl-based/src/bin/microwave-ui.rs
Normal file
546
lvgl-based/src/bin/microwave-ui.rs
Normal file
@ -0,0 +1,546 @@
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
cmp::min,
|
||||
str::FromStr,
|
||||
sync::mpsc::channel,
|
||||
thread,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
use cstr_core::CString;
|
||||
use display_interface_spi::SPIInterface;
|
||||
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,
|
||||
},
|
||||
units::FromValueType, // for converting 26MHz to value
|
||||
};
|
||||
use lvgl::{
|
||||
font::Font,
|
||||
input_device::{
|
||||
pointer::{Pointer, PointerInputData},
|
||||
InputDriver,
|
||||
},
|
||||
style::{FlexAlign, FlexFlow, Layout, Style},
|
||||
widgets::{Arc, Btn, Label, Slider, Switch},
|
||||
Align,
|
||||
AnimationState,
|
||||
Color,
|
||||
Display,
|
||||
DrawBuffer,
|
||||
Event,
|
||||
LvError,
|
||||
NativeObject,
|
||||
Obj,
|
||||
Part,
|
||||
Screen,
|
||||
TextAlign,
|
||||
Widget,
|
||||
};
|
||||
use mipidsi::{
|
||||
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 t = t.min(max_t);
|
||||
let result = start
|
||||
+ ((end - start.min(end)) * t + (max_t / 2))
|
||||
/ max_t;
|
||||
result as u8
|
||||
}
|
||||
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!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<(), LvError> {
|
||||
const HOR_RES: u32 = 320;
|
||||
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
|
||||
esp_idf_svc::sys::link_patches();
|
||||
|
||||
// Initialize lvgl
|
||||
lvgl::init();
|
||||
|
||||
// Bind the log crate to the ESP Logging facilities
|
||||
esp_idf_svc::log::EspLogger::initialize_default();
|
||||
|
||||
log::info!("================= Starting App =======================");
|
||||
|
||||
let peripherals = Peripherals::take().unwrap();
|
||||
|
||||
// #[allow(unused)]
|
||||
let pins = peripherals.pins;
|
||||
|
||||
let sclk = pins.gpio14;
|
||||
let miso = pins.gpio12;
|
||||
let mosi = pins.gpio13;
|
||||
let cs = pins.gpio15;
|
||||
let dc = pins.gpio2;
|
||||
|
||||
let spi = SpiDeviceDriver::new_single(
|
||||
peripherals.spi2,
|
||||
sclk, // sclk
|
||||
mosi, // sdo
|
||||
Some(miso), // sdi
|
||||
Some(cs), // cs
|
||||
&DriverConfig::new().dma(Dma::Channel1(4096)),
|
||||
&SpiConfig::new()
|
||||
.write_only(true)
|
||||
.baudrate(10.MHz().into()),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// let rst = PinDriver::output(pins.gpio33).unwrap();
|
||||
let dc = PinDriver::output(dc).unwrap();
|
||||
let di = SPIInterface::new(spi, dc);
|
||||
|
||||
// Turn backlight on
|
||||
let mut bklt = PinDriver::output(pins.gpio21).unwrap();
|
||||
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)
|
||||
// .with_display_size(320, 240)
|
||||
// .with_color_order(ColorOrder::Bgr)
|
||||
// .with_orientation(Orientation::Portrait(false))
|
||||
// .with_invert_colors(mipidsi::ColorInversion::Inverted)
|
||||
// .init(&mut delay::Ets, Some(rst))
|
||||
// .unwrap();
|
||||
|
||||
// 0.6.0
|
||||
// let mut raw_display = Builder::ili9342c_rgb565(di)
|
||||
// .with_orientation(Orientation::Portrait(false))
|
||||
// .with_color_order(ColorOrder::Bgr)
|
||||
// .with_invert_colors(true)
|
||||
// .init(&mut Delay::new_default(),
|
||||
// None::<PinDriver<AnyOutputPin, Output>>)
|
||||
// .unwrap();
|
||||
|
||||
let raw_display = Builder::new(ILI9341Rgb565, di)
|
||||
.orientation(Orientation {
|
||||
rotation: Rotation::Deg90,
|
||||
mirrored: true,
|
||||
})
|
||||
.color_order(ColorOrder::Bgr)
|
||||
// .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();
|
||||
let touch_irq = pins.gpio36;
|
||||
let touch_mosi = pins.gpio32;
|
||||
let touch_miso = pins.gpio39;
|
||||
let touch_clk = pins.gpio25;
|
||||
let touch_cs = pins.gpio33;
|
||||
|
||||
let mut touch_driver = Xpt2046::new(
|
||||
SpiDeviceDriver::new_single(
|
||||
peripherals.spi3,
|
||||
touch_clk,
|
||||
touch_mosi,
|
||||
Some(touch_miso),
|
||||
Some(touch_cs),
|
||||
&DriverConfig::new(),
|
||||
&SpiConfig::new()
|
||||
.write_only(true)
|
||||
.baudrate(2.MHz().into()),
|
||||
)
|
||||
.unwrap(),
|
||||
PinDriver::input(touch_irq).unwrap(),
|
||||
xpt2046::Orientation::LandscapeFlipped,
|
||||
);
|
||||
touch_driver.set_num_samples(1);
|
||||
touch_driver.init(&mut Delay::new_default()).unwrap();
|
||||
|
||||
let touch_driver = RefCell::new(touch_driver);
|
||||
|
||||
let _lvgl_thread = thread::Builder::new()
|
||||
.stack_size(40_000)
|
||||
.spawn(move || {
|
||||
println!("thread started");
|
||||
|
||||
let mut appdata = AppData::new();
|
||||
|
||||
let buffer = DrawBuffer::<{ (HOR_RES * LINES) as usize }>::default();
|
||||
let display = Display::register(buffer, HOR_RES, VER_RES, |refresh| {
|
||||
raw_display.draw_iter(refresh.as_pixels()).unwrap();
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
// Register a new input device that's capable of reading the current state of
|
||||
// the input
|
||||
// let mut last_touch = RefCell::new(None);
|
||||
let _touch_screen = Pointer::register(
|
||||
|| {
|
||||
let mut td_ref = touch_driver.borrow_mut();
|
||||
td_ref.run().expect("Running Touch driver failed");
|
||||
if td_ref.is_touched() {
|
||||
let point = td_ref.get_touch_point();
|
||||
// println!("touched {:?}", point);
|
||||
PointerInputData::Touch(Point::new(point.x + 20, 240 - point.y)).pressed().once()
|
||||
} else {
|
||||
// println!("untouched");
|
||||
PointerInputData::Touch(Point::new(0, 0)).released().once()
|
||||
}
|
||||
},
|
||||
&display,
|
||||
);
|
||||
|
||||
// Create screen and widgets
|
||||
let mut screen = display.get_scr_act().unwrap();
|
||||
let mut screen_style = Style::default();
|
||||
screen_style.set_bg_color(Color::from_rgb((0, 0, 0)));
|
||||
screen_style.set_radius(0);
|
||||
// screen_style.set_layout(Layout::flex());
|
||||
// screen_style.set_flex_flow(FlexFlow::ROW_WRAP);
|
||||
// screen_style.set_flex_main_place(FlexAlign::CENTER);
|
||||
// screen_style.set_flex_cross_place(FlexAlign::CENTER);
|
||||
screen.add_style(Part::Main, &mut screen_style);
|
||||
|
||||
|
||||
let mut wattage_label = Label::create(&mut screen).unwrap();
|
||||
wattage_label.set_align(Align::Center, -70, 0);
|
||||
let mut wattage_style = Style::default();
|
||||
wattage_style.set_text_color(Color::from_rgb((255, 255, 255)));
|
||||
unsafe { wattage_style.set_text_font(Font::new_raw(lvgl_sys::lv_font_montserrat_32)) };
|
||||
wattage_label.add_style(Part::Main, &mut wattage_style);
|
||||
wattage_label.set_text(CString::new(appdata.get_wattage_level_str()).unwrap().as_c_str());
|
||||
|
||||
|
||||
let mut power_arc = Arc::create(&mut screen).unwrap();
|
||||
power_arc.set_size(150, 150);
|
||||
power_arc.set_align(Align::Center, -70, 0);
|
||||
power_arc.set_angles(135, 45); // Creates a 270-degree arc
|
||||
power_arc.set_rotation(0);
|
||||
power_arc.set_bg_angles(135, 45);
|
||||
unsafe {
|
||||
lvgl_sys::lv_arc_set_range(power_arc.raw().as_mut(), 0, 5);
|
||||
}
|
||||
|
||||
power_arc.on_event(|arc, event| {
|
||||
if let Event::ValueChanged = event {
|
||||
let mut value = unsafe {
|
||||
lvgl_sys::lv_arc_get_value(arc.raw().as_mut())
|
||||
};
|
||||
appdata.set_wattage_level((value as u8).min(6));
|
||||
wattage_label.set_text(CString::new(appdata.get_wattage_level_str()).unwrap().as_c_str());
|
||||
}
|
||||
});
|
||||
|
||||
// Add timer display on the right
|
||||
let mut time_label = Label::new().unwrap();
|
||||
time_label.set_text(CString::new("00:10:000").unwrap().as_c_str());
|
||||
let mut style_time = Style::default();
|
||||
style_time.set_text_color(Color::from_rgb((255, 255, 255)));
|
||||
style_time.set_text_align(TextAlign::Center);
|
||||
unsafe { style_time.set_text_font(Font::new_raw(lvgl_sys::lv_font_montserrat_24)) };
|
||||
time_label.add_style(Part::Main, &mut style_time);
|
||||
time_label.set_align(Align::Center, 80, 0);
|
||||
|
||||
// Add + and - buttons at bottom
|
||||
let mut button_add = Btn::create(&mut screen).unwrap();
|
||||
button_add.set_align(Align::Center, 10, 70);
|
||||
button_add.set_size(30, 30);
|
||||
let mut btn_lbl1 = Label::create(&mut button_add).unwrap();
|
||||
btn_lbl1.set_text(CString::new(b"+").unwrap().as_c_str());
|
||||
|
||||
let mut button_sub = Btn::create(&mut screen).unwrap();
|
||||
button_sub.set_size(30, 30);
|
||||
button_sub.set_align(Align::Center, 130, 70);
|
||||
let mut btn_lbl2 = Label::create(&mut button_sub).unwrap();
|
||||
btn_lbl2.set_text(CString::new(b"-").unwrap().as_c_str());
|
||||
|
||||
// Add timer control logic from timer.rs
|
||||
button_add.on_event(|_btn, event| {
|
||||
if let Event::Pressed = event {
|
||||
if appdata.timer_stopped() {
|
||||
appdata.add_secs(10);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
button_sub.on_event(|_btn, event| {
|
||||
if let Event::Pressed = event {
|
||||
if appdata.timer_stopped() {
|
||||
appdata.sub_secs(10);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Add reset button
|
||||
let mut button_reset = Btn::create(&mut screen).unwrap();
|
||||
button_reset.set_align(Align::Center, 50, 70);
|
||||
button_reset.set_size(35, 35);
|
||||
let mut btn_lbl3 = Label::create(&mut button_reset).unwrap();
|
||||
btn_lbl3.set_text(CString::new(b"\xEF\x80\xA1").unwrap().as_c_str());
|
||||
|
||||
// Add start/stop/pause button
|
||||
const PLAY: &'static [u8; 3] = b"\xEF\x81\x8B";
|
||||
const PAUSE: &'static [u8; 3] = b"\xEF\x81\x8C";
|
||||
const STOP: &'static [u8; 3] = b"\xEF\x81\x8D";
|
||||
|
||||
let mut button_start_stop = Btn::create(&mut screen).unwrap();
|
||||
button_start_stop.set_align(Align::Center, 90, 70);
|
||||
button_start_stop.set_size(35, 35);
|
||||
let mut btn_lbl4 = Label::create(&mut button_start_stop).unwrap();
|
||||
btn_lbl4.set_text(CString::new(PLAY).unwrap().as_c_str());
|
||||
|
||||
// Add event handlers
|
||||
button_reset.on_event(|_btn, event| {
|
||||
if let Event::Pressed = event {
|
||||
appdata.reset_timer();
|
||||
btn_lbl4.set_text(CString::new(PLAY).unwrap().as_c_str());
|
||||
unsafe {
|
||||
lvgl_sys::lv_obj_clear_state(button_add.raw().as_mut(), lvgl_sys::LV_STATE_DISABLED as u16);
|
||||
lvgl_sys::lv_obj_clear_state(button_sub.raw().as_mut(), lvgl_sys::LV_STATE_DISABLED as u16);
|
||||
lvgl_sys::lv_obj_clear_state(power_arc.raw().as_mut(), lvgl_sys::LV_STATE_DISABLED as u16);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
button_start_stop.on_event(|_btn, event| {
|
||||
if let Event::Pressed = event {
|
||||
if appdata.timer_finished() {
|
||||
appdata.reset_timer();
|
||||
btn_lbl4.set_text(CString::new(PLAY).unwrap().as_c_str());
|
||||
// Enable all buttons
|
||||
unsafe {
|
||||
lvgl_sys::lv_obj_clear_state(button_add.raw().as_mut(), lvgl_sys::LV_STATE_DISABLED as u16);
|
||||
lvgl_sys::lv_obj_clear_state(button_sub.raw().as_mut(), lvgl_sys::LV_STATE_DISABLED as u16);
|
||||
lvgl_sys::lv_obj_clear_state(power_arc.raw().as_mut(), lvgl_sys::LV_STATE_DISABLED as u16);
|
||||
}
|
||||
} else if appdata.timer_running() {
|
||||
appdata.pause_timer();
|
||||
btn_lbl4.set_text(CString::new(PLAY).unwrap().as_c_str());
|
||||
// Enable all buttons
|
||||
unsafe {
|
||||
lvgl_sys::lv_obj_clear_state(button_add.raw().as_mut(), lvgl_sys::LV_STATE_DISABLED as u16);
|
||||
lvgl_sys::lv_obj_clear_state(button_sub.raw().as_mut(), lvgl_sys::LV_STATE_DISABLED as u16);
|
||||
lvgl_sys::lv_obj_clear_state(power_arc.raw().as_mut(), lvgl_sys::LV_STATE_DISABLED as u16);
|
||||
}
|
||||
} else {
|
||||
appdata.start_timer();
|
||||
if appdata.timer_finished() {
|
||||
btn_lbl4.set_text(CString::new(STOP).unwrap().as_c_str());
|
||||
} else {
|
||||
btn_lbl4.set_text(CString::new(PAUSE).unwrap().as_c_str());
|
||||
// Disable buttons while running
|
||||
unsafe {
|
||||
lvgl_sys::lv_obj_add_state(button_add.raw().as_mut(), lvgl_sys::LV_STATE_DISABLED as u16);
|
||||
lvgl_sys::lv_obj_add_state(button_sub.raw().as_mut(), lvgl_sys::LV_STATE_DISABLED as u16);
|
||||
lvgl_sys::lv_obj_add_state(power_arc.raw().as_mut(), lvgl_sys::LV_STATE_DISABLED as u16);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
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 dur = appdata.remaining();
|
||||
if last_rem_time != dur {
|
||||
let val = CString::new(format!("{:02}:{:02}:{:03}",
|
||||
dur.as_secs() / 60,
|
||||
dur.as_secs() % 60,
|
||||
dur.as_millis() % 1000)).unwrap();
|
||||
|
||||
time_label.set_text(&val).unwrap();
|
||||
last_rem_time = dur;
|
||||
}
|
||||
|
||||
if !was_finished && appdata.timer_finished() {
|
||||
btn_lbl4.set_text(CString::new(STOP).unwrap().as_c_str());
|
||||
}
|
||||
was_finished = appdata.timer_finished();
|
||||
|
||||
let start_draw_time = Instant::now();
|
||||
lvgl::task_handler();
|
||||
|
||||
let now_time = Instant::now();
|
||||
lvgl::tick_inc(now_time.duration_since(last_time));
|
||||
last_time = now_time;
|
||||
|
||||
let end_time = Instant::now();
|
||||
let draw_time = raw_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);
|
||||
|
||||
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, );
|
||||
}
|
||||
raw_display.reset_time();
|
||||
|
||||
delay::FreeRtos::delay_ms(2);
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
loop {
|
||||
// Don't exit application
|
||||
delay::FreeRtos::delay_ms(1_000_000);
|
||||
}
|
||||
}
|
266
lvgl-based/src/bin/starter.rs
Normal file
266
lvgl-based/src/bin/starter.rs
Normal file
@ -0,0 +1,266 @@
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
sync::mpsc::channel,
|
||||
thread,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use std::cmp::min;
|
||||
use cstr_core::CString;
|
||||
use display_interface_spi::SPIInterface;
|
||||
use embedded_graphics_core::{draw_target::DrawTarget, prelude::Point};
|
||||
use esp_idf_hal::spi::SpiSingleDeviceDriver;
|
||||
use esp_idf_hal::{
|
||||
delay::{self, Delay},
|
||||
gpio::*,
|
||||
peripherals::Peripherals,
|
||||
spi::{config::DriverConfig, Dma, SpiConfig, SpiDeviceDriver},
|
||||
units::FromValueType, // for converting 26MHz to value
|
||||
};
|
||||
use lvgl::{
|
||||
font::Font,
|
||||
input_device::{
|
||||
pointer::{Pointer, PointerInputData},
|
||||
InputDriver,
|
||||
},
|
||||
style::Style,
|
||||
widgets::{Btn, Label},
|
||||
Align,
|
||||
Color,
|
||||
Display,
|
||||
DrawBuffer,
|
||||
LvError,
|
||||
Part,
|
||||
TextAlign,
|
||||
Widget,
|
||||
};
|
||||
use mipidsi::{
|
||||
models::ILI9486Rgb565,
|
||||
options::{ColorInversion, ColorOrder, Orientation, Rotation},
|
||||
Builder,
|
||||
};
|
||||
use xpt2046::Xpt2046;
|
||||
use embedded_graphics_profiler_display::ProfilerDisplay;
|
||||
|
||||
fn main() -> Result<(), LvError> {
|
||||
const HOR_RES: u32 = 320;
|
||||
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
|
||||
esp_idf_svc::sys::link_patches();
|
||||
|
||||
// Initialize lvgl
|
||||
lvgl::init();
|
||||
|
||||
// Bind the log crate to the ESP Logging facilities
|
||||
esp_idf_svc::log::EspLogger::initialize_default();
|
||||
|
||||
log::info!("================= Starting App =======================");
|
||||
|
||||
let peripherals = Peripherals::take().unwrap();
|
||||
|
||||
// #[allow(unused)]
|
||||
let pins = peripherals.pins;
|
||||
|
||||
let sclk = pins.gpio14;
|
||||
let miso = pins.gpio12;
|
||||
let mosi = pins.gpio13;
|
||||
let cs = pins.gpio15;
|
||||
let dc = pins.gpio2;
|
||||
|
||||
let spi = SpiDeviceDriver::new_single(
|
||||
peripherals.spi2,
|
||||
sclk, // sclk
|
||||
mosi, // sdo
|
||||
Some(miso), // sdi
|
||||
Some(cs), // cs
|
||||
&DriverConfig::new().dma(Dma::Channel1(4096)),
|
||||
&SpiConfig::new().write_only(true).baudrate(10.MHz().into()),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// let rst = PinDriver::output(pins.gpio33).unwrap();
|
||||
let dc = PinDriver::output(dc).unwrap();
|
||||
let di = SPIInterface::new(spi, dc);
|
||||
|
||||
// Turn backlight on
|
||||
let mut bklt = PinDriver::output(pins.gpio21).unwrap();
|
||||
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)
|
||||
// .with_display_size(320, 240)
|
||||
// .with_color_order(ColorOrder::Bgr)
|
||||
// .with_orientation(Orientation::Portrait(false))
|
||||
// .with_invert_colors(mipidsi::ColorInversion::Inverted)
|
||||
// .init(&mut delay::Ets, Some(rst))
|
||||
// .unwrap();
|
||||
|
||||
// 0.6.0
|
||||
// let mut raw_display = Builder::ili9342c_rgb565(di)
|
||||
// .with_orientation(Orientation::Portrait(false))
|
||||
// .with_color_order(ColorOrder::Bgr)
|
||||
// .with_invert_colors(true)
|
||||
// .init(&mut Delay::new_default(), None::<PinDriver<AnyOutputPin, Output>>)
|
||||
// .unwrap();
|
||||
|
||||
let raw_display = Builder::new(ILI9486Rgb565, di)
|
||||
.orientation(Orientation {
|
||||
rotation: Rotation::Deg90,
|
||||
mirrored: true,
|
||||
})
|
||||
.color_order(ColorOrder::Bgr)
|
||||
.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();
|
||||
let touch_irq = pins.gpio36;
|
||||
let touch_mosi = pins.gpio32;
|
||||
let touch_miso = pins.gpio39;
|
||||
let touch_clk = pins.gpio25;
|
||||
let touch_cs = pins.gpio33;
|
||||
|
||||
let mut touch_driver = Xpt2046::new(
|
||||
SpiDeviceDriver::new_single(
|
||||
peripherals.spi3,
|
||||
touch_clk,
|
||||
touch_mosi,
|
||||
Some(touch_miso),
|
||||
Some(touch_cs),
|
||||
&DriverConfig::new(),
|
||||
&SpiConfig::new().write_only(true).baudrate(2.MHz().into()),
|
||||
)
|
||||
.unwrap(),
|
||||
PinDriver::input(touch_irq).unwrap(),
|
||||
xpt2046::Orientation::LandscapeFlipped,
|
||||
);
|
||||
touch_driver.set_num_samples(1);
|
||||
touch_driver.init(&mut Delay::new_default()).unwrap();
|
||||
|
||||
let touch_driver = RefCell::new(touch_driver);
|
||||
|
||||
let _lvgl_thread = thread::Builder::new()
|
||||
.stack_size(40_000)
|
||||
.spawn(move || {
|
||||
println!("thread started");
|
||||
|
||||
let buffer = DrawBuffer::<{ (HOR_RES * LINES) as usize }>::default();
|
||||
let display = Display::register(buffer, HOR_RES, VER_RES, |refresh| {
|
||||
raw_display.draw_iter(refresh.as_pixels()).unwrap();
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
// Register a new input device that's capable of reading the current state of
|
||||
// the input
|
||||
// let mut last_touch = RefCell::new(None);
|
||||
let _touch_screen = Pointer::register(
|
||||
|| {
|
||||
let mut td_ref = touch_driver.borrow_mut();
|
||||
td_ref.run().expect("Running Touch driver failed");
|
||||
if td_ref.is_touched() {
|
||||
let point = td_ref.get_touch_point();
|
||||
PointerInputData::Touch(point).pressed().once()
|
||||
} else {
|
||||
PointerInputData::Touch(Point::new(0, 0)).released().once()
|
||||
}
|
||||
},
|
||||
&display,
|
||||
);
|
||||
|
||||
// Create screen and widgets
|
||||
let mut screen = display.get_scr_act().unwrap();
|
||||
let mut screen_style = Style::default();
|
||||
screen_style.set_bg_color(Color::from_rgb((0, 0, 0)));
|
||||
screen_style.set_radius(0);
|
||||
screen.add_style(Part::Main, &mut screen_style);
|
||||
|
||||
let mut time = Label::new().unwrap();
|
||||
let mut style_time = Style::default();
|
||||
style_time.set_text_color(Color::from_rgb((255, 255, 255))); // white
|
||||
style_time.set_text_align(TextAlign::Center);
|
||||
|
||||
// Custom font requires lvgl-sys in Cargo.toml and 'use lvgl_sys' in this file
|
||||
style_time.set_text_font(unsafe { Font::new_raw(lvgl_sys::gotham_bold_80) });
|
||||
|
||||
time.add_style(Part::Main, &mut style_time);
|
||||
|
||||
// Time text will be centered in screen
|
||||
time.set_align(Align::Center, 0, 0);
|
||||
|
||||
let mut button = Btn::create(&mut screen).unwrap();
|
||||
button.set_align(Align::LeftMid, 30, 0);
|
||||
button.set_size(180, 80);
|
||||
let mut btn_lbl = Label::create(&mut button).unwrap();
|
||||
btn_lbl.set_text(CString::new("Click me!").unwrap().as_c_str());
|
||||
|
||||
let mut btn_state = false;
|
||||
button.on_event(|_btn, event| {
|
||||
// println!("Button received event: {:?}", event);
|
||||
if let lvgl::Event::Clicked = event {
|
||||
if btn_state {
|
||||
let nt = CString::new("Click me!").unwrap();
|
||||
btn_lbl.set_text(nt.as_c_str()).unwrap();
|
||||
} else {
|
||||
let nt = CString::new("Clicked!").unwrap();
|
||||
btn_lbl.set_text(nt.as_c_str()).unwrap();
|
||||
}
|
||||
btn_state = !btn_state;
|
||||
}
|
||||
});
|
||||
|
||||
let mut i = 0;
|
||||
|
||||
loop {
|
||||
let start_time = Instant::now();
|
||||
if i > 59 {
|
||||
i = 0;
|
||||
}
|
||||
|
||||
let val = CString::new(format!("21:{:02}", i)).unwrap();
|
||||
time.set_text(&val).unwrap();
|
||||
i += 1;
|
||||
|
||||
let start_draw_time = Instant::now();
|
||||
lvgl::task_handler();
|
||||
|
||||
// Simulate clock - so sleep for one second so time text is incremented in
|
||||
// seconds
|
||||
delay::FreeRtos::delay_ms(10);
|
||||
|
||||
lvgl::tick_inc(Instant::now().duration_since(start_time));
|
||||
|
||||
|
||||
let end_time = Instant::now();
|
||||
let draw_time = raw_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);
|
||||
|
||||
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, );
|
||||
}
|
||||
raw_display.reset_time();
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
loop {
|
||||
// Don't exit application
|
||||
delay::FreeRtos::delay_ms(1_000_000);
|
||||
}
|
||||
}
|
492
lvgl-based/src/bin/timer.rs
Normal file
492
lvgl-based/src/bin/timer.rs
Normal file
@ -0,0 +1,492 @@
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
cmp::min,
|
||||
sync::mpsc::channel,
|
||||
thread,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
use cstr_core::CString;
|
||||
use display_interface_spi::SPIInterface;
|
||||
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,
|
||||
},
|
||||
units::FromValueType, // for converting 26MHz to value
|
||||
};
|
||||
use lvgl::{
|
||||
font::Font,
|
||||
input_device::{
|
||||
pointer::{Pointer, PointerInputData},
|
||||
InputDriver,
|
||||
},
|
||||
style::{FlexAlign, FlexFlow, Style},
|
||||
widgets::{Btn, Label},
|
||||
Align,
|
||||
Color,
|
||||
Display,
|
||||
DrawBuffer,
|
||||
Event,
|
||||
LvError,
|
||||
Obj,
|
||||
Part,
|
||||
TextAlign,
|
||||
Widget,
|
||||
};
|
||||
use mipidsi::{
|
||||
models::ILI9341Rgb565,
|
||||
options::{
|
||||
ColorInversion,
|
||||
ColorOrder,
|
||||
Orientation,
|
||||
Rotation,
|
||||
},
|
||||
Builder,
|
||||
};
|
||||
use xpt2046::Xpt2046;
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<(), LvError> {
|
||||
const HOR_RES: u32 = 320;
|
||||
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
|
||||
esp_idf_svc::sys::link_patches();
|
||||
|
||||
// Initialize lvgl
|
||||
lvgl::init();
|
||||
|
||||
// Bind the log crate to the ESP Logging facilities
|
||||
esp_idf_svc::log::EspLogger::initialize_default();
|
||||
|
||||
log::info!("================= Starting App =======================");
|
||||
|
||||
let peripherals = Peripherals::take().unwrap();
|
||||
|
||||
// #[allow(unused)]
|
||||
let pins = peripherals.pins;
|
||||
|
||||
let sclk = pins.gpio14;
|
||||
let miso = pins.gpio12;
|
||||
let mosi = pins.gpio13;
|
||||
let cs = pins.gpio15;
|
||||
let dc = pins.gpio2;
|
||||
|
||||
let spi = SpiDeviceDriver::new_single(
|
||||
peripherals.spi2,
|
||||
sclk, // sclk
|
||||
mosi, // sdo
|
||||
Some(miso), // sdi
|
||||
Some(cs), // cs
|
||||
&DriverConfig::new().dma(Dma::Channel1(4096)),
|
||||
&SpiConfig::new()
|
||||
.write_only(true)
|
||||
.baudrate(10.MHz().into()),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// let rst = PinDriver::output(pins.gpio33).unwrap();
|
||||
let dc = PinDriver::output(dc).unwrap();
|
||||
let di = SPIInterface::new(spi, dc);
|
||||
|
||||
// Turn backlight on
|
||||
let mut bklt = PinDriver::output(pins.gpio21).unwrap();
|
||||
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)
|
||||
// .with_display_size(320, 240)
|
||||
// .with_color_order(ColorOrder::Bgr)
|
||||
// .with_orientation(Orientation::Portrait(false))
|
||||
// .with_invert_colors(mipidsi::ColorInversion::Inverted)
|
||||
// .init(&mut delay::Ets, Some(rst))
|
||||
// .unwrap();
|
||||
|
||||
// 0.6.0
|
||||
// let mut raw_display = Builder::ili9342c_rgb565(di)
|
||||
// .with_orientation(Orientation::Portrait(false))
|
||||
// .with_color_order(ColorOrder::Bgr)
|
||||
// .with_invert_colors(true)
|
||||
// .init(&mut Delay::new_default(),
|
||||
// None::<PinDriver<AnyOutputPin, Output>>)
|
||||
// .unwrap();
|
||||
|
||||
let raw_display = Builder::new(ILI9341Rgb565, di)
|
||||
.orientation(Orientation {
|
||||
rotation: Rotation::Deg90,
|
||||
mirrored: true,
|
||||
})
|
||||
.color_order(ColorOrder::Bgr)
|
||||
// .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();
|
||||
let touch_irq = pins.gpio36;
|
||||
let touch_mosi = pins.gpio32;
|
||||
let touch_miso = pins.gpio39;
|
||||
let touch_clk = pins.gpio25;
|
||||
let touch_cs = pins.gpio33;
|
||||
|
||||
let mut touch_driver = Xpt2046::new(
|
||||
SpiDeviceDriver::new_single(
|
||||
peripherals.spi3,
|
||||
touch_clk,
|
||||
touch_mosi,
|
||||
Some(touch_miso),
|
||||
Some(touch_cs),
|
||||
&DriverConfig::new(),
|
||||
&SpiConfig::new()
|
||||
.write_only(true)
|
||||
.baudrate(2.MHz().into()),
|
||||
)
|
||||
.unwrap(),
|
||||
PinDriver::input(touch_irq).unwrap(),
|
||||
xpt2046::Orientation::LandscapeFlipped,
|
||||
);
|
||||
touch_driver.set_num_samples(1);
|
||||
touch_driver.init(&mut Delay::new_default()).unwrap();
|
||||
|
||||
let touch_driver = RefCell::new(touch_driver);
|
||||
|
||||
let _lvgl_thread = thread::Builder::new()
|
||||
.stack_size(40_000)
|
||||
.spawn(move || {
|
||||
println!("thread started");
|
||||
|
||||
let mut appdata = AppData::new();
|
||||
|
||||
let buffer = DrawBuffer::<{ (HOR_RES * LINES) as usize }>::default();
|
||||
let display = Display::register(buffer, HOR_RES, VER_RES, |refresh| {
|
||||
raw_display.draw_iter(refresh.as_pixels()).unwrap();
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
// Register a new input device that's capable of reading the current state of
|
||||
// the input
|
||||
// let mut last_touch = RefCell::new(None);
|
||||
let _touch_screen = Pointer::register(
|
||||
|| {
|
||||
let mut td_ref = touch_driver.borrow_mut();
|
||||
td_ref.run().expect("Running Touch driver failed");
|
||||
if td_ref.is_touched() {
|
||||
let point = td_ref.get_touch_point();
|
||||
// println!("touched {:?}", point);
|
||||
PointerInputData::Touch(Point::new(point.x + 20, 240 - point.y)).pressed().once()
|
||||
} else {
|
||||
// println!("untouched");
|
||||
PointerInputData::Touch(Point::new(0, 0)).released().once()
|
||||
}
|
||||
},
|
||||
&display,
|
||||
);
|
||||
|
||||
// Create screen and widgets
|
||||
let mut screen = display.get_scr_act().unwrap();
|
||||
let mut screen_style = Style::default();
|
||||
screen_style.set_bg_color(Color::from_rgb((0, 0, 0)));
|
||||
screen_style.set_radius(0);
|
||||
screen.add_style(Part::Main, &mut screen_style);
|
||||
|
||||
let mut time = Label::new().unwrap();
|
||||
time.set_text(CString::new("00:10:000").unwrap().as_c_str());
|
||||
let mut style_time = Style::default();
|
||||
style_time.set_text_color(Color::from_rgb((255, 255, 255))); // white
|
||||
style_time.set_text_align(TextAlign::Center);
|
||||
unsafe { style_time.set_text_font(Font::new_raw(lvgl_sys::lv_font_montserrat_24)) };
|
||||
|
||||
// Custom font requires lvgl-sys in Cargo.toml and 'use lvgl_sys' in this file
|
||||
|
||||
time.add_style(Part::Main, &mut style_time);
|
||||
|
||||
// Time text will be centered in screen
|
||||
time.set_align(Align::Center, 0, 0);
|
||||
|
||||
// let mut cont = Obj::new().unwrap();
|
||||
// cont.set_size(320, 50);
|
||||
// let mut style = Style::default();
|
||||
// style.set_flex_flow(FlexFlow::ROW);
|
||||
// style.set_flex_main_place(FlexAlign::SPACE_EVENLY);
|
||||
// style.set_flex_cross_place(FlexAlign::CENTER);
|
||||
// // style.set_bg_opa(0);
|
||||
// style.set_border_width(0);
|
||||
// cont.add_style(Part::Any, &mut style);
|
||||
// cont.set_align(Align::Center, 0, 40);
|
||||
|
||||
let mut button_add = Btn::create(&mut screen).unwrap();
|
||||
button_add.set_align(Align::Center, -50, 32);
|
||||
// button_add.set_pos(130, 150);
|
||||
button_add.set_size(30, 30);
|
||||
// button_add.set_align(Align::Center, 0, 0);
|
||||
let mut btn_lbl1 = Label::create(&mut button_add).unwrap();
|
||||
btn_lbl1.set_text(CString::new(b"+").unwrap().as_c_str());
|
||||
|
||||
button_add.on_event(|_btn, event| {
|
||||
if let Event::Pressed = event {
|
||||
println!("pressed");
|
||||
if appdata.timer_stopped() {
|
||||
appdata.add_secs(10);
|
||||
}
|
||||
}
|
||||
// println!("Button received event: {:?}", event);
|
||||
});
|
||||
|
||||
let mut button_sub = Btn::create(&mut screen).unwrap();
|
||||
// button_sub.set_pos(170, 150);
|
||||
button_sub.set_size(30, 30);
|
||||
button_sub.set_align(Align::Center, 50, 35);
|
||||
// button_sub.set_align(Align::Center, 0, 0);
|
||||
let mut btn_lbl2 = Label::create(&mut button_sub).unwrap();
|
||||
btn_lbl2.set_text(CString::new(b"-").unwrap().as_c_str());
|
||||
|
||||
button_sub.on_event(|_btn, event| {
|
||||
if let Event::Pressed = event {
|
||||
if appdata.timer_stopped() {
|
||||
appdata.sub_secs(10);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let mut center_label = Label::new().unwrap();
|
||||
center_label.set_text(CString::new(b"+/- 10s").unwrap().as_c_str());
|
||||
center_label.set_align(Align::Center, 0, 35);
|
||||
let mut cl_style = Style::default();
|
||||
cl_style.set_text_color(Color::from_rgb((255, 255, 255)));
|
||||
center_label.add_style(Part::Main, &mut cl_style);
|
||||
|
||||
let mut button_reset = Btn::create(&mut screen).unwrap();
|
||||
//button_reset.set_pos(123, 190);
|
||||
button_reset.set_align(Align::Center, -22, 70);
|
||||
button_reset.set_size(35, 35);
|
||||
let mut btn_lbl3 = Label::create(&mut button_reset).unwrap();
|
||||
btn_lbl3.set_text(CString::new(b"\xEF\x80\xA1").unwrap().as_c_str());
|
||||
|
||||
|
||||
const PLAY: &'static [u8; 3] = b"\xEF\x81\x8B";
|
||||
const PAUSE: &'static [u8; 3] = b"\xEF\x81\x8C";
|
||||
const STOP: &'static [u8; 3] = b"\xEF\x81\x8D";
|
||||
|
||||
let mut button_start_stop = Btn::create(&mut screen).unwrap();
|
||||
// button_start_stop.set_pos(173, 190);
|
||||
button_start_stop.set_align(Align::Center, 22, 70);
|
||||
button_start_stop.set_size(35, 35);
|
||||
let mut btn_lbl4 = Label::create(&mut button_start_stop).unwrap();
|
||||
btn_lbl4.set_text(CString::new(b"\xEF\x81\x8B").unwrap().as_c_str());
|
||||
|
||||
button_reset.on_event(|_btn, event| {
|
||||
if let Event::Pressed = event {
|
||||
appdata.reset_timer();
|
||||
btn_lbl4.set_text(CString::new(PLAY).unwrap().as_c_str());
|
||||
}
|
||||
});
|
||||
|
||||
button_start_stop.on_event(|_btn, event| {
|
||||
if let Event::Pressed = event {
|
||||
if appdata.timer_finished() {
|
||||
// println!("Resetting finished timer");
|
||||
appdata.reset_timer();
|
||||
btn_lbl4.set_text(CString::new(PLAY).unwrap().as_c_str());
|
||||
} else if appdata.timer_running() {
|
||||
// println!("Pausing timer");
|
||||
appdata.pause_timer();
|
||||
btn_lbl4.set_text(CString::new(PLAY).unwrap().as_c_str());
|
||||
} else {
|
||||
// println!("Starting timer");
|
||||
appdata.start_timer();
|
||||
if appdata.timer_finished() {
|
||||
// println!("Timer already finished");
|
||||
btn_lbl4.set_text(CString::new(STOP).unwrap().as_c_str());
|
||||
} else {
|
||||
// println!("Timer running");
|
||||
btn_lbl4.set_text(CString::new(PAUSE).unwrap().as_c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
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;
|
||||
|
||||
|
||||
if !was_finished && appdata.timer_finished() {
|
||||
was_finished = true;
|
||||
btn_lbl4.set_text(CString::new(STOP).unwrap().as_c_str());
|
||||
}
|
||||
was_finished = appdata.timer_finished();
|
||||
|
||||
let start_draw_time = Instant::now();
|
||||
lvgl::task_handler();
|
||||
|
||||
// Simulate clock - so sleep for one second so time text is incremented in
|
||||
// seconds
|
||||
// delay::FreeRtos::delay_ms(1);
|
||||
|
||||
let now_time = Instant::now();
|
||||
lvgl::tick_inc(now_time.duration_since(last_time));
|
||||
last_time = now_time;
|
||||
|
||||
|
||||
let end_time = Instant::now();
|
||||
let draw_time = raw_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);
|
||||
|
||||
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, );
|
||||
}
|
||||
raw_display.reset_time();
|
||||
|
||||
delay::FreeRtos::delay_ms(2);
|
||||
}
|
||||
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
loop {
|
||||
// Don't exit application
|
||||
delay::FreeRtos::delay_ms(1_000_000);
|
||||
}
|
||||
}
|
161
lvgl-based/src/main.rs
Normal file
161
lvgl-based/src/main.rs
Normal file
@ -0,0 +1,161 @@
|
||||
use cstr_core::CString;
|
||||
|
||||
use embedded_graphics_core::draw_target::DrawTarget;
|
||||
|
||||
use std::thread;
|
||||
use std::time::Instant;
|
||||
use display_interface_spi::{SPIInterface};
|
||||
use esp_idf_hal::{
|
||||
delay::{self, Delay},
|
||||
gpio::*,
|
||||
peripherals::Peripherals,
|
||||
spi::{config::DriverConfig, Dma, SpiConfig, SpiDeviceDriver},
|
||||
units::FromValueType, // for converting 26MHz to value
|
||||
};
|
||||
|
||||
use lvgl::font::Font;
|
||||
use lvgl::style::Style;
|
||||
use lvgl::widgets::Label;
|
||||
use lvgl::{Align, Color, Display, DrawBuffer, LvError, Part, TextAlign, Widget};
|
||||
use mipidsi::Builder;
|
||||
use mipidsi::models::ILI9486Rgb565;
|
||||
use mipidsi::options::{ColorInversion, ColorOrder, Orientation, Rotation};
|
||||
|
||||
fn main() -> Result<(), LvError> {
|
||||
const HOR_RES: u32 = 320;
|
||||
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
|
||||
esp_idf_svc::sys::link_patches();
|
||||
|
||||
// Initialize lvgl
|
||||
lvgl::init();
|
||||
|
||||
|
||||
// Bind the log crate to the ESP Logging facilities
|
||||
esp_idf_svc::log::EspLogger::initialize_default();
|
||||
|
||||
log::info!("================= Starting App =======================");
|
||||
|
||||
let peripherals = Peripherals::take().unwrap();
|
||||
|
||||
// #[allow(unused)]
|
||||
let pins = peripherals.pins;
|
||||
|
||||
let sclk = pins.gpio14;
|
||||
let miso = pins.gpio12;
|
||||
let mosi = pins.gpio13;
|
||||
let cs = pins.gpio15;
|
||||
let dc = pins.gpio2;
|
||||
|
||||
let spi = SpiDeviceDriver::new_single(
|
||||
peripherals.spi2,
|
||||
sclk, // sclk
|
||||
mosi, // sdo
|
||||
Some(miso), // sdi
|
||||
Some(cs), // cs
|
||||
&DriverConfig::new().dma(Dma::Channel1(4096)),
|
||||
&SpiConfig::new().write_only(true).baudrate(10.MHz().into()),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// let rst = PinDriver::output(pins.gpio33).unwrap();
|
||||
let dc = PinDriver::output(dc).unwrap();
|
||||
let di = SPIInterface::new(spi, dc);
|
||||
|
||||
// Turn backlight on
|
||||
let mut bklt = PinDriver::output(pins.gpio21).unwrap();
|
||||
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)
|
||||
// .with_display_size(320, 240)
|
||||
// .with_color_order(ColorOrder::Bgr)
|
||||
// .with_orientation(Orientation::Portrait(false))
|
||||
// .with_invert_colors(mipidsi::ColorInversion::Inverted)
|
||||
// .init(&mut delay::Ets, Some(rst))
|
||||
// .unwrap();
|
||||
|
||||
// 0.6.0
|
||||
// let mut raw_display = Builder::ili9342c_rgb565(di)
|
||||
// .with_orientation(Orientation::Portrait(false))
|
||||
// .with_color_order(ColorOrder::Bgr)
|
||||
// .with_invert_colors(true)
|
||||
// .init(&mut Delay::new_default(), None::<PinDriver<AnyOutputPin, Output>>)
|
||||
// .unwrap();
|
||||
|
||||
let mut raw_display = Builder::new(ILI9486Rgb565, di)
|
||||
.orientation(Orientation {
|
||||
rotation: Rotation::Deg90,
|
||||
mirrored: true,
|
||||
})
|
||||
.color_order(ColorOrder::Bgr)
|
||||
.invert_colors(ColorInversion::Inverted)
|
||||
.init(&mut Delay::new_default())
|
||||
.unwrap();
|
||||
|
||||
|
||||
|
||||
// Stack size value - 20,000 for 10 lines, 40,000 for 20 lines
|
||||
let _lvgl_thread = thread::Builder::new()
|
||||
.stack_size(40_000)
|
||||
.spawn(move || {
|
||||
println!("thread started");
|
||||
|
||||
let buffer = DrawBuffer::<{ (HOR_RES * LINES) as usize }>::default();
|
||||
let display = Display::register(buffer, HOR_RES, VER_RES, |refresh| {
|
||||
raw_display.draw_iter(refresh.as_pixels()).unwrap();
|
||||
println!("rendering...");
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
// Create screen and widgets
|
||||
let mut screen = display.get_scr_act().unwrap();
|
||||
let mut screen_style = Style::default();
|
||||
screen_style.set_bg_color(Color::from_rgb((0, 0, 0)));
|
||||
screen_style.set_radius(0);
|
||||
screen.add_style(Part::Main, &mut screen_style);
|
||||
|
||||
let mut time = Label::new().unwrap();
|
||||
let mut style_time = Style::default();
|
||||
style_time.set_text_color(Color::from_rgb((255, 255, 255))); // white
|
||||
style_time.set_text_align(TextAlign::Center);
|
||||
|
||||
// Custom font requires lvgl-sys in Cargo.toml and 'use lvgl_sys' in this file
|
||||
|
||||
time.add_style(Part::Main, &mut style_time);
|
||||
|
||||
// Time text will be centered in screen
|
||||
time.set_align(Align::Center, 0, 0);
|
||||
|
||||
let mut i = 0;
|
||||
|
||||
println!("starting lvgl loop");
|
||||
loop {
|
||||
let start = Instant::now();
|
||||
if i > 59 {
|
||||
i = 0;
|
||||
}
|
||||
|
||||
let val = CString::new(format!("21:{:02}", i)).unwrap();
|
||||
time.set_text(&val).unwrap();
|
||||
i += 1;
|
||||
|
||||
lvgl::task_handler();
|
||||
|
||||
// Simulate clock - so sleep for one second so time text is incremented in seconds
|
||||
delay::FreeRtos::delay_ms(1);
|
||||
|
||||
lvgl::tick_inc(Instant::now().duration_since(start));
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
loop {
|
||||
// Don't exit application
|
||||
delay::FreeRtos::delay_ms(1000);
|
||||
}
|
||||
}
|
322
lvgl-based/tree.text
Normal file
322
lvgl-based/tree.text
Normal file
@ -0,0 +1,322 @@
|
||||
rust-m5stack-lvgl-demo v0.1.0 (/home/yannik/repos/kolibri-cyd-tester-app-embassy/lvgl-based)
|
||||
├── cstr_core v0.2.6
|
||||
│ ├── cty v0.2.2
|
||||
│ └── memchr v2.7.4
|
||||
├── display-interface-spi v0.5.0
|
||||
│ ├── byte-slice-cast v1.2.2
|
||||
│ ├── display-interface v0.5.0
|
||||
│ ├── embedded-hal v1.0.0
|
||||
│ └── embedded-hal-async v1.0.0
|
||||
│ └── embedded-hal v1.0.0
|
||||
├── embedded-graphics-core v0.4.0
|
||||
│ ├── az v1.2.1
|
||||
│ └── byteorder v1.5.0
|
||||
├── esp-idf-hal v0.44.1
|
||||
│ ├── atomic-waker v1.1.2
|
||||
│ ├── critical-section v1.2.0
|
||||
│ ├── embassy-sync v0.6.0
|
||||
│ │ ├── cfg-if v1.0.0
|
||||
│ │ ├── critical-section v1.2.0
|
||||
│ │ ├── embedded-io-async v0.6.1
|
||||
│ │ │ └── embedded-io v0.6.1
|
||||
│ │ ├── futures-util v0.3.31
|
||||
│ │ │ ├── futures-core v0.3.31
|
||||
│ │ │ ├── futures-task v0.3.31
|
||||
│ │ │ ├── pin-project-lite v0.2.15
|
||||
│ │ │ └── pin-utils v0.1.0
|
||||
│ │ └── heapless v0.8.0
|
||||
│ │ ├── hash32 v0.3.1
|
||||
│ │ │ └── byteorder v1.5.0
|
||||
│ │ └── stable_deref_trait v1.2.0
|
||||
│ ├── embedded-can v0.4.1
|
||||
│ │ └── nb v1.1.0
|
||||
│ ├── embedded-hal v0.2.7
|
||||
│ │ ├── nb v0.1.3
|
||||
│ │ │ └── nb v1.1.0
|
||||
│ │ └── void v1.0.2
|
||||
│ ├── embedded-hal v1.0.0
|
||||
│ ├── embedded-hal-async v1.0.0 (*)
|
||||
│ ├── embedded-hal-nb v1.0.0
|
||||
│ │ ├── embedded-hal v1.0.0
|
||||
│ │ └── nb v1.1.0
|
||||
│ ├── embedded-io v0.6.1
|
||||
│ ├── embedded-io-async v0.6.1 (*)
|
||||
│ ├── enumset v1.1.5
|
||||
│ │ └── enumset_derive v0.10.0 (proc-macro)
|
||||
│ │ ├── darling v0.20.10
|
||||
│ │ │ ├── darling_core v0.20.10
|
||||
│ │ │ │ ├── fnv v1.0.7
|
||||
│ │ │ │ ├── ident_case v1.0.1
|
||||
│ │ │ │ ├── proc-macro2 v1.0.89
|
||||
│ │ │ │ │ └── unicode-ident v1.0.13
|
||||
│ │ │ │ ├── quote v1.0.37
|
||||
│ │ │ │ │ └── proc-macro2 v1.0.89 (*)
|
||||
│ │ │ │ └── syn v2.0.87
|
||||
│ │ │ │ ├── proc-macro2 v1.0.89 (*)
|
||||
│ │ │ │ ├── quote v1.0.37 (*)
|
||||
│ │ │ │ └── unicode-ident v1.0.13
|
||||
│ │ │ └── darling_macro v0.20.10 (proc-macro)
|
||||
│ │ │ ├── darling_core v0.20.10 (*)
|
||||
│ │ │ ├── quote v1.0.37 (*)
|
||||
│ │ │ └── syn v2.0.87 (*)
|
||||
│ │ ├── proc-macro2 v1.0.89 (*)
|
||||
│ │ ├── quote v1.0.37 (*)
|
||||
│ │ └── syn v2.0.87 (*)
|
||||
│ ├── esp-idf-sys v0.35.0
|
||||
│ │ ├── build-time v0.1.3 (proc-macro)
|
||||
│ │ │ ├── chrono v0.4.38
|
||||
│ │ │ │ ├── iana-time-zone v0.1.61
|
||||
│ │ │ │ └── num-traits v0.2.19
|
||||
│ │ │ │ [build-dependencies]
|
||||
│ │ │ │ └── autocfg v1.4.0
|
||||
│ │ │ ├── once_cell v1.20.2
|
||||
│ │ │ ├── proc-macro2 v1.0.89 (*)
|
||||
│ │ │ ├── quote v1.0.37 (*)
|
||||
│ │ │ └── syn v2.0.87 (*)
|
||||
│ │ ├── const_format v0.2.33
|
||||
│ │ │ └── const_format_proc_macros v0.2.33 (proc-macro)
|
||||
│ │ │ ├── proc-macro2 v1.0.89 (*)
|
||||
│ │ │ ├── quote v1.0.37 (*)
|
||||
│ │ │ └── unicode-xid v0.2.6
|
||||
│ │ └── libc v0.2.162
|
||||
│ │ [build-dependencies]
|
||||
│ │ ├── anyhow v1.0.93
|
||||
│ │ ├── bindgen v0.69.5
|
||||
│ │ │ ├── bitflags v2.6.0
|
||||
│ │ │ ├── cexpr v0.6.0
|
||||
│ │ │ │ └── nom v7.1.3
|
||||
│ │ │ │ ├── memchr v2.7.4
|
||||
│ │ │ │ └── minimal-lexical v0.2.1
|
||||
│ │ │ ├── clang-sys v1.8.1
|
||||
│ │ │ │ ├── glob v0.3.1
|
||||
│ │ │ │ ├── libc v0.2.162
|
||||
│ │ │ │ └── libloading v0.8.5
|
||||
│ │ │ │ └── cfg-if v1.0.0
|
||||
│ │ │ │ [build-dependencies]
|
||||
│ │ │ │ └── glob v0.3.1
|
||||
│ │ │ ├── itertools v0.12.1
|
||||
│ │ │ │ └── either v1.13.0
|
||||
│ │ │ ├── lazy_static v1.5.0
|
||||
│ │ │ ├── lazycell v1.3.0
|
||||
│ │ │ ├── log v0.4.22
|
||||
│ │ │ ├── prettyplease v0.2.25
|
||||
│ │ │ │ ├── proc-macro2 v1.0.89 (*)
|
||||
│ │ │ │ └── syn v2.0.87 (*)
|
||||
│ │ │ ├── proc-macro2 v1.0.89 (*)
|
||||
│ │ │ ├── quote v1.0.37 (*)
|
||||
│ │ │ ├── regex v1.11.1
|
||||
│ │ │ │ ├── aho-corasick v1.1.3
|
||||
│ │ │ │ │ └── memchr v2.7.4
|
||||
│ │ │ │ ├── memchr v2.7.4
|
||||
│ │ │ │ ├── regex-automata v0.4.9
|
||||
│ │ │ │ │ ├── aho-corasick v1.1.3 (*)
|
||||
│ │ │ │ │ ├── memchr v2.7.4
|
||||
│ │ │ │ │ └── regex-syntax v0.8.5
|
||||
│ │ │ │ └── regex-syntax v0.8.5
|
||||
│ │ │ ├── rustc-hash v1.1.0
|
||||
│ │ │ ├── shlex v1.3.0
|
||||
│ │ │ ├── syn v2.0.87 (*)
|
||||
│ │ │ └── which v4.4.2
|
||||
│ │ │ ├── either v1.13.0
|
||||
│ │ │ ├── home v0.5.9
|
||||
│ │ │ └── rustix v0.38.40
|
||||
│ │ │ ├── bitflags v2.6.0
|
||||
│ │ │ └── linux-raw-sys v0.4.14
|
||||
│ │ ├── cargo_metadata v0.18.1
|
||||
│ │ │ ├── camino v1.1.9
|
||||
│ │ │ │ └── serde v1.0.215
|
||||
│ │ │ │ └── serde_derive v1.0.215 (proc-macro)
|
||||
│ │ │ │ ├── proc-macro2 v1.0.89 (*)
|
||||
│ │ │ │ ├── quote v1.0.37 (*)
|
||||
│ │ │ │ └── syn v2.0.87 (*)
|
||||
│ │ │ ├── cargo-platform v0.1.8
|
||||
│ │ │ │ └── serde v1.0.215 (*)
|
||||
│ │ │ ├── semver v1.0.23
|
||||
│ │ │ │ └── serde v1.0.215 (*)
|
||||
│ │ │ ├── serde v1.0.215 (*)
|
||||
│ │ │ ├── serde_json v1.0.132
|
||||
│ │ │ │ ├── itoa v1.0.11
|
||||
│ │ │ │ ├── memchr v2.7.4
|
||||
│ │ │ │ ├── ryu v1.0.18
|
||||
│ │ │ │ └── serde v1.0.215 (*)
|
||||
│ │ │ └── thiserror v1.0.69
|
||||
│ │ │ └── thiserror-impl v1.0.69 (proc-macro)
|
||||
│ │ │ ├── proc-macro2 v1.0.89 (*)
|
||||
│ │ │ ├── quote v1.0.37 (*)
|
||||
│ │ │ └── syn v2.0.87 (*)
|
||||
│ │ ├── embuild v0.32.0
|
||||
│ │ │ ├── anyhow v1.0.93
|
||||
│ │ │ ├── bindgen v0.69.5 (*)
|
||||
│ │ │ ├── bitflags v1.3.2
|
||||
│ │ │ ├── cmake v0.1.51
|
||||
│ │ │ │ └── cc v1.2.1
|
||||
│ │ │ │ └── shlex v1.3.0
|
||||
│ │ │ ├── filetime v0.2.25
|
||||
│ │ │ │ ├── cfg-if v1.0.0
|
||||
│ │ │ │ └── libc v0.2.162
|
||||
│ │ │ ├── globwalk v0.8.1
|
||||
│ │ │ │ ├── bitflags v1.3.2
|
||||
│ │ │ │ ├── ignore v0.4.23
|
||||
│ │ │ │ │ ├── crossbeam-deque v0.8.5
|
||||
│ │ │ │ │ │ ├── crossbeam-epoch v0.9.18
|
||||
│ │ │ │ │ │ │ └── crossbeam-utils v0.8.20
|
||||
│ │ │ │ │ │ └── crossbeam-utils v0.8.20
|
||||
│ │ │ │ │ ├── globset v0.4.15
|
||||
│ │ │ │ │ │ ├── aho-corasick v1.1.3 (*)
|
||||
│ │ │ │ │ │ ├── bstr v1.11.0
|
||||
│ │ │ │ │ │ │ └── memchr v2.7.4
|
||||
│ │ │ │ │ │ ├── log v0.4.22
|
||||
│ │ │ │ │ │ ├── regex-automata v0.4.9 (*)
|
||||
│ │ │ │ │ │ └── regex-syntax v0.8.5
|
||||
│ │ │ │ │ ├── log v0.4.22
|
||||
│ │ │ │ │ ├── memchr v2.7.4
|
||||
│ │ │ │ │ ├── regex-automata v0.4.9 (*)
|
||||
│ │ │ │ │ ├── same-file v1.0.6
|
||||
│ │ │ │ │ └── walkdir v2.5.0
|
||||
│ │ │ │ │ └── same-file v1.0.6
|
||||
│ │ │ │ └── walkdir v2.5.0 (*)
|
||||
│ │ │ ├── home v0.5.9
|
||||
│ │ │ ├── log v0.4.22
|
||||
│ │ │ ├── regex v1.11.1 (*)
|
||||
│ │ │ ├── remove_dir_all v0.8.4
|
||||
│ │ │ │ ├── cfg-if v1.0.0
|
||||
│ │ │ │ ├── cvt v0.1.2
|
||||
│ │ │ │ │ └── cfg-if v1.0.0
|
||||
│ │ │ │ ├── fs_at v0.2.1
|
||||
│ │ │ │ │ ├── cfg-if v1.0.0
|
||||
│ │ │ │ │ ├── cvt v0.1.2 (*)
|
||||
│ │ │ │ │ ├── libc v0.2.162
|
||||
│ │ │ │ │ └── nix v0.29.0
|
||||
│ │ │ │ │ ├── bitflags v2.6.0
|
||||
│ │ │ │ │ ├── cfg-if v1.0.0
|
||||
│ │ │ │ │ └── libc v0.2.162
|
||||
│ │ │ │ │ [build-dependencies]
|
||||
│ │ │ │ │ └── cfg_aliases v0.2.1
|
||||
│ │ │ │ ├── libc v0.2.162
|
||||
│ │ │ │ └── normpath v1.3.0
|
||||
│ │ │ ├── serde v1.0.215 (*)
|
||||
│ │ │ ├── serde_json v1.0.132 (*)
|
||||
│ │ │ ├── shlex v1.3.0
|
||||
│ │ │ ├── strum v0.24.1
|
||||
│ │ │ │ └── strum_macros v0.24.3 (proc-macro)
|
||||
│ │ │ │ ├── heck v0.4.1
|
||||
│ │ │ │ ├── proc-macro2 v1.0.89 (*)
|
||||
│ │ │ │ ├── quote v1.0.37 (*)
|
||||
│ │ │ │ ├── rustversion v1.0.18 (proc-macro)
|
||||
│ │ │ │ └── syn v1.0.109
|
||||
│ │ │ │ ├── proc-macro2 v1.0.89 (*)
|
||||
│ │ │ │ ├── quote v1.0.37 (*)
|
||||
│ │ │ │ └── unicode-ident v1.0.13
|
||||
│ │ │ ├── tempfile v3.14.0
|
||||
│ │ │ │ ├── cfg-if v1.0.0
|
||||
│ │ │ │ ├── fastrand v2.2.0
|
||||
│ │ │ │ ├── once_cell v1.20.2
|
||||
│ │ │ │ └── rustix v0.38.40 (*)
|
||||
│ │ │ ├── thiserror v1.0.69 (*)
|
||||
│ │ │ └── which v4.4.2 (*)
|
||||
│ │ ├── envy v0.4.2
|
||||
│ │ │ └── serde v1.0.215 (*)
|
||||
│ │ ├── regex v1.11.1 (*)
|
||||
│ │ ├── serde v1.0.215 (*)
|
||||
│ │ ├── strum v0.24.1 (*)
|
||||
│ │ └── which v4.4.2 (*)
|
||||
│ ├── heapless v0.8.0 (*)
|
||||
│ ├── log v0.4.22
|
||||
│ ├── nb v1.1.0
|
||||
│ └── num_enum v0.7.3
|
||||
│ └── num_enum_derive v0.7.3 (proc-macro)
|
||||
│ ├── proc-macro2 v1.0.89 (*)
|
||||
│ ├── quote v1.0.37 (*)
|
||||
│ └── syn v2.0.87 (*)
|
||||
│ [build-dependencies]
|
||||
│ └── embuild v0.32.0 (*)
|
||||
├── esp-idf-svc v0.49.1
|
||||
│ ├── embassy-futures v0.1.1
|
||||
│ ├── embassy-time-driver v0.1.0
|
||||
│ │ └── document-features v0.2.10 (proc-macro)
|
||||
│ │ └── litrs v0.4.1
|
||||
│ ├── embedded-hal-async v1.0.0 (*)
|
||||
│ ├── embedded-svc v0.28.0
|
||||
│ │ ├── embedded-io v0.6.1
|
||||
│ │ ├── embedded-io-async v0.6.1 (*)
|
||||
│ │ ├── enumset v1.1.5 (*)
|
||||
│ │ ├── heapless v0.8.0 (*)
|
||||
│ │ └── serde v1.0.215
|
||||
│ │ └── serde_derive v1.0.215 (proc-macro) (*)
|
||||
│ ├── enumset v1.1.5 (*)
|
||||
│ ├── esp-idf-hal v0.44.1 (*)
|
||||
│ ├── heapless v0.8.0 (*)
|
||||
│ ├── log v0.4.22
|
||||
│ ├── num_enum v0.7.3 (*)
|
||||
│ └── uncased v0.9.10
|
||||
│ [build-dependencies]
|
||||
│ └── version_check v0.9.5
|
||||
│ [build-dependencies]
|
||||
│ └── embuild v0.32.0 (*)
|
||||
├── esp-idf-sys v0.35.0 (*)
|
||||
├── log v0.4.22
|
||||
├── lvgl v0.6.2 (https://github.com/enelson1001/lv_binding_rust#723ad383)
|
||||
│ ├── bitflags v2.6.0
|
||||
│ ├── cstr_core v0.2.6 (*)
|
||||
│ ├── ctor v0.2.8 (proc-macro)
|
||||
│ │ ├── quote v1.0.37 (*)
|
||||
│ │ └── syn v2.0.87 (*)
|
||||
│ ├── cty v0.2.2
|
||||
│ ├── embedded-graphics v0.8.1
|
||||
│ │ ├── az v1.2.1
|
||||
│ │ ├── byteorder v1.5.0
|
||||
│ │ ├── embedded-graphics-core v0.4.0 (*)
|
||||
│ │ ├── float-cmp v0.9.0
|
||||
│ │ │ └── num-traits v0.2.19
|
||||
│ │ │ [build-dependencies]
|
||||
│ │ │ └── autocfg v1.4.0
|
||||
│ │ └── micromath v2.1.0
|
||||
│ ├── lvgl-sys v0.6.2 (https://github.com/enelson1001/lv_binding_rust#723ad383)
|
||||
│ │ └── cty v0.2.2
|
||||
│ │ [build-dependencies]
|
||||
│ │ ├── bindgen v0.65.1
|
||||
│ │ │ ├── bitflags v1.3.2
|
||||
│ │ │ ├── cexpr v0.6.0 (*)
|
||||
│ │ │ ├── clang-sys v1.8.1 (*)
|
||||
│ │ │ ├── lazy_static v1.5.0
|
||||
│ │ │ ├── lazycell v1.3.0
|
||||
│ │ │ ├── log v0.4.22
|
||||
│ │ │ ├── peeking_take_while v0.1.2
|
||||
│ │ │ ├── prettyplease v0.2.25 (*)
|
||||
│ │ │ ├── proc-macro2 v1.0.89 (*)
|
||||
│ │ │ ├── quote v1.0.37 (*)
|
||||
│ │ │ ├── regex v1.11.1 (*)
|
||||
│ │ │ ├── rustc-hash v1.1.0
|
||||
│ │ │ ├── shlex v1.3.0
|
||||
│ │ │ ├── syn v2.0.87 (*)
|
||||
│ │ │ └── which v4.4.2 (*)
|
||||
│ │ └── cc v1.2.1 (*)
|
||||
│ └── paste v1.0.15 (proc-macro)
|
||||
│ [build-dependencies]
|
||||
│ ├── lvgl-codegen v0.6.2 (https://github.com/enelson1001/lv_binding_rust#723ad383)
|
||||
│ │ ├── Inflector v0.11.4
|
||||
│ │ │ ├── lazy_static v1.5.0
|
||||
│ │ │ └── regex v1.11.1 (*)
|
||||
│ │ ├── lazy_static v1.5.0
|
||||
│ │ ├── proc-macro2 v1.0.89 (*)
|
||||
│ │ ├── quote v1.0.37 (*)
|
||||
│ │ ├── regex v1.11.1 (*)
|
||||
│ │ └── syn v2.0.87 (*)
|
||||
│ ├── lvgl-sys v0.6.2 (https://github.com/enelson1001/lv_binding_rust#723ad383)
|
||||
│ │ └── cty v0.2.2
|
||||
│ │ [build-dependencies]
|
||||
│ │ ├── bindgen v0.65.1 (*)
|
||||
│ │ └── cc v1.2.1 (*)
|
||||
│ ├── proc-macro2 v1.0.89 (*)
|
||||
│ └── quote v1.0.37 (*)
|
||||
├── lvgl-sys v0.6.2 (https://github.com/enelson1001/lv_binding_rust#723ad383) (*)
|
||||
├── mipidsi v0.8.0
|
||||
│ ├── display-interface v0.5.0
|
||||
│ ├── embedded-graphics-core v0.4.0 (*)
|
||||
│ ├── embedded-hal v1.0.0
|
||||
│ ├── heapless v0.8.0 (*)
|
||||
│ └── nb v1.1.0
|
||||
└── static_cell v2.1.0
|
||||
└── portable-atomic v1.9.0
|
||||
[build-dependencies]
|
||||
└── embuild v0.32.0 (*)
|
@ -14,3 +14,6 @@ imports_layout = "HorizontalVertical"
|
||||
# Miscellaneous
|
||||
enum_discrim_align_threshold = 25
|
||||
hex_literal_case = "Upper"
|
||||
|
||||
# Length
|
||||
max_width=60
|
||||
|
41
slint-based/.cargo/config.toml
Normal file
41
slint-based/.cargo/config.toml
Normal file
@ -0,0 +1,41 @@
|
||||
#
|
||||
# Cargo Configuration for the https://github.com/rp-rs/rp-hal.git repository.
|
||||
#
|
||||
# Copyright (c) The RP-RS Developers, 2021
|
||||
#
|
||||
# You might want to make a similar file in your own repository if you are
|
||||
# writing programs for Raspberry Silicon microcontrollers.
|
||||
#
|
||||
# This file is MIT or Apache-2.0 as per the repository README.md file
|
||||
#
|
||||
|
||||
# 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
|
||||
|
||||
# Target specific options
|
||||
[target.thumbv6m-none-eabi]
|
||||
# Pass some extra options to rustc, some of which get passed on to the linker.
|
||||
#
|
||||
# * linker argument --nmagic turns off page alignment of sections (which saves
|
||||
# flash space)
|
||||
# * linker argument -Tlink.x tells the linker to use link.x as the linker
|
||||
# script. This is usually provided by the cortex-m-rt crate, and by default
|
||||
# the version in that crate will include a file called `memory.x` which
|
||||
# describes the particular memory layout for your specific chip.
|
||||
# * inline-threshold=5 makes the compiler more aggressive and inlining functions
|
||||
# * no-vectorize-loops turns off the loop vectorizer (seeing as the M0+ doesn't
|
||||
# have SIMD)
|
||||
rustflags = [
|
||||
"-C", "link-arg=--nmagic",
|
||||
"-C", "link-arg=-Tlink.x",
|
||||
"-C", "llvm-args=--inline-threshold=5",
|
||||
"-C", "no-vectorize-loops",
|
||||
]
|
||||
|
||||
# This runner will make a UF2 file and then copy it to a mounted RP2040 in USB
|
||||
# Bootloader mode:
|
||||
# runner = "elf2uf2-rs -d"
|
||||
|
||||
# This runner will find a supported SWD debug probe and flash your RP2040 over
|
||||
# SWD:
|
||||
# runner = "probe-run --chip RP2040"
|
6
slint-based/.gitignore
vendored
Normal file
6
slint-based/.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
/target/
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
7
slint-based/.vscode/extensions.json
vendored
Normal file
7
slint-based/.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"rust-lang.rust-analyzer",
|
||||
"vadimcn.vscode-lldb",
|
||||
"Slint.slint"
|
||||
]
|
||||
}
|
5186
slint-based/Cargo.lock
generated
Normal file
5186
slint-based/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
70
slint-based/Cargo.toml
Normal file
70
slint-based/Cargo.toml
Normal file
@ -0,0 +1,70 @@
|
||||
[workspace]
|
||||
|
||||
[package]
|
||||
name = "slint-mcu-rust-template"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
build = "build.rs"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
# [[bin]]
|
||||
# name = "main"
|
||||
|
||||
[features]
|
||||
starter = []
|
||||
timer = []
|
||||
light-control = []
|
||||
microwave-ui = []
|
||||
simulator = ["slint/backend-winit"]
|
||||
|
||||
[[bin]]
|
||||
|
||||
name = "starter"
|
||||
|
||||
[[bin]]
|
||||
name = "timer"
|
||||
|
||||
[[bin]]
|
||||
name = "light-control"
|
||||
|
||||
[[bin]]
|
||||
name = "microwave-ui"
|
||||
|
||||
[dependencies]
|
||||
slint = { version = "1.8", default-features = false, features = ["compat-1-2", "renderer-software", "libm", "unsafe-single-threaded"] }
|
||||
|
||||
embassy-embedded-hal = "0.2.0"
|
||||
embassy-executor = { version = "0.6.0", features = ["log"] }
|
||||
embassy-sync = "0.6.0"
|
||||
embassy-time = { version = "0.3.1", features = ["generic-queue-8"] }
|
||||
|
||||
esp-hal = { version = "0.20.1", features = ["async", "esp32", "log"] }
|
||||
esp-hal-embassy = { version = "0.3.0", features = ["esp32", "log"] }
|
||||
esp-println = { version = "0.12.0", features = ["esp32", "log"] }
|
||||
|
||||
cortex-m = { version = "0.7.6" }
|
||||
cortex-m-rt = { version = "0.7.1" }
|
||||
embedded-alloc = { version = "0.6.0" }
|
||||
shared-bus = { version = "0.3.1" }
|
||||
panic-halt = { version = "1.0.0" }
|
||||
display-interface-spi = { version = "0.5.0" }
|
||||
mipidsi = "0.8.0"
|
||||
embedded-graphics-core = { version = "0.4.0" }
|
||||
embedded-hal = { version = "1.0.0" }
|
||||
fugit = { version = "0.3.6" }
|
||||
esp-alloc = "0.5.0"
|
||||
embedded-graphics-profiler-display = { version = "0.1.0", path = "../embedded-graphics-profiler-display" }
|
||||
xpt2046 = { git = "https://github.com/Yandrik/xpt2046.git", version = "0.3.1" }
|
||||
|
||||
|
||||
esp-backtrace = { version = "0.14.2", features = ["esp32", "println", "panic-handler", "exception-handler"] }
|
||||
|
||||
static_cell = { version = "2.1.0", features = ["nightly"] }
|
||||
embedded-hal-bus = "0.2.0"
|
||||
|
||||
[build-dependencies]
|
||||
slint-build = { version = "1.8" }
|
||||
|
||||
|
45
slint-based/README.md
Normal file
45
slint-based/README.md
Normal file
@ -0,0 +1,45 @@
|
||||
# Slint Bare Metal Microcontroller Rust Template
|
||||
|
||||
A template for a Rust Microcontroller(MCU) application that's using [Slint](https://slint-ui.com) for the user interface.
|
||||
|
||||
## About
|
||||
|
||||
This template helps you get started developing a bare metal MCU Rust application with Slint as toolkit for the user interface.
|
||||
It shows how to implement the `slint::platform::Platform` trait, and displays a simple `.slint` design on the screen.
|
||||
|
||||
For a template about using Slint with an operating system (Desktop, or Embedded Linux), check out the
|
||||
classic template at https://github.com/slint-ui/slint-rust-template.
|
||||
|
||||
## Usage
|
||||
|
||||
1. Download and extract the [ZIP archive of this repository](https://github.com/slint-ui/slint-mcu-rust-template/archive/refs/heads/main.zip).
|
||||
2. Rename the extracted directory and change into it:
|
||||
```
|
||||
mv slint-mcu-rust-template-main my-project
|
||||
cd my-project
|
||||
```
|
||||
3. Run on the Desktop (Simulator)
|
||||
```
|
||||
cargo run --features simulator
|
||||
```
|
||||
4. If you have a [RaspberryPi Pico](https://www.raspberrypi.com/products/raspberry-pi-pico/) with a [2.8 inch Waveshare Touch Screen](https://www.waveshare.com/pico-restouch-lcd-2.8.htm):
|
||||
|
||||
a. Install the cargo extension to create UF2 images for the RP2040 USB Bootloader
|
||||
```
|
||||
cargo install elf2uf2-rs --locked
|
||||
```
|
||||
|
||||
b. Run on the device
|
||||
```
|
||||
cargo run --target=thumbv6m-none-eabi --features=pico --release
|
||||
```
|
||||
|
||||
In order to port to your device, you will have to replace all the code that is specific to the RaspberryPi Pico.
|
||||
See also the instructions on https://slint-ui.com/snapshots/master/docs/rust/slint/docs/mcu/index.html
|
||||
|
||||
## Next Steps
|
||||
|
||||
We hope that this template helps you get started and you enjoy exploring making user interfaces with Slint. To learn more
|
||||
about the Slint APIs and the `.slint` markup language check out our [online documentation](https://slint-ui.com/docs/rust/slint/).
|
||||
|
||||
Don't forget to edit this readme to replace it by yours, and edit the `name =` field in `Cargo.toml` to match the name of your project.
|
30
slint-based/build.rs
Normal file
30
slint-based/build.rs
Normal file
@ -0,0 +1,30 @@
|
||||
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()
|
||||
.embed_resources(slint_build::EmbedResourcesKind::EmbedForSoftwareRenderer),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
BIN
slint-based/img/pause.png
Normal file
BIN
slint-based/img/pause.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 373 B |
BIN
slint-based/img/play.png
Normal file
BIN
slint-based/img/play.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 401 B |
BIN
slint-based/img/restart.png
Normal file
BIN
slint-based/img/restart.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
BIN
slint-based/img/xmark-square.png
Normal file
BIN
slint-based/img/xmark-square.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 542 B |
2
slint-based/rust-toolchain.toml
Normal file
2
slint-based/rust-toolchain.toml
Normal file
@ -0,0 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "esp"
|
2
slint-based/rustfmt.toml
Normal file
2
slint-based/rustfmt.toml
Normal file
@ -0,0 +1,2 @@
|
||||
use_small_heuristics = "Max"
|
||||
max_width = 60
|
432
slint-based/src/bin/light-control.rs
Normal file
432
slint-based/src/bin/light-control.rs
Normal file
@ -0,0 +1,432 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use alloc::rc::Rc;
|
||||
use core::mem::MaybeUninit;
|
||||
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::Delay;
|
||||
use embassy_time::{Duration, Instant, Timer};
|
||||
use embedded_graphics_core::pixelcolor::Rgb565;
|
||||
use embedded_graphics_core::prelude::*;
|
||||
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},
|
||||
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,
|
||||
};
|
||||
use slint::platform::software_renderer::MinimalSoftwareWindow;
|
||||
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!();
|
||||
# */
|
||||
|
||||
slint::include_modules!();
|
||||
|
||||
fn init_heap() {
|
||||
const HEAP_SIZE: usize = 64 * 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: ExclusiveDevice<
|
||||
Spi<'static, SPI3, FullDuplexMode>,
|
||||
Output<'static, GpioPin<33>>,
|
||||
&'static mut Delay,
|
||||
>,
|
||||
touch_signal: &'static Signal<
|
||||
NoopRawMutex,
|
||||
Option<Point>,
|
||||
>,
|
||||
) -> ! {
|
||||
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");
|
||||
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 point_to_logical_pos(point: Point) -> LogicalPosition {
|
||||
LogicalPosition::new(point.x as f32, point.y as f32)
|
||||
}
|
||||
|
||||
struct CYDPlatform {
|
||||
window: Rc<slint::platform::software_renderer::MinimalSoftwareWindow>,
|
||||
}
|
||||
|
||||
impl Platform for CYDPlatform {
|
||||
fn create_window_adapter(
|
||||
&self,
|
||||
) -> 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()
|
||||
}
|
||||
|
||||
//noinspection DuplicatedCode
|
||||
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();
|
||||
|
||||
let mut rtc = Rtc::new(peripherals.LPWR);
|
||||
rtc.rwdt.disable();
|
||||
let mut timer_group0 =
|
||||
TimerGroup::new(peripherals.TIMG0, &clocks);
|
||||
timer_group0.wdt.disable();
|
||||
let mut timer_group1 =
|
||||
TimerGroup::new(peripherals.TIMG1, &clocks);
|
||||
timer_group1.wdt.disable();
|
||||
|
||||
esp_hal_embassy::init(&clocks, timer_group0.timer0);
|
||||
|
||||
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
|
||||
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_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_signal = Signal::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;
|
||||
|
||||
// static EXECUTOR: StaticCell<InterruptExecutor<2>> = StaticCell::new();
|
||||
// let executor = InterruptExecutor::<2>::new(sw_int);
|
||||
// let executor = EXECUTOR.init(executor);
|
||||
|
||||
spawner
|
||||
.spawn(touch_task(
|
||||
touch_irq,
|
||||
touch_spi,
|
||||
touch_signal,
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
// executor.start(Priority::Priority1);
|
||||
|
||||
// Display setup
|
||||
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);
|
||||
|
||||
let mut spi = Spi::new(
|
||||
peripherals.SPI2,
|
||||
10u32.MHz(),
|
||||
SpiMode::Mode0,
|
||||
&clocks,
|
||||
)
|
||||
.with_pins(
|
||||
Some(sclk),
|
||||
Some(mosi),
|
||||
Some(miso),
|
||||
esp_hal::gpio::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);
|
||||
|
||||
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 di =
|
||||
SPIInterface::new(spi, 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);
|
||||
|
||||
backlight.set_high();
|
||||
|
||||
let size = display.bounding_box().size;
|
||||
// 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 ui = create_slint_app();
|
||||
|
||||
window.set_size(slint::PhysicalSize::new(320, 240));
|
||||
|
||||
let mut buffer_provider = DrawBuffer {
|
||||
display,
|
||||
buffer: &mut [slint::platform::software_renderer::Rgb565Pixel(0); 320],
|
||||
};
|
||||
|
||||
let mut last_touch = None;
|
||||
|
||||
loop {
|
||||
let start_time = Instant::now();
|
||||
if let Some(touch) = touch_signal.try_take() {
|
||||
// println!("touch: {:?}, last_touch: {:?}", touch, last_touch);
|
||||
let button = PointerEventButton::Left;
|
||||
let interact = match (touch, last_touch) {
|
||||
(Some(point), Some(_)) => {
|
||||
Some(WindowEvent::PointerMoved {
|
||||
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,
|
||||
),
|
||||
button,
|
||||
})
|
||||
}
|
||||
(None, None) => None,
|
||||
};
|
||||
if let Some(event) = interact {
|
||||
// println!("event: {:?}", event);
|
||||
window.dispatch_event(event);
|
||||
}
|
||||
|
||||
last_touch = touch;
|
||||
}
|
||||
|
||||
slint::platform::update_timers_and_animations();
|
||||
|
||||
// let window = window.clone();
|
||||
let start_draw_time = Instant::now();
|
||||
window.draw_if_needed(|renderer| {
|
||||
renderer.render_by_line(&mut buffer_provider);
|
||||
});
|
||||
|
||||
if window.has_active_animations() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let display = &mut buffer_provider.display;
|
||||
|
||||
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(1)).await; // 60 a second
|
||||
}
|
||||
}
|
||||
|
||||
fn create_slint_app() -> LightsApp {
|
||||
let ui = LightsApp::new().unwrap();
|
||||
ui
|
||||
}
|
||||
|
||||
struct DrawBuffer<'a, DT> {
|
||||
display: DT,
|
||||
buffer: &'a mut [slint::platform::software_renderer::Rgb565Pixel],
|
||||
}
|
||||
|
||||
impl<
|
||||
// DI: display_interface_spi::WriteOnlyDataCommand,
|
||||
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>
|
||||
{
|
||||
type TargetPixel =
|
||||
slint::platform::software_renderer::Rgb565Pixel;
|
||||
|
||||
fn process_line(
|
||||
&mut self,
|
||||
line: usize,
|
||||
range: core::ops::Range<usize>,
|
||||
render_fn: impl FnOnce(&mut [slint::platform::software_renderer::Rgb565Pixel]),
|
||||
) {
|
||||
let buffer = &mut self.buffer[range.clone()];
|
||||
|
||||
render_fn(buffer);
|
||||
|
||||
// We send empty data just to get the device in the right window
|
||||
self.display
|
||||
.fill_contiguous(
|
||||
&Rectangle::new(
|
||||
Point::new(range.start as i32, line as i32),
|
||||
Size::new((range.end - range.start) as u32, 1),
|
||||
),
|
||||
// range.start as u16,
|
||||
// line as _,
|
||||
// range.end as u16,
|
||||
// line as u16,
|
||||
buffer
|
||||
.iter()
|
||||
.map(|x| embedded_graphics_core::pixelcolor::raw::RawU16::new(x.0).into()),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
583
slint-based/src/bin/microwave-ui.rs
Normal file
583
slint-based/src/bin/microwave-ui.rs
Normal file
@ -0,0 +1,583 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use alloc::rc::Rc;
|
||||
use core::mem::MaybeUninit;
|
||||
use core::{cell::RefCell, cmp::min};
|
||||
use display_interface_spi::SPIInterface;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||
use embassy_sync::signal::Signal;
|
||||
use embassy_time::Delay;
|
||||
use embassy_time::{Duration, Instant, Timer};
|
||||
use embedded_graphics_core::pixelcolor::Rgb565;
|
||||
use embedded_graphics_core::prelude::*;
|
||||
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_hal::{self, prelude::*};
|
||||
use esp_hal::{
|
||||
clock::ClockControl,
|
||||
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_println::println;
|
||||
use mipidsi::{
|
||||
options::{ColorOrder, Orientation, Rotation},
|
||||
Builder,
|
||||
};
|
||||
use slint::platform::software_renderer::MinimalSoftwareWindow;
|
||||
use slint::platform::{
|
||||
Platform, PointerEventButton, WindowEvent,
|
||||
};
|
||||
use slint::{format, LogicalPosition};
|
||||
use static_cell::StaticCell;
|
||||
use xpt2046::Xpt2046;
|
||||
|
||||
use mipidsi::models::ILI9341Rgb565;
|
||||
// slint::slint!{ export MyUI := Window {} }
|
||||
/*
|
||||
slint::include_modules!();
|
||||
# */
|
||||
|
||||
slint::include_modules!();
|
||||
|
||||
fn init_heap() {
|
||||
const HEAP_SIZE: usize = 64 * 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: ExclusiveDevice<
|
||||
Spi<'static, SPI3, FullDuplexMode>,
|
||||
Output<'static, GpioPin<33>>,
|
||||
&'static mut Delay,
|
||||
>,
|
||||
touch_signal: &'static Signal<
|
||||
CriticalSectionRawMutex,
|
||||
Option<Point>,
|
||||
>,
|
||||
) -> ! {
|
||||
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");
|
||||
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 point_to_logical_pos(point: Point) -> LogicalPosition {
|
||||
LogicalPosition::new(point.x as f32, point.y as f32)
|
||||
}
|
||||
|
||||
struct CYDPlatform {
|
||||
window: Rc<slint::platform::software_renderer::MinimalSoftwareWindow>,
|
||||
}
|
||||
|
||||
impl Platform for CYDPlatform {
|
||||
fn create_window_adapter(
|
||||
&self,
|
||||
) -> 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()
|
||||
}
|
||||
|
||||
//noinspection DuplicatedCode
|
||||
fn run_event_loop(
|
||||
&self,
|
||||
) -> Result<(), slint::PlatformError> {
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
init_heap();
|
||||
let peripherals = Peripherals::take();
|
||||
let system = SystemControl::new(peripherals.SYSTEM);
|
||||
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);
|
||||
timer_group0.wdt.disable();
|
||||
let mut timer_group1 =
|
||||
TimerGroup::new(peripherals.TIMG1, &clocks);
|
||||
timer_group1.wdt.disable();
|
||||
|
||||
esp_hal_embassy::init(&clocks, timer_group0.timer0);
|
||||
|
||||
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
|
||||
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_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_signal = Signal::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;
|
||||
|
||||
// static EXECUTOR: StaticCell<InterruptExecutor<2>> = StaticCell::new();
|
||||
// let executor = InterruptExecutor::<2>::new(sw_int);
|
||||
// let executor = EXECUTOR.init(executor);
|
||||
|
||||
// static EXECUTOR: StaticCell<InterruptExecutor<2>> = StaticCell::new();
|
||||
// let executor =
|
||||
// InterruptExecutor::<2>::new(system.software_interrupt_control.software_interrupt2);
|
||||
// let mut executor = EXECUTOR.init(executor);
|
||||
|
||||
// executor
|
||||
// .start(Priority::Priority2)
|
||||
spawner
|
||||
.spawn(touch_task(
|
||||
touch_irq,
|
||||
touch_spi,
|
||||
touch_signal,
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
// Display setup
|
||||
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);
|
||||
|
||||
let mut spi = Spi::new(
|
||||
peripherals.SPI2,
|
||||
10u32.MHz(),
|
||||
SpiMode::Mode0,
|
||||
&clocks,
|
||||
)
|
||||
.with_pins(
|
||||
Some(sclk),
|
||||
Some(mosi),
|
||||
Some(miso),
|
||||
esp_hal::gpio::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);
|
||||
|
||||
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 di =
|
||||
SPIInterface::new(spi, 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);
|
||||
|
||||
backlight.set_high();
|
||||
|
||||
let size = display.bounding_box().size;
|
||||
// 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 ui = create_slint_app();
|
||||
|
||||
window.set_size(slint::PhysicalSize::new(320, 240));
|
||||
|
||||
let mut buffer_provider = DrawBuffer {
|
||||
display,
|
||||
buffer: &mut [slint::platform::software_renderer::Rgb565Pixel(0); 320],
|
||||
};
|
||||
|
||||
let mut last_touch = None;
|
||||
|
||||
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)
|
||||
});
|
||||
let mut cl_appdata = appdata.clone();
|
||||
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()
|
||||
});
|
||||
let mut cl_appdata = appdata.clone();
|
||||
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()
|
||||
});
|
||||
|
||||
loop {
|
||||
let start_time = Instant::now();
|
||||
if let Some(touch) = touch_signal.try_take() {
|
||||
// println!("touch: {:?}, last_touch: {:?}", touch, last_touch);
|
||||
let button = PointerEventButton::Left;
|
||||
let interact = match (touch, last_touch) {
|
||||
(Some(point), Some(_)) => {
|
||||
Some(WindowEvent::PointerMoved {
|
||||
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,
|
||||
),
|
||||
button,
|
||||
})
|
||||
}
|
||||
(None, None) => None,
|
||||
};
|
||||
if let Some(event) = interact {
|
||||
// println!("event: {:?}", event);
|
||||
window.dispatch_event(event);
|
||||
}
|
||||
|
||||
last_touch = touch;
|
||||
}
|
||||
|
||||
{
|
||||
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_stop_timer(
|
||||
appdata.timer_running()
|
||||
&& !appdata.timer_finished(),
|
||||
);
|
||||
|
||||
ui.set_timer_text(format!(
|
||||
"{:02}:{:02}:{:03}",
|
||||
remaining.as_secs() / 60,
|
||||
remaining.as_secs() % 60,
|
||||
remaining.as_millis() % 1000
|
||||
));
|
||||
}
|
||||
|
||||
slint::platform::update_timers_and_animations();
|
||||
|
||||
// let window = window.clone();
|
||||
let start_draw_time = Instant::now();
|
||||
window.draw_if_needed(|renderer| {
|
||||
// println!("dirty reg: {:?}", renderer.render_by_line(&mut buffer_provider));
|
||||
renderer.render_by_line(&mut buffer_provider);
|
||||
});
|
||||
|
||||
if window.has_active_animations() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let display = &mut buffer_provider.display;
|
||||
|
||||
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(1)).await; // 60 a second
|
||||
}
|
||||
}
|
||||
|
||||
fn create_slint_app() -> MicrowaveUI {
|
||||
let ui = MicrowaveUI::new().unwrap();
|
||||
|
||||
/*
|
||||
let ui_handle = ui.as_weak();
|
||||
ui.on_request_increase_value(move || {
|
||||
let ui = ui_handle.unwrap();
|
||||
ui.set_counter(ui.get_counter() + 1);
|
||||
});
|
||||
*/
|
||||
|
||||
ui
|
||||
}
|
||||
|
||||
struct DrawBuffer<'a, DT> {
|
||||
display: DT,
|
||||
buffer: &'a mut [slint::platform::software_renderer::Rgb565Pixel],
|
||||
}
|
||||
|
||||
impl<
|
||||
// DI: display_interface_spi::WriteOnlyDataCommand,
|
||||
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>
|
||||
{
|
||||
type TargetPixel =
|
||||
slint::platform::software_renderer::Rgb565Pixel;
|
||||
|
||||
fn process_line(
|
||||
&mut self,
|
||||
line: usize,
|
||||
range: core::ops::Range<usize>,
|
||||
render_fn: impl FnOnce(&mut [slint::platform::software_renderer::Rgb565Pixel]),
|
||||
) {
|
||||
let buffer = &mut self.buffer[range.clone()];
|
||||
|
||||
render_fn(buffer);
|
||||
|
||||
// We send empty data just to get the device in the right window
|
||||
self.display
|
||||
.fill_contiguous(
|
||||
&Rectangle::new(
|
||||
Point::new(range.start as i32, line as i32),
|
||||
Size::new((range.end - range.start) as u32, 1),
|
||||
),
|
||||
// range.start as u16,
|
||||
// line as _,
|
||||
// range.end as u16,
|
||||
// line as u16,
|
||||
buffer
|
||||
.iter()
|
||||
.map(|x| embedded_graphics_core::pixelcolor::raw::RawU16::new(x.0).into()),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
450
slint-based/src/bin/starter.rs
Normal file
450
slint-based/src/bin/starter.rs
Normal file
@ -0,0 +1,450 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use alloc::rc::Rc;
|
||||
use core::mem::MaybeUninit;
|
||||
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::Delay;
|
||||
use embassy_time::{Duration, Instant, Timer};
|
||||
use embedded_graphics_core::pixelcolor::Rgb565;
|
||||
use embedded_graphics_core::prelude::*;
|
||||
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},
|
||||
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,
|
||||
};
|
||||
use panic_halt as _;
|
||||
use slint::platform::software_renderer::MinimalSoftwareWindow;
|
||||
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 _;
|
||||
|
||||
// slint::slint!{ export MyUI := Window {} }
|
||||
/*
|
||||
slint::include_modules!();
|
||||
# */
|
||||
|
||||
slint::include_modules!();
|
||||
|
||||
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: ExclusiveDevice<
|
||||
Spi<'static, SPI3, FullDuplexMode>,
|
||||
Output<'static, GpioPin<33>>,
|
||||
&'static mut Delay,
|
||||
>,
|
||||
touch_signal: &'static Signal<NoopRawMutex, Option<Point>>,
|
||||
) -> ! {
|
||||
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");
|
||||
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 point_to_logical_pos(point: Point) -> LogicalPosition {
|
||||
LogicalPosition::new(point.x as f32, point.y as f32)
|
||||
}
|
||||
|
||||
struct CYDPlatform {
|
||||
window: Rc<slint::platform::software_renderer::MinimalSoftwareWindow>,
|
||||
}
|
||||
|
||||
impl Platform for CYDPlatform {
|
||||
fn create_window_adapter(
|
||||
&self,
|
||||
) -> 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()
|
||||
}
|
||||
|
||||
//noinspection DuplicatedCode
|
||||
fn run_event_loop(&self) -> Result<(), slint::PlatformError> {
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
init_heap();
|
||||
let peripherals = Peripherals::take();
|
||||
let system = SystemControl::new(peripherals.SYSTEM);
|
||||
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);
|
||||
timer_group0.wdt.disable();
|
||||
let mut timer_group1 = TimerGroup::new(peripherals.TIMG1, &clocks);
|
||||
timer_group1.wdt.disable();
|
||||
|
||||
esp_hal_embassy::init(&clocks, timer_group0.timer0);
|
||||
|
||||
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
|
||||
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_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_signal = Signal::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;
|
||||
|
||||
// static EXECUTOR: StaticCell<InterruptExecutor<2>> = StaticCell::new();
|
||||
// let executor = InterruptExecutor::<2>::new(sw_int);
|
||||
// let executor = EXECUTOR.init(executor);
|
||||
|
||||
spawner.spawn(touch_task(touch_irq, touch_spi, touch_signal)).unwrap();
|
||||
|
||||
// executor.start(Priority::Priority1);
|
||||
|
||||
// Display setup
|
||||
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);
|
||||
|
||||
let mut spi = Spi::new(peripherals.SPI2, 10u32.MHz(), SpiMode::Mode0, &clocks).with_pins(
|
||||
Some(sclk),
|
||||
Some(mosi),
|
||||
Some(miso),
|
||||
esp_hal::gpio::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);
|
||||
|
||||
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 di = SPIInterface::new(spi, 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);
|
||||
|
||||
backlight.set_high();
|
||||
|
||||
let size = display.bounding_box().size;
|
||||
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 ui = create_slint_app();
|
||||
|
||||
window.set_size(slint::PhysicalSize::new(320, 240));
|
||||
|
||||
let mut buffer_provider = DrawBuffer {
|
||||
display,
|
||||
buffer: &mut [slint::platform::software_renderer::Rgb565Pixel(0); 320],
|
||||
};
|
||||
|
||||
let mut last_touch = None;
|
||||
|
||||
loop {
|
||||
let start_time = Instant::now();
|
||||
if let Some(touch) = touch_signal.try_take() {
|
||||
// println!("touch: {:?}, last_touch: {:?}", touch, last_touch);
|
||||
let button = PointerEventButton::Left;
|
||||
let interact = match (touch, last_touch) {
|
||||
(Some(point), Some(_)) => {
|
||||
Some(WindowEvent::PointerMoved { 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),
|
||||
button,
|
||||
}),
|
||||
(None, None) => None,
|
||||
};
|
||||
if let Some(event) = interact {
|
||||
// println!("event: {:?}", event);
|
||||
window.dispatch_event(event);
|
||||
}
|
||||
|
||||
last_touch = touch;
|
||||
}
|
||||
|
||||
slint::platform::update_timers_and_animations();
|
||||
|
||||
// let window = window.clone();
|
||||
let start_draw_time = Instant::now();
|
||||
window.draw_if_needed(|renderer| {
|
||||
renderer.render_by_line(&mut buffer_provider);
|
||||
});
|
||||
|
||||
let button = PointerEventButton::Left;
|
||||
|
||||
if window.has_active_animations() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let display = &mut buffer_provider.display;
|
||||
|
||||
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(1)).await; // 60 a second
|
||||
}
|
||||
}
|
||||
|
||||
fn create_slint_app() -> AppWindow {
|
||||
let ui = AppWindow::new().unwrap();
|
||||
|
||||
let ui_handle = ui.as_weak();
|
||||
ui.on_request_increase_value(move || {
|
||||
let ui = ui_handle.unwrap();
|
||||
ui.set_counter(ui.get_counter() + 1);
|
||||
});
|
||||
|
||||
ui
|
||||
}
|
||||
|
||||
struct DrawBuffer<'a, DT> {
|
||||
display: DT,
|
||||
buffer: &'a mut [slint::platform::software_renderer::Rgb565Pixel],
|
||||
}
|
||||
|
||||
impl<
|
||||
// DI: display_interface_spi::WriteOnlyDataCommand,
|
||||
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>
|
||||
{
|
||||
type TargetPixel = slint::platform::software_renderer::Rgb565Pixel;
|
||||
|
||||
fn process_line(
|
||||
&mut self,
|
||||
line: usize,
|
||||
range: core::ops::Range<usize>,
|
||||
render_fn: impl FnOnce(&mut [slint::platform::software_renderer::Rgb565Pixel]),
|
||||
) {
|
||||
let buffer = &mut self.buffer[range.clone()];
|
||||
|
||||
render_fn(buffer);
|
||||
|
||||
// We send empty data just to get the device in the right window
|
||||
self.display
|
||||
.fill_contiguous(
|
||||
&Rectangle::new(
|
||||
Point::new(range.start as i32, line as i32),
|
||||
Size::new((range.end - range.start) as u32, 1),
|
||||
),
|
||||
// range.start as u16,
|
||||
// line as _,
|
||||
// range.end as u16,
|
||||
// line as u16,
|
||||
buffer
|
||||
.iter()
|
||||
.map(|x| embedded_graphics_core::pixelcolor::raw::RawU16::new(x.0).into()),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
583
slint-based/src/bin/timer.rs
Normal file
583
slint-based/src/bin/timer.rs
Normal file
@ -0,0 +1,583 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use alloc::rc::Rc;
|
||||
use core::mem::MaybeUninit;
|
||||
use core::{cell::RefCell, cmp::min};
|
||||
use display_interface_spi::SPIInterface;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||
use embassy_sync::signal::Signal;
|
||||
use embassy_time::Delay;
|
||||
use embassy_time::{Duration, Instant, Timer};
|
||||
use embedded_graphics_core::pixelcolor::Rgb565;
|
||||
use embedded_graphics_core::prelude::*;
|
||||
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_hal::{self, prelude::*};
|
||||
use esp_hal::{
|
||||
clock::ClockControl,
|
||||
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_println::println;
|
||||
use mipidsi::{
|
||||
options::{ColorOrder, Orientation, Rotation},
|
||||
Builder,
|
||||
};
|
||||
use slint::platform::software_renderer::MinimalSoftwareWindow;
|
||||
use slint::platform::{
|
||||
Platform, PointerEventButton, WindowEvent,
|
||||
};
|
||||
use slint::{format, LogicalPosition};
|
||||
use static_cell::StaticCell;
|
||||
use xpt2046::Xpt2046;
|
||||
|
||||
use mipidsi::models::ILI9341Rgb565;
|
||||
// slint::slint!{ export MyUI := Window {} }
|
||||
/*
|
||||
slint::include_modules!();
|
||||
# */
|
||||
|
||||
slint::include_modules!();
|
||||
|
||||
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: ExclusiveDevice<
|
||||
Spi<'static, SPI3, FullDuplexMode>,
|
||||
Output<'static, GpioPin<33>>,
|
||||
&'static mut Delay,
|
||||
>,
|
||||
touch_signal: &'static Signal<
|
||||
CriticalSectionRawMutex,
|
||||
Option<Point>,
|
||||
>,
|
||||
) -> ! {
|
||||
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");
|
||||
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 point_to_logical_pos(point: Point) -> LogicalPosition {
|
||||
LogicalPosition::new(point.x as f32, point.y as f32)
|
||||
}
|
||||
|
||||
struct CYDPlatform {
|
||||
window: Rc<slint::platform::software_renderer::MinimalSoftwareWindow>,
|
||||
}
|
||||
|
||||
impl Platform for CYDPlatform {
|
||||
fn create_window_adapter(
|
||||
&self,
|
||||
) -> 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()
|
||||
}
|
||||
|
||||
//noinspection DuplicatedCode
|
||||
fn run_event_loop(
|
||||
&self,
|
||||
) -> Result<(), slint::PlatformError> {
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
init_heap();
|
||||
let peripherals = Peripherals::take();
|
||||
let system = SystemControl::new(peripherals.SYSTEM);
|
||||
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);
|
||||
timer_group0.wdt.disable();
|
||||
let mut timer_group1 =
|
||||
TimerGroup::new(peripherals.TIMG1, &clocks);
|
||||
timer_group1.wdt.disable();
|
||||
|
||||
esp_hal_embassy::init(&clocks, timer_group0.timer0);
|
||||
|
||||
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
|
||||
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_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_signal = Signal::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;
|
||||
|
||||
// static EXECUTOR: StaticCell<InterruptExecutor<2>> = StaticCell::new();
|
||||
// let executor = InterruptExecutor::<2>::new(sw_int);
|
||||
// let executor = EXECUTOR.init(executor);
|
||||
|
||||
// static EXECUTOR: StaticCell<InterruptExecutor<2>> = StaticCell::new();
|
||||
// let executor =
|
||||
// InterruptExecutor::<2>::new(system.software_interrupt_control.software_interrupt2);
|
||||
// let mut executor = EXECUTOR.init(executor);
|
||||
|
||||
// executor
|
||||
// .start(Priority::Priority2)
|
||||
spawner
|
||||
.spawn(touch_task(
|
||||
touch_irq,
|
||||
touch_spi,
|
||||
touch_signal,
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
// Display setup
|
||||
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);
|
||||
|
||||
let mut spi = Spi::new(
|
||||
peripherals.SPI2,
|
||||
10u32.MHz(),
|
||||
SpiMode::Mode0,
|
||||
&clocks,
|
||||
)
|
||||
.with_pins(
|
||||
Some(sclk),
|
||||
Some(mosi),
|
||||
Some(miso),
|
||||
esp_hal::gpio::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);
|
||||
|
||||
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 di =
|
||||
SPIInterface::new(spi, 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);
|
||||
|
||||
backlight.set_high();
|
||||
|
||||
let size = display.bounding_box().size;
|
||||
// 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 ui = create_slint_app();
|
||||
|
||||
window.set_size(slint::PhysicalSize::new(320, 240));
|
||||
|
||||
let mut buffer_provider = DrawBuffer {
|
||||
display,
|
||||
buffer: &mut [slint::platform::software_renderer::Rgb565Pixel(0); 320],
|
||||
};
|
||||
|
||||
let mut last_touch = None;
|
||||
|
||||
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)
|
||||
});
|
||||
let mut cl_appdata = appdata.clone();
|
||||
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()
|
||||
});
|
||||
let mut cl_appdata = appdata.clone();
|
||||
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()
|
||||
});
|
||||
|
||||
loop {
|
||||
let start_time = Instant::now();
|
||||
if let Some(touch) = touch_signal.try_take() {
|
||||
// println!("touch: {:?}, last_touch: {:?}", touch, last_touch);
|
||||
let button = PointerEventButton::Left;
|
||||
let interact = match (touch, last_touch) {
|
||||
(Some(point), Some(_)) => {
|
||||
Some(WindowEvent::PointerMoved {
|
||||
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,
|
||||
),
|
||||
button,
|
||||
})
|
||||
}
|
||||
(None, None) => None,
|
||||
};
|
||||
if let Some(event) = interact {
|
||||
// println!("event: {:?}", event);
|
||||
window.dispatch_event(event);
|
||||
}
|
||||
|
||||
last_touch = touch;
|
||||
}
|
||||
|
||||
{
|
||||
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_stop_timer(
|
||||
appdata.timer_running()
|
||||
&& !appdata.timer_finished(),
|
||||
);
|
||||
|
||||
ui.set_timer_text(format!(
|
||||
"{:02}:{:02}:{:03}",
|
||||
remaining.as_secs() / 60,
|
||||
remaining.as_secs() % 60,
|
||||
remaining.as_millis() % 1000
|
||||
));
|
||||
}
|
||||
|
||||
slint::platform::update_timers_and_animations();
|
||||
|
||||
// let window = window.clone();
|
||||
let start_draw_time = Instant::now();
|
||||
window.draw_if_needed(|renderer| {
|
||||
// println!("dirty reg: {:?}", renderer.render_by_line(&mut buffer_provider));
|
||||
renderer.render_by_line(&mut buffer_provider);
|
||||
});
|
||||
|
||||
if window.has_active_animations() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let display = &mut buffer_provider.display;
|
||||
|
||||
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(1)).await; // 60 a second
|
||||
}
|
||||
}
|
||||
|
||||
fn create_slint_app() -> TimerApp {
|
||||
let ui = TimerApp::new().unwrap();
|
||||
|
||||
/*
|
||||
let ui_handle = ui.as_weak();
|
||||
ui.on_request_increase_value(move || {
|
||||
let ui = ui_handle.unwrap();
|
||||
ui.set_counter(ui.get_counter() + 1);
|
||||
});
|
||||
*/
|
||||
|
||||
ui
|
||||
}
|
||||
|
||||
struct DrawBuffer<'a, DT> {
|
||||
display: DT,
|
||||
buffer: &'a mut [slint::platform::software_renderer::Rgb565Pixel],
|
||||
}
|
||||
|
||||
impl<
|
||||
// DI: display_interface_spi::WriteOnlyDataCommand,
|
||||
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>
|
||||
{
|
||||
type TargetPixel =
|
||||
slint::platform::software_renderer::Rgb565Pixel;
|
||||
|
||||
fn process_line(
|
||||
&mut self,
|
||||
line: usize,
|
||||
range: core::ops::Range<usize>,
|
||||
render_fn: impl FnOnce(&mut [slint::platform::software_renderer::Rgb565Pixel]),
|
||||
) {
|
||||
let buffer = &mut self.buffer[range.clone()];
|
||||
|
||||
render_fn(buffer);
|
||||
|
||||
// We send empty data just to get the device in the right window
|
||||
self.display
|
||||
.fill_contiguous(
|
||||
&Rectangle::new(
|
||||
Point::new(range.start as i32, line as i32),
|
||||
Size::new((range.end - range.start) as u32, 1),
|
||||
),
|
||||
// range.start as u16,
|
||||
// line as _,
|
||||
// range.end as u16,
|
||||
// line as u16,
|
||||
buffer
|
||||
.iter()
|
||||
.map(|x| embedded_graphics_core::pixelcolor::raw::RawU16::new(x.0).into()),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
260
slint-based/src/cyd.rs
Normal file
260
slint-based/src/cyd.rs
Normal file
@ -0,0 +1,260 @@
|
||||
use alloc::boxed::Box;
|
||||
use alloc::rc::Rc;
|
||||
use core::cell::RefCell;
|
||||
use core::mem::MaybeUninit;
|
||||
use display_interface_spi::SPIInterface;
|
||||
use embassy_sync::blocking_mutex::raw::NoopRawMutex;
|
||||
use embassy_sync::signal::Signal;
|
||||
use embassy_time::{Duration, Timer};
|
||||
use embedded_graphics_core::geometry::{OriginDimensions, Point};
|
||||
use embedded_graphics_profiler_display::ProfilerDisplay;
|
||||
use embedded_hal::digital::OutputPin;
|
||||
use embedded_hal_bus::spi::ExclusiveDevice;
|
||||
use esp_hal::clock::ClockControl;
|
||||
use esp_hal::delay::Delay;
|
||||
pub use esp_hal::entry;
|
||||
use esp_hal::gpio::{GpioPin, Input, Io, Level, Output, Pull, NO_PIN};
|
||||
use esp_hal::interrupt::Priority;
|
||||
use esp_hal::peripherals::{Peripherals, SPI3};
|
||||
use esp_hal::prelude::*;
|
||||
use esp_hal::rtc_cntl::Rtc;
|
||||
use esp_hal::spi::{master::Spi, FullDuplexMode, SpiMode};
|
||||
use esp_hal::system::SystemControl;
|
||||
use esp_hal::timer::timg::TimerGroup;
|
||||
use esp_hal_embassy::InterruptExecutor;
|
||||
use mipidsi::models::ILI9486Rgb565;
|
||||
use mipidsi::options::{ColorInversion, ColorOrder, Rotation};
|
||||
use mipidsi::{options::Orientation, Builder, Display};
|
||||
use xpt2046::Xpt2046;
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn touch_task(
|
||||
touch_irq: GpioPin<36>,
|
||||
spi: ExclusiveDevice<
|
||||
Spi<'static, SPI3, FullDuplexMode>,
|
||||
Output<'static, GpioPin<33>>,
|
||||
&'static mut Delay,
|
||||
>,
|
||||
touch_signal: &'static Signal<NoopRawMutex, Option<Point>>,
|
||||
) -> ! {
|
||||
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");
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init() {
|
||||
const HEAP_SIZE: usize = 250 * 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(),
|
||||
));
|
||||
}
|
||||
slint::platform::set_platform(Box::new(EspBackend::default()))
|
||||
.expect("backend already initialized");
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct EspBackend {
|
||||
window: RefCell<Option<Rc<slint::platform::software_renderer::MinimalSoftwareWindow>>>,
|
||||
}
|
||||
|
||||
impl slint::platform::Platform for EspBackend {
|
||||
fn create_window_adapter(
|
||||
&self,
|
||||
) -> Result<Rc<dyn slint::platform::WindowAdapter>, slint::PlatformError> {
|
||||
let window = slint::platform::software_renderer::MinimalSoftwareWindow::new(
|
||||
slint::platform::software_renderer::RepaintBufferType::ReusedBuffer,
|
||||
);
|
||||
self.window.replace(Some(window.clone()));
|
||||
Ok(window)
|
||||
}
|
||||
|
||||
fn duration_since_start(&self) -> core::time::Duration {
|
||||
embassy_time::Instant::from_millis(0).elapsed().into()
|
||||
}
|
||||
|
||||
//noinspection DuplicatedCode
|
||||
fn run_event_loop(&self) -> Result<(), slint::PlatformError> {
|
||||
use display_interface_spi::SPIInterface;
|
||||
use embedded_hal_bus::spi::ExclusiveDevice;
|
||||
use esp_hal::delay::Delay;
|
||||
use esp_hal::gpio::{Io, Level, Output};
|
||||
use esp_hal::rtc_cntl::Rtc;
|
||||
use esp_hal::spi::{master::Spi, SpiMode};
|
||||
use esp_hal::timer::timg::TimerGroup;
|
||||
use esp_hal::{self, prelude::*};
|
||||
use mipidsi::{
|
||||
options::{ColorInversion, ColorOrder, Orientation, Rotation},
|
||||
Builder,
|
||||
};
|
||||
use static_cell::StaticCell;
|
||||
|
||||
let peripherals = Peripherals::take();
|
||||
let system = SystemControl::new(peripherals.SYSTEM);
|
||||
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);
|
||||
timer_group0.wdt.disable();
|
||||
let mut timer_group1 = TimerGroup::new(peripherals.TIMG1, &clocks);
|
||||
timer_group1.wdt.disable();
|
||||
|
||||
esp_hal_embassy::init(&clocks, timer_group0.timer0);
|
||||
|
||||
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
|
||||
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);
|
||||
|
||||
let touch_spi =
|
||||
ExclusiveDevice::new(touch_spi, Output::new(touch_cs, Level::Low), &mut Delay).unwrap();
|
||||
|
||||
let touch_signal = Signal::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;
|
||||
|
||||
static EXECUTOR: StaticCell<InterruptExecutor<2>> = StaticCell::new();
|
||||
let executor = InterruptExecutor::<2>::new(sw_int);
|
||||
let executor = EXECUTOR.init(executor);
|
||||
|
||||
|
||||
executor.spawner().unwrap()
|
||||
.spawn(touch_task(touch_irq, touch_spi, touch_signal))
|
||||
.unwrap();
|
||||
|
||||
executor.start(Priority::Priority1);
|
||||
|
||||
// Display setup
|
||||
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);
|
||||
|
||||
let mut spi = Spi::new(peripherals.SPI2, 10u32.MHz(), SpiMode::Mode0, &clocks).with_pins(
|
||||
Some(sclk),
|
||||
Some(mosi),
|
||||
Some(miso),
|
||||
esp_hal::gpio::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 spi = ExclusiveDevice::new(spi, Output::new(cs, Level::Low), &mut Delay).unwrap();
|
||||
|
||||
let di = SPIInterface::new(spi, 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);
|
||||
|
||||
backlight.set_high().unwrap();
|
||||
|
||||
let size = display.size();
|
||||
let size = slint::PhysicalSize::new(size.width as u32, size.height as u32);
|
||||
|
||||
self.window.borrow().as_ref().unwrap().set_size(size);
|
||||
|
||||
let mut buffer_provider = DrawBuffer {
|
||||
display,
|
||||
buffer: &mut [slint::platform::software_renderer::Rgb565Pixel(0); 320],
|
||||
};
|
||||
|
||||
loop {
|
||||
slint::platform::update_timers_and_animations();
|
||||
|
||||
if let Some(window) = self.window.borrow().clone() {
|
||||
window.draw_if_needed(|renderer| {
|
||||
renderer.render_by_line(&mut buffer_provider);
|
||||
});
|
||||
if window.has_active_animations() {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// TODO: Implement touch handling
|
||||
}
|
||||
}
|
||||
|
||||
fn debug_log(&self, arguments: core::fmt::Arguments) {
|
||||
esp_println::println!("{}", arguments);
|
||||
}
|
||||
}
|
||||
|
||||
struct DrawBuffer<'a, Display> {
|
||||
display: Display,
|
||||
buffer: &'a mut [slint::platform::software_renderer::Rgb565Pixel],
|
||||
}
|
||||
|
||||
impl<
|
||||
DI: display_interface_spi::WriteOnlyDataCommand,
|
||||
RST: OutputPin<Error = core::convert::Infallible>,
|
||||
> slint::platform::software_renderer::LineBufferProvider
|
||||
for &mut DrawBuffer<'_, Display<DI, mipidsi::models::ILI9342CRgb565, RST>>
|
||||
{
|
||||
type TargetPixel = slint::platform::software_renderer::Rgb565Pixel;
|
||||
|
||||
fn process_line(
|
||||
&mut self,
|
||||
line: usize,
|
||||
range: core::ops::Range<usize>,
|
||||
render_fn: impl FnOnce(&mut [slint::platform::software_renderer::Rgb565Pixel]),
|
||||
) {
|
||||
let buffer = &mut self.buffer[range.clone()];
|
||||
|
||||
render_fn(buffer);
|
||||
|
||||
// We send empty data just to get the device in the right window
|
||||
self.display
|
||||
.set_pixels(
|
||||
range.start as u16,
|
||||
line as _,
|
||||
range.end as u16,
|
||||
line as u16,
|
||||
buffer
|
||||
.iter()
|
||||
.map(|x| embedded_graphics_core::pixelcolor::raw::RawU16::new(x.0).into()),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
8
slint-based/src/lib.rs
Normal file
8
slint-based/src/lib.rs
Normal file
@ -0,0 +1,8 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
// mod cyd;
|
||||
|
||||
// pub use cyd::*;
|
22
slint-based/ui/app-window.slint
Normal file
22
slint-based/ui/app-window.slint
Normal file
@ -0,0 +1,22 @@
|
||||
import { Button, VerticalBox , AboutSlint } from "std-widgets.slint";
|
||||
|
||||
export component AppWindow inherits Window {
|
||||
width: 320px;
|
||||
height: 240px;
|
||||
in-out property <int> counter: 42;
|
||||
callback request-increase-value();
|
||||
VerticalBox {
|
||||
Text {
|
||||
text: "Counter: \{root.counter}";
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Increase value";
|
||||
clicked => {
|
||||
root.request-increase-value();
|
||||
}
|
||||
}
|
||||
|
||||
AboutSlint { }
|
||||
}
|
||||
}
|
164
slint-based/ui/lights-app.slint
Normal file
164
slint-based/ui/lights-app.slint
Normal file
@ -0,0 +1,164 @@
|
||||
import { Button, VerticalBox , AboutSlint, Slider, Switch } from "std-widgets.slint";
|
||||
|
||||
export struct Light {
|
||||
name: string,
|
||||
brightness: int,
|
||||
on: bool,
|
||||
}
|
||||
|
||||
export component LightsApp inherits Window {
|
||||
width: 320px;
|
||||
height: 240px;
|
||||
|
||||
in property <bool> show-start-timer: true;
|
||||
in property <bool> show-stop-timer: false;
|
||||
in property <bool> show-reset-timer: false;
|
||||
|
||||
property <[Light]> lights: [
|
||||
{
|
||||
name: "Bathroom",
|
||||
brightness: 100,
|
||||
on: true,
|
||||
},
|
||||
{
|
||||
name: "Bedroom",
|
||||
brightness: 200,
|
||||
on: true,
|
||||
},
|
||||
{
|
||||
name: "Living Room",
|
||||
brightness: 50,
|
||||
on: false,
|
||||
},
|
||||
{
|
||||
name: "Front Door",
|
||||
brightness: 250,
|
||||
on: false,
|
||||
},
|
||||
{
|
||||
name: "Porch",
|
||||
brightness: 1,
|
||||
on: true,
|
||||
},
|
||||
// {name: "Bathroom", brightness: 4, on: false, },
|
||||
];
|
||||
|
||||
property <int> selected-light: 0;
|
||||
property <bool> show-light-page: false;
|
||||
|
||||
in property <string> timer-text: "00:00:000";
|
||||
|
||||
property <image> start-timer-icon: @image-url("../img/play.png");
|
||||
property <image> stop-timer-icon: @image-url("../img/pause.png");
|
||||
property <image> reset-timer-icon: @image-url("../img/xmark-square.png");
|
||||
|
||||
property <image> light-icon: @image-url("../img/play.png");
|
||||
|
||||
VerticalBox {
|
||||
alignment: start;
|
||||
Text {
|
||||
text: show-light-page ? lights[selected-light].name : "Light Control App (Slint)";
|
||||
font-size: 14px;
|
||||
horizontal-alignment: center;
|
||||
}
|
||||
}
|
||||
|
||||
if !show-light-page: VerticalLayout {
|
||||
alignment: center;
|
||||
spacing: 5px;
|
||||
padding-top: 25px;
|
||||
// height: 200px;
|
||||
HorizontalLayout {
|
||||
alignment: LayoutAlignment.center;
|
||||
spacing: 6px;
|
||||
for i in 3: HorizontalLayout {
|
||||
alignment: center;
|
||||
height: 100px;
|
||||
if i < lights.length:
|
||||
Button {
|
||||
width: 96px;
|
||||
height: 96px;
|
||||
// icon: light-icon;
|
||||
text: lights[i].name;
|
||||
clicked => {
|
||||
selected-light = i;
|
||||
show-light-page = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HorizontalLayout {
|
||||
alignment: LayoutAlignment.center;
|
||||
spacing: 6px;
|
||||
for i in 3: HorizontalLayout {
|
||||
alignment: center;
|
||||
height: 100px;
|
||||
if i + 3 < lights.length:
|
||||
Button {
|
||||
width: 96px;
|
||||
height: 96px;
|
||||
// icon: light-icon;
|
||||
text: lights[i].name;
|
||||
clicked => {
|
||||
selected-light = i + 3;
|
||||
show-light-page = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if show-light-page: Rectangle {
|
||||
VerticalLayout {
|
||||
alignment: LayoutAlignment.center;
|
||||
width: 320px;
|
||||
spacing: 4px;
|
||||
|
||||
HorizontalLayout {
|
||||
alignment: LayoutAlignment.center;
|
||||
Slider {
|
||||
width: 250px;
|
||||
maximum: 255;
|
||||
value: lights[selected-light].brightness;
|
||||
changed(f) => {
|
||||
lights[selected-light].brightness = f
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "Brightness";
|
||||
horizontal-alignment: center;
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
HorizontalLayout {
|
||||
alignment: LayoutAlignment.center;
|
||||
Switch {
|
||||
checked: lights[selected-light].on;
|
||||
toggled => {
|
||||
lights[selected-light].on = !lights[selected-light].on
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "On / Off";
|
||||
horizontal-alignment: center;
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
x: 10px;
|
||||
y: 10px;
|
||||
text: "<";
|
||||
clicked => {
|
||||
show-light-page = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
146
slint-based/ui/microwave-ui.slint
Normal file
146
slint-based/ui/microwave-ui.slint
Normal file
@ -0,0 +1,146 @@
|
||||
import { Button, VerticalBox, HorizontalBox, AboutSlint } from "std-widgets.slint";
|
||||
|
||||
export component MicrowaveUI inherits Window {
|
||||
width: 320px;
|
||||
height: 240px;
|
||||
|
||||
property <[string]> wattages: ["180W", "220W", "360W", "480W", "620W", "800W"];
|
||||
property <int> selected-wattage: 0;
|
||||
|
||||
callback add-10s();
|
||||
callback sub-10s();
|
||||
callback start-timer();
|
||||
callback stop-timer();
|
||||
callback reset-timer();
|
||||
|
||||
in property <bool> show-start-timer: true;
|
||||
in property <bool> show-stop-timer: false;
|
||||
in property <bool> show-reset-timer: false;
|
||||
|
||||
in property <string> timer-text: "00:00:000";
|
||||
|
||||
property <image> start-timer-icon: @image-url("../img/play.png");
|
||||
property <image> stop-timer-icon: @image-url("../img/pause.png");
|
||||
property <image> reset-timer-icon: @image-url("../img/xmark-square.png");
|
||||
|
||||
function multifunction-button-pressed() {
|
||||
if (show-start-timer) {
|
||||
start-timer();
|
||||
}
|
||||
if (show-stop-timer) {
|
||||
stop-timer();
|
||||
}
|
||||
if (show-reset-timer) {
|
||||
reset-timer();
|
||||
}
|
||||
}
|
||||
|
||||
function multifunction-button-icon() -> image {
|
||||
if (show-start-timer) {
|
||||
return start-timer-icon;
|
||||
}
|
||||
if (show-stop-timer) {
|
||||
return stop-timer-icon;
|
||||
}
|
||||
if (show-reset-timer) {
|
||||
return reset-timer-icon;
|
||||
}
|
||||
return start-timer-icon;
|
||||
}
|
||||
|
||||
VerticalBox {
|
||||
alignment: start;
|
||||
Text {
|
||||
text: " Microwave UI (Slint)";
|
||||
font-size: 14px;
|
||||
horizontal-alignment: center;
|
||||
}
|
||||
}
|
||||
|
||||
HorizontalBox {
|
||||
VerticalBox {
|
||||
padding-top: 15px;
|
||||
padding-bottom: 20px;
|
||||
Button {
|
||||
enabled: (selected-wattage < wattages.length - 1) && show-start-timer;
|
||||
text: "+";
|
||||
clicked => {
|
||||
selected-wattage += 1
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
font-size: 24px;
|
||||
text: wattages[selected-wattage];
|
||||
horizontal-alignment: center;
|
||||
vertical-alignment: center;
|
||||
}
|
||||
|
||||
Button {
|
||||
enabled: !(selected-wattage <= 0) && show-start-timer;
|
||||
text: "-";
|
||||
clicked => {
|
||||
selected-wattage -= 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VerticalBox {
|
||||
alignment: center;
|
||||
Text {
|
||||
text: timer-text;
|
||||
font-size: 24px;
|
||||
horizontal-alignment: center;
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
height: 4px;
|
||||
}
|
||||
|
||||
HorizontalLayout {
|
||||
alignment: center;
|
||||
spacing: 8px;
|
||||
|
||||
Button {
|
||||
text: "+10s";
|
||||
enabled: show-start-timer;
|
||||
clicked => {
|
||||
add-10s();
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "Set Timer";
|
||||
vertical-alignment: center;
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "-10s";
|
||||
enabled: show-start-timer;
|
||||
clicked => {
|
||||
sub-10s();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HorizontalLayout {
|
||||
alignment: center;
|
||||
spacing: 8px;
|
||||
Button {
|
||||
icon: @image-url("../img/restart.png");
|
||||
clicked => {
|
||||
reset-timer();
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
icon: multifunction-button-icon();
|
||||
// visible: root.show_start_timer;
|
||||
clicked => {
|
||||
multifunction-button-pressed();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
114
slint-based/ui/timer-app.slint
Normal file
114
slint-based/ui/timer-app.slint
Normal file
@ -0,0 +1,114 @@
|
||||
import { Button, VerticalBox , AboutSlint } from "std-widgets.slint";
|
||||
|
||||
export component TimerApp inherits Window {
|
||||
width: 320px;
|
||||
height: 240px;
|
||||
|
||||
callback add-10s();
|
||||
callback sub-10s();
|
||||
callback start-timer();
|
||||
callback stop-timer();
|
||||
callback reset-timer();
|
||||
|
||||
in property <bool> show-start-timer: true;
|
||||
in property <bool> show-stop-timer: false;
|
||||
in property <bool> show-reset-timer: false;
|
||||
|
||||
in property <string> timer-text: "00:00:000";
|
||||
|
||||
property <image> start-timer-icon: @image-url("../img/play.png");
|
||||
property <image> stop-timer-icon: @image-url("../img/pause.png");
|
||||
property <image> reset-timer-icon: @image-url("../img/xmark-square.png");
|
||||
|
||||
function multifunction-button-pressed() {
|
||||
if (show-start-timer) {
|
||||
start-timer();
|
||||
}
|
||||
if (show-stop-timer) {
|
||||
stop-timer();
|
||||
}
|
||||
if (show-reset-timer) {
|
||||
reset-timer();
|
||||
}
|
||||
}
|
||||
|
||||
function multifunction-button-icon() -> image {
|
||||
if (show-start-timer) {
|
||||
return start-timer-icon;
|
||||
}
|
||||
if (show-stop-timer) {
|
||||
return stop-timer-icon;
|
||||
}
|
||||
if (show-reset-timer) {
|
||||
return reset-timer-icon;
|
||||
}
|
||||
return start-timer-icon;
|
||||
}
|
||||
|
||||
VerticalBox {
|
||||
alignment: start;
|
||||
Text {
|
||||
text: "Timer App (Slint)";
|
||||
font-size: 14px;
|
||||
horizontal-alignment: center;
|
||||
}
|
||||
}
|
||||
|
||||
VerticalBox {
|
||||
alignment: center;
|
||||
Text {
|
||||
text: timer-text;
|
||||
font-size: 24px;
|
||||
horizontal-alignment: center;
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
height: 4px;
|
||||
}
|
||||
|
||||
HorizontalLayout {
|
||||
alignment: center;
|
||||
spacing: 8px;
|
||||
|
||||
Button {
|
||||
text: "+10s";
|
||||
enabled: show-start-timer;
|
||||
clicked => {
|
||||
add-10s();
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "Set Timer";
|
||||
vertical-alignment: center;
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "-10s";
|
||||
enabled: show-start-timer;
|
||||
clicked => {
|
||||
sub-10s();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HorizontalLayout {
|
||||
alignment: center;
|
||||
spacing: 8px;
|
||||
Button {
|
||||
icon: @image-url("../img/restart.png");
|
||||
clicked => {
|
||||
reset-timer();
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
icon: multifunction-button-icon();
|
||||
// visible: root.show_start_timer;
|
||||
clicked => {
|
||||
multifunction-button-pressed();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
0
slint/ui.slint
Normal file
0
slint/ui.slint
Normal file
Reference in New Issue
Block a user