From 05eb16b89f55b9e9ed0985d19907d79e4d258272 Mon Sep 17 00:00:00 2001 From: Priec Date: Sun, 3 May 2026 12:54:32 +0200 Subject: [PATCH] semestralka na tprais --- tprais_semestralka1/.cargo/config.toml | 17 + tprais_semestralka1/.env_temp | 4 + tprais_semestralka1/.gitignore | 20 + tprais_semestralka1/Cargo.lock | 1996 +++++++++++++++++ tprais_semestralka1/Cargo.toml | 96 + tprais_semestralka1/Makefile | 12 + tprais_semestralka1/build.rs | 73 + .../docs/critical_data_flow_points.mermaid | 37 + .../critical_data_flow_points.mermaid.svg | 1 + .../docs/mpu_data_flow.mermaid | 54 + .../docs/mpu_data_flow.mermaid.svg | 1 + .../docs/overall_system_architecture.mermaid | 42 + .../overall_system_architecture.mermaid.svg | 1 + tprais_semestralka1/expanded.rs | 0 tprais_semestralka1/old_main.rs | 181 ++ tprais_semestralka1/rust-toolchain.toml | 2 + tprais_semestralka1/src/bin/main.rs | 293 +++ tprais_semestralka1/src/lib.rs | 4 + tprais_semestralka1/src/mqtt/client.rs | 442 ++++ tprais_semestralka1/src/mqtt/config.rs | 122 + tprais_semestralka1/src/mqtt/mod.rs | 4 + 21 files changed, 3402 insertions(+) create mode 100644 tprais_semestralka1/.cargo/config.toml create mode 100644 tprais_semestralka1/.env_temp create mode 100644 tprais_semestralka1/.gitignore create mode 100644 tprais_semestralka1/Cargo.lock create mode 100644 tprais_semestralka1/Cargo.toml create mode 100644 tprais_semestralka1/Makefile create mode 100644 tprais_semestralka1/build.rs create mode 100644 tprais_semestralka1/docs/critical_data_flow_points.mermaid create mode 100644 tprais_semestralka1/docs/critical_data_flow_points.mermaid.svg create mode 100644 tprais_semestralka1/docs/mpu_data_flow.mermaid create mode 100644 tprais_semestralka1/docs/mpu_data_flow.mermaid.svg create mode 100644 tprais_semestralka1/docs/overall_system_architecture.mermaid create mode 100644 tprais_semestralka1/docs/overall_system_architecture.mermaid.svg create mode 100644 tprais_semestralka1/expanded.rs create mode 100644 tprais_semestralka1/old_main.rs create mode 100644 tprais_semestralka1/rust-toolchain.toml create mode 100644 tprais_semestralka1/src/bin/main.rs create mode 100644 tprais_semestralka1/src/lib.rs create mode 100644 tprais_semestralka1/src/mqtt/client.rs create mode 100644 tprais_semestralka1/src/mqtt/config.rs create mode 100644 tprais_semestralka1/src/mqtt/mod.rs diff --git a/tprais_semestralka1/.cargo/config.toml b/tprais_semestralka1/.cargo/config.toml new file mode 100644 index 0000000..a8791c1 --- /dev/null +++ b/tprais_semestralka1/.cargo/config.toml @@ -0,0 +1,17 @@ +[target.xtensa-esp32-none-elf] +runner = "espflash flash --monitor --chip esp32" + +[env] +ESP_LOG="info" + +[build] +rustflags = [ + "-C", "link-arg=-nostartfiles", + "-C", "link-arg=-Tdefmt.x", + "-Z", "stack-protector=all", +] + +target = "xtensa-esp32-none-elf" + +[unstable] +build-std = ["alloc", "core"] diff --git a/tprais_semestralka1/.env_temp b/tprais_semestralka1/.env_temp new file mode 100644 index 0000000..cdce368 --- /dev/null +++ b/tprais_semestralka1/.env_temp @@ -0,0 +1,4 @@ +SSID = "nazov_wifi_siete" +PASSWORD = "heslo_od_wifi" +BROKER_IP= "5.196.78.28" +BROKER_PORT= "1883" diff --git a/tprais_semestralka1/.gitignore b/tprais_semestralka1/.gitignore new file mode 100644 index 0000000..ea52893 --- /dev/null +++ b/tprais_semestralka1/.gitignore @@ -0,0 +1,20 @@ +# will have compiled files and executables +debug/ +target/ +.vscode/ +.zed/ +.helix/ +.env + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb + +# RustRover +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ diff --git a/tprais_semestralka1/Cargo.lock b/tprais_semestralka1/Cargo.lock new file mode 100644 index 0000000..5c38fed --- /dev/null +++ b/tprais_semestralka1/Cargo.lock @@ -0,0 +1,1996 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "allocator-api2" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c583acf993cf4245c4acb0a2cc2ab1f9cc097de73411bb6d3647ff6af2b1013d" + +[[package]] +name = "anyhow" +version = "1.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "az" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" + +[[package]] +name = "basic-toml" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba62675e8242a4c4e806d12f11d136e626e6c8361d6b829310732241652a178a" +dependencies = [ + "serde", +] + +[[package]] +name = "bitfield" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62a3a774b2fcac1b726922b921ebba5e9fe36ad37659c822cf8ff2c1e0819892" +dependencies = [ + "bitfield-macros", +] + +[[package]] +name = "bitfield-macros" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52511b09931f7d5fe3a14f23adefbc23e5725b184013e96c8419febb61f14734" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" + +[[package]] +name = "byte-slice-cast" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" + +[[package]] +name = "bytemuck" +version = "1.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3995eaeebcdf32f91f980d360f78732ddc061097ab4e39991ae7a6ace9194677" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "castaway" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" +dependencies = [ + "rustversion", +] + +[[package]] +name = "cfg-if" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" + +[[package]] +name = "compact_str" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb1325a1cece981e8a296ab8f0f9b63ae357bd0784a9faaf548cc7b480707a" +dependencies = [ + "castaway", + "cfg-if", + "itoa", + "rustversion", + "ryu", + "static_assertions", +] + +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core 0.20.11", + "darling_macro 0.20.11", +] + +[[package]] +name = "darling" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +dependencies = [ + "darling_core 0.21.3", + "darling_macro 0.21.3", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.106", +] + +[[package]] +name = "darling_core" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core 0.20.11", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "darling_macro" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +dependencies = [ + "darling_core 0.21.3", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "defmt" +version = "0.3.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0963443817029b2024136fc4dd07a5107eb8f977eaf18fcd1fdeb11306b64ad" +dependencies = [ + "defmt 1.0.1", +] + +[[package]] +name = "defmt" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "548d977b6da32fa1d1fda2876453da1e7df63ad0304c8b3dae4dbe7b96f39b78" +dependencies = [ + "bitflags 1.3.2", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d4fc12a85bcf441cfe44344c4b72d58493178ce635338a3f3b78943aceb258e" +dependencies = [ + "defmt-parser", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "defmt-parser" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" +dependencies = [ + "thiserror", +] + +[[package]] +name = "delegate" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6178a82cf56c836a3ba61a7935cdb1c49bfaa6fa4327cd5bf554a503087de26b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "deranged" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "crypto-common", +] + +[[package]] +name = "display-interface" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ba2aab1ef3793e6f7804162debb5ac5edb93b3d650fbcc5aeb72fcd0e6c03a0" + +[[package]] +name = "display-interface-i2c" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d964fa85bbbb5a6ecd06e58699407ac5dc3e3ad72dac0ab7e6b0d00a1cd262d" +dependencies = [ + "display-interface", + "embedded-hal 1.0.0", + "embedded-hal-async", +] + +[[package]] +name = "display-interface-spi" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f86b9ec30048b1955da2038fcc3c017f419ab21bb0001879d16c0a3749dc6b7a" +dependencies = [ + "byte-slice-cast", + "display-interface", + "embedded-hal 1.0.0", + "embedded-hal-async", +] + +[[package]] +name = "document-features" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d" +dependencies = [ + "litrs", +] + +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "embassy-embedded-hal" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c62a3bf127e03832fb97d8b01a058775e617653bc89e2a12c256485a7fb54c1" +dependencies = [ + "embassy-embedded-hal 0.4.0", + "embassy-futures", + "embassy-sync 0.6.2", + "embassy-time 0.4.0", + "embedded-hal 0.2.7", + "embedded-hal 1.0.0", + "embedded-hal-async", + "embedded-storage", + "embedded-storage-async", + "nb 1.1.0", +] + +[[package]] +name = "embassy-embedded-hal" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1611b7a7ab5d1fbed84c338df26d56fd9bded58006ebb029075112ed2c5e039" +dependencies = [ + "embassy-futures", + "embassy-hal-internal", + "embassy-sync 0.7.2", + "embedded-hal 0.2.7", + "embedded-hal 1.0.0", + "embedded-hal-async", + "embedded-storage", + "embedded-storage-async", + "nb 1.1.0", +] + +[[package]] +name = "embassy-executor" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90327bcc66333a507f89ecc4e2d911b265c45f5c9bc241f98eee076752d35ac6" +dependencies = [ + "critical-section", + "document-features", + "embassy-executor-macros", + "log", +] + +[[package]] +name = "embassy-executor-macros" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3577b1e9446f61381179a330fc5324b01d511624c55f25e3c66c9e3c626dbecf" +dependencies = [ + "darling 0.20.11", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "embassy-futures" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc2d050bdc5c21e0862a89256ed8029ae6c290a93aecefc73084b3002cdebb01" + +[[package]] +name = "embassy-hal-internal" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95285007a91b619dc9f26ea8f55452aa6c60f7115a4edc05085cd2bd3127cd7a" +dependencies = [ + "num-traits", +] + +[[package]] +name = "embassy-net" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0558a231a47e7d4a06a28b5278c92e860f1200f24821d2f365a2f40fe3f3c7b2" +dependencies = [ + "document-features", + "embassy-net-driver", + "embassy-sync 0.7.2", + "embassy-time 0.5.0", + "embedded-io-async", + "embedded-nal-async", + "heapless 0.8.0", + "log", + "managed", + "smoltcp", +] + +[[package]] +name = "embassy-net-driver" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524eb3c489760508f71360112bca70f6e53173e6fe48fc5f0efd0f5ab217751d" + +[[package]] +name = "embassy-sync" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d2c8cdff05a7a51ba0087489ea44b0b1d97a296ca6b1d6d1a33ea7423d34049" +dependencies = [ + "cfg-if", + "critical-section", + "embedded-io-async", + "futures-sink", + "futures-util", + "heapless 0.8.0", +] + +[[package]] +name = "embassy-sync" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73974a3edbd0bd286759b3d483540f0ebef705919a5f56f4fc7709066f71689b" +dependencies = [ + "cfg-if", + "critical-section", + "embedded-io-async", + "futures-core", + "futures-sink", + "heapless 0.8.0", +] + +[[package]] +name = "embassy-time" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f820157f198ada183ad62e0a66f554c610cdcd1a9f27d4b316358103ced7a1f8" +dependencies = [ + "cfg-if", + "critical-section", + "document-features", + "embassy-time-driver", + "embedded-hal 0.2.7", + "embedded-hal 1.0.0", + "embedded-hal-async", + "futures-util", +] + +[[package]] +name = "embassy-time" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4fa65b9284d974dad7a23bb72835c4ec85c0b540d86af7fc4098c88cff51d65" +dependencies = [ + "cfg-if", + "critical-section", + "document-features", + "embassy-time-driver", + "embedded-hal 0.2.7", + "embedded-hal 1.0.0", + "embedded-hal-async", + "futures-core", + "log", +] + +[[package]] +name = "embassy-time-driver" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0a244c7dc22c8d0289379c8d8830cae06bb93d8f990194d0de5efb3b5ae7ba6" +dependencies = [ + "document-features", +] + +[[package]] +name = "embassy-time-queue-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc55c748d16908a65b166d09ce976575fb8852cf60ccd06174092b41064d8f83" +dependencies = [ + "embassy-executor", + "heapless 0.8.0", +] + +[[package]] +name = "embedded-can" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9d2e857f87ac832df68fa498d18ddc679175cf3d2e4aa893988e5601baf9438" +dependencies = [ + "nb 1.1.0", +] + +[[package]] +name = "embedded-graphics" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0649998afacf6d575d126d83e68b78c0ab0e00ca2ac7e9b3db11b4cbe8274ef0" +dependencies = [ + "az", + "byteorder", + "embedded-graphics-core", + "float-cmp", + "micromath", +] + +[[package]] +name = "embedded-graphics-core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba9ecd261f991856250d2207f6d8376946cd9f412a2165d3b75bc87a0bc7a044" +dependencies = [ + "az", + "byteorder", +] + +[[package]] +name = "embedded-hal" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" +dependencies = [ + "nb 0.1.3", + "void", +] + +[[package]] +name = "embedded-hal" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" + +[[package]] +name = "embedded-hal-async" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884" +dependencies = [ + "embedded-hal 1.0.0", +] + +[[package]] +name = "embedded-hal-bus" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "513e0b3a8fb7d3013a8ae17a834283f170deaf7d0eeab0a7c1a36ad4dd356d22" +dependencies = [ + "critical-section", + "embedded-hal 1.0.0", +] + +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + +[[package]] +name = "embedded-io-async" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff09972d4073aa8c299395be75161d582e7629cd663171d62af73c8d50dba3f" +dependencies = [ + "embedded-io", +] + +[[package]] +name = "embedded-nal" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56a28be191a992f28f178ec338a0bf02f63d7803244add736d026a471e6ed77" +dependencies = [ + "nb 1.1.0", +] + +[[package]] +name = "embedded-nal-async" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76959917cd2b86f40a98c28dd5624eddd1fa69d746241c8257eac428d83cb211" +dependencies = [ + "embedded-io-async", + "embedded-nal", +] + +[[package]] +name = "embedded-storage" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21dea9854beb860f3062d10228ce9b976da520a73474aed3171ec276bc0c032" + +[[package]] +name = "embedded-storage-async" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1763775e2323b7d5f0aa6090657f5e21cfa02ede71f5dc40eead06d64dcd15cc" +dependencies = [ + "embedded-storage", +] + +[[package]] +name = "enumset" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25b07a8dfbbbfc0064c0a6bdf9edcf966de6b1c33ce344bdeca3b41615452634" +dependencies = [ + "enumset_derive", +] + +[[package]] +name = "enumset_derive" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43e744e4ea338060faee68ed933e46e722fb7f3617e722a5772d7e856d8b3ce" +dependencies = [ + "darling 0.21.3", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "esp-alloc" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e95f1de57ce5a6600368f3d3c931b0dfe00501661e96f5ab83bc5cdee031784" +dependencies = [ + "allocator-api2 0.3.1", + "cfg-if", + "critical-section", + "document-features", + "enumset", + "linked_list_allocator", +] + +[[package]] +name = "esp-backtrace" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f270a29a3c4e492399b13e157b10151a7616cba69c4d554076ea93ed1bd2916" +dependencies = [ + "cfg-if", + "esp-config", + "esp-println", + "heapless 0.8.0", + "semihosting", +] + +[[package]] +name = "esp-bootloader-esp-idf" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a093dbdc64b0288baacc214c2e8c2f3f13ecbf979c36ee2f63797ecf22538f1" +dependencies = [ + "cfg-if", + "document-features", + "embedded-storage", + "esp-config", + "esp-rom-sys", + "jiff", + "strum", +] + +[[package]] +name = "esp-config" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abd4a8db4b72794637a25944bc8d361c3cc271d4f03987ce8741312b6b61529c" +dependencies = [ + "document-features", + "esp-metadata-generated", + "evalexpr", + "serde", + "serde_yaml", +] + +[[package]] +name = "esp-hal" +version = "1.0.0-rc.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3887eda2917deef3d99e7a5c324f9190714e99055361ad36890dffd0a995b49" +dependencies = [ + "bitfield", + "bitflags 2.10.0", + "bytemuck", + "cfg-if", + "critical-section", + "delegate", + "digest", + "document-features", + "embassy-embedded-hal 0.3.2", + "embassy-futures", + "embassy-sync 0.6.2", + "embedded-can", + "embedded-hal 1.0.0", + "embedded-hal-async", + "embedded-io", + "embedded-io-async", + "enumset", + "esp-config", + "esp-hal-procmacros", + "esp-metadata-generated", + "esp-riscv-rt", + "esp-rom-sys", + "esp32", + "esp32c2", + "esp32c3", + "esp32c6", + "esp32h2", + "esp32s2", + "esp32s3", + "fugit", + "instability", + "log", + "nb 1.1.0", + "paste", + "portable-atomic", + "rand_core 0.6.4", + "rand_core 0.9.3", + "riscv", + "serde", + "strum", + "ufmt-write", + "xtensa-lx", + "xtensa-lx-rt", +] + +[[package]] +name = "esp-hal-embassy" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d000d94064c485f86adc6b02b541e2f072e03321b4f03d4303b7ff3062c7e692" +dependencies = [ + "cfg-if", + "critical-section", + "document-features", + "embassy-executor", + "embassy-sync 0.6.2", + "embassy-time 0.4.0", + "embassy-time-driver", + "embassy-time-queue-utils", + "esp-config", + "esp-hal", + "esp-hal-procmacros", + "esp-metadata-generated", + "log", + "portable-atomic", + "static_cell", +] + +[[package]] +name = "esp-hal-procmacros" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbece384edaf0d1eabfa45afa96d910634d4158638ef983b2d419a8dec832246" +dependencies = [ + "document-features", + "litrs", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.106", + "termcolor", +] + +[[package]] +name = "esp-metadata" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6fbc1d166be84c0750f121e95c8989ddebd7e7bdd86af3594a6cfb34f039650" +dependencies = [ + "anyhow", + "basic-toml", + "indexmap", + "proc-macro2", + "quote", + "serde", + "strum", +] + +[[package]] +name = "esp-metadata-generated" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "189d36b8c8a752bdebec67fd02a15ebb1432feea345553749bca7ce2393cc795" +dependencies = [ + "esp-metadata", +] + +[[package]] +name = "esp-println" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e7e3ab41e96093d7fd307e93bfc88bd646a8ff23036ebf809e116b18869f719" +dependencies = [ + "critical-section", + "defmt 1.0.1", + "document-features", + "esp-metadata-generated", + "log", + "portable-atomic", +] + +[[package]] +name = "esp-riscv-rt" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a00370dfcb0ccc01c6b2540076379c6efd6890a27f584de217c38e3239e19d5" +dependencies = [ + "document-features", + "riscv", + "riscv-rt-macros", +] + +[[package]] +name = "esp-rom-sys" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "646aca2b30503b6c6f34250255fbd5887fd0c4104ea90802c1fea34f3035e7d6" +dependencies = [ + "cfg-if", + "document-features", + "esp-metadata-generated", +] + +[[package]] +name = "esp-wifi" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84908f2e95cb99a200cf448abafc416576338be590778a15d9224eee237f3210" +dependencies = [ + "allocator-api2 0.3.1", + "cfg-if", + "critical-section", + "document-features", + "embassy-net-driver", + "embedded-io", + "embedded-io-async", + "enumset", + "esp-alloc", + "esp-config", + "esp-hal", + "esp-metadata-generated", + "esp-wifi-sys", + "log", + "num-derive", + "num-traits", + "portable-atomic", + "portable_atomic_enum", + "rand_core 0.9.3", + "smoltcp", + "xtensa-lx-rt", +] + +[[package]] +name = "esp-wifi-sys" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6b5438361891c431970194a733415006fb3d00b6eb70b3dcb66fd58f04d9b39" +dependencies = [ + "anyhow", + "log", +] + +[[package]] +name = "esp32" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7680f79e3a4770e59c2dc25b17dcd852921ee57ffae9a4c4806c9ca5001d54d" +dependencies = [ + "critical-section", + "vcell", +] + +[[package]] +name = "esp32c2" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da1bcf86fca83543e0e95561cba27bbcc6b6e7adc5428f49187f5868bc0c3ed2" +dependencies = [ + "critical-section", + "vcell", +] + +[[package]] +name = "esp32c3" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce2c5a33d4377f974cbe8cadf8307f04f2c39755704cb09e81852c63ee4ac7b8" +dependencies = [ + "critical-section", + "vcell", +] + +[[package]] +name = "esp32c6" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ca8fc81b7164df58b5e04aaac9e987459312e51903cca807317990293973a6e" +dependencies = [ + "critical-section", + "vcell", +] + +[[package]] +name = "esp32h2" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80171d08c17d8c63b53334c60ca654786a7593481531d19b639c4e5c76d276de" +dependencies = [ + "critical-section", + "vcell", +] + +[[package]] +name = "esp32s2" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c90d347480fca91f4be3e94b576af9c6c7987795c58dc3c5a7c108b6b3966dc" +dependencies = [ + "critical-section", + "vcell", +] + +[[package]] +name = "esp32s3" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3769c56222c4548833f236c7009f1f8b3f2387af26366f6bd1cea456666a49d" +dependencies = [ + "critical-section", + "vcell", +] + +[[package]] +name = "evalexpr" +version = "12.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02a3229bec56a977f174b32fe7b8d89e8c79ebb4493d10ad763b6676dc2dc0c9" + +[[package]] +name = "float-cmp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" +dependencies = [ + "num-traits", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "fugit" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17186ad64927d5ac8f02c1e77ccefa08ccd9eaa314d5a4772278aa204a22f7e7" +dependencies = [ + "gcd", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", +] + +[[package]] +name = "gcd" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + +[[package]] +name = "hashbrown" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" +dependencies = [ + "allocator-api2 0.2.21", + "equivalent", + "foldhash", +] + +[[package]] +name = "heapless" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" +dependencies = [ + "hash32", + "stable_deref_trait", +] + +[[package]] +name = "heapless" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af2455f757db2b292a9b1768c4b70186d443bcb3b316252d6b540aec1cd89ed" +dependencies = [ + "hash32", + "stable_deref_trait", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "indexmap" +version = "2.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" +dependencies = [ + "equivalent", + "hashbrown", + "serde", + "serde_core", +] + +[[package]] +name = "indoc" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd" + +[[package]] +name = "instability" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435d80800b936787d62688c927b6490e887c7ef5ff9ce922c6c6050fca75eb9a" +dependencies = [ + "darling 0.20.11", + "indoc", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "jiff" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49" +dependencies = [ + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde", +] + +[[package]] +name = "jiff-static" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "kasuari" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fe90c1150662e858c7d5f945089b7517b0a80d8bf7ba4b1b5ffc984e7230a5b" +dependencies = [ + "hashbrown", + "portable-atomic", + "portable-atomic-util", + "thiserror", +] + +[[package]] +name = "line-clipping" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f4de44e98ddbf09375cbf4d17714d18f39195f4f4894e8524501726fd9a8a4a" +dependencies = [ + "bitflags 2.10.0", +] + +[[package]] +name = "linked_list_allocator" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286" + +[[package]] +name = "litrs" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "log" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" + +[[package]] +name = "lru" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1dc47f592c06f33f8e3aea9591776ec7c9f9e4124778ff8a3c3b87159f7e593" +dependencies = [ + "hashbrown", +] + +[[package]] +name = "managed" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d" + +[[package]] +name = "maybe-async-cfg" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1e083394889336bc66a4eaf1011ffbfa74893e910f902a9f271fa624c61e1b2" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "pulldown-cmark", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "micromath" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c8dda44ff03a2f238717214da50f65d5a53b45cd213a7370424ffdb6fae815" + +[[package]] +name = "mousefood" +version = "0.2.1" +source = "git+https://github.com/j-g00da/mousefood?branch=main#693d82ae9482c32be6363e72474faeb7d962cb1b" +dependencies = [ + "embedded-graphics", + "ratatui-core", + "thiserror", +] + +[[package]] +name = "nb" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" +dependencies = [ + "nb 1.1.0", +] + +[[package]] +name = "nb" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "pages-tui" +version = "0.1.0" +dependencies = [ + "heapless 0.9.2", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "portable-atomic" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" + +[[package]] +name = "portable-atomic-util" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "portable_atomic_enum" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d48f60c43e0120bb2bb48589a16d4bed2f4b911be41e299f2d0fc0e0e20885" +dependencies = [ + "portable-atomic", + "portable_atomic_enum_macros", +] + +[[package]] +name = "portable_atomic_enum_macros" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a33fa6ec7f2047f572d49317cca19c87195de99c6e5b6ee492da701cfe02b053" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "proc-macro-crate" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "projekt_final" +version = "0.2.0" +dependencies = [ + "critical-section", + "defmt 1.0.1", + "dotenvy", + "embassy-executor", + "embassy-futures", + "embassy-net", + "embassy-sync 0.7.2", + "embassy-time 0.5.0", + "embedded-hal 1.0.0", + "embedded-hal-bus", + "embedded-io", + "embedded-io-async", + "esp-alloc", + "esp-backtrace", + "esp-bootloader-esp-idf", + "esp-hal", + "esp-hal-embassy", + "esp-println", + "esp-wifi", + "heapless 0.9.2", + "log", + "mousefood", + "pages-tui", + "ratatui", + "rust-mqtt", + "smoltcp", + "ssd1306", + "static_cell", +] + +[[package]] +name = "pulldown-cmark" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "679341d22c78c6c649893cbd6c3278dcbe9fc4faa62fea3a9296ae2b50c14625" +dependencies = [ + "bitflags 2.10.0", + "memchr", + "unicase", +] + +[[package]] +name = "quote" +version = "1.0.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r0" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd7a31eed1591dcbc95d92ad7161908e72f4677f8fabf2a32ca49b4237cbf211" + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" + +[[package]] +name = "ratatui" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1ce67fb8ba4446454d1c8dbaeda0557ff5e94d39d5e5ed7f10a65eb4c8266bc" +dependencies = [ + "instability", + "ratatui-core", + "ratatui-macros", + "ratatui-widgets", +] + +[[package]] +name = "ratatui-core" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ef8dea09a92caaf73bff7adb70b76162e5937524058a7e5bff37869cbbec293" +dependencies = [ + "bitflags 2.10.0", + "compact_str", + "hashbrown", + "indoc", + "itertools 0.14.0", + "kasuari", + "lru", + "strum", + "thiserror", + "unicode-segmentation", + "unicode-truncate", + "unicode-width", +] + +[[package]] +name = "ratatui-macros" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7f1342a13e83e4bb9d0b793d0ea762be633f9582048c892ae9041ef39c936f4" +dependencies = [ + "ratatui-core", + "ratatui-widgets", +] + +[[package]] +name = "ratatui-widgets" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7dbfa023cd4e604c2553483820c5fe8aa9d71a42eea5aa77c6e7f35756612db" +dependencies = [ + "bitflags 2.10.0", + "hashbrown", + "indoc", + "instability", + "itertools 0.14.0", + "line-clipping", + "ratatui-core", + "strum", + "time", + "unicode-segmentation", + "unicode-width", +] + +[[package]] +name = "riscv" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ea8ff73d3720bdd0a97925f0bf79ad2744b6da8ff36be3840c48ac81191d7a7" +dependencies = [ + "critical-section", + "embedded-hal 1.0.0", + "paste", + "riscv-macros", + "riscv-pac", +] + +[[package]] +name = "riscv-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f265be5d634272320a7de94cea15c22a3bfdd4eb42eb43edc528415f066a1f25" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[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.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc71814687c45ba4cd1e47a54e03a2dbc62ca3667098fbae9cc6b423956758fa" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "rust-mqtt" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f71160765f368fd9a84e0955e2ddb6d64ac9018fee1c5323354d6d08c816b40" +dependencies = [ + "defmt 0.3.100", + "embedded-io", + "embedded-io-async", + "heapless 0.8.0", + "rand_core 0.6.4", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "semihosting" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e1c7d2b77d80283c750a39c52f1ab4d17234e8f30bca43550f5b2375f41d5f" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "smoltcp" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dad095989c1533c1c266d9b1e8d70a1329dd3723c3edac6d03bbd67e7bf6f4bb" +dependencies = [ + "bitflags 1.3.2", + "byteorder", + "cfg-if", + "heapless 0.8.0", + "log", + "managed", +] + +[[package]] +name = "ssd1306" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ea6aac2d078bbc71d9b8ac3f657335311f3b6625e9a1a96ccc29f5abfa77c56" +dependencies = [ + "display-interface", + "display-interface-i2c", + "display-interface-spi", + "embedded-graphics-core", + "embedded-hal 1.0.0", + "maybe-async-cfg", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "static_cell" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0530892bb4fa575ee0da4b86f86c667132a94b74bb72160f58ee5a4afec74c23" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "time" +version = "0.3.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" + +[[package]] +name = "toml_datetime" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f1085dec27c2b6632b04c80b3bb1b4300d6495d1e129693bdda7d91e72eec1" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.23.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3effe7c0e86fdff4f69cdd2ccc1b96f933e24811c5441d44904e8683e27184b" +dependencies = [ + "indexmap", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cf893c33be71572e0e9aa6dd15e6677937abd686b066eac3f8cd3531688a627" +dependencies = [ + "winnow", +] + +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + +[[package]] +name = "ufmt-write" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e87a2ed6b42ec5e28cc3b94c09982969e9227600b2e3dcbc1db927a84c06bd69" + +[[package]] +name = "unicase" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" + +[[package]] +name = "unicode-ident" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-truncate" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fbf03860ff438702f3910ca5f28f8dac63c1c11e7efb5012b8b175493606330" +dependencies = [ + "itertools 0.13.0", + "unicode-segmentation", + "unicode-width", +] + +[[package]] +name = "unicode-width" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" + +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + +[[package]] +name = "vcell" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "windows-link" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" + +[[package]] +name = "windows-sys" +version = "0.61.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f109e41dd4a3c848907eb83d5a42ea98b3769495597450cf6d153507b166f0f" +dependencies = [ + "windows-link", +] + +[[package]] +name = "winnow" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" +dependencies = [ + "memchr", +] + +[[package]] +name = "xtensa-lx" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a564fffeb3cd773a524e8d8a5c66ca5e9739ea7450e36a3e6a54dd31f1e652f" +dependencies = [ + "critical-section", +] + +[[package]] +name = "xtensa-lx-rt" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520a8fb0121eb6868f4f5ff383e262dc863f9042496724e01673a98a9b7e6c2b" +dependencies = [ + "document-features", + "r0", + "xtensa-lx", + "xtensa-lx-rt-proc-macros", +] + +[[package]] +name = "xtensa-lx-rt-proc-macros" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5a56a616147f5947ceb673790dd618d77b30e26e677f4a896df049d73059438" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] diff --git a/tprais_semestralka1/Cargo.toml b/tprais_semestralka1/Cargo.toml new file mode 100644 index 0000000..9efb5ea --- /dev/null +++ b/tprais_semestralka1/Cargo.toml @@ -0,0 +1,96 @@ +[package] +edition = "2021" +name = "projekt_final" +rust-version = "1.89.0" +version = "0.2.0" + +[[bin]] +name = "projekt_final" +path = "./src/bin/main.rs" + +[dependencies] +pages-tui = { path = "../../../pages-tui" } +esp-bootloader-esp-idf = { version = "0.2.0", features = ["esp32"] } +esp-hal = { version = "=1.0.0-rc.0", features = [ + "esp32", + "log-04", + "unstable", +] } +log = "0.4.27" + +embassy-net = { version = "0.7.0", features = [ + "dhcpv4", + "proto-ipv6", + "log", + "medium-ethernet", + "tcp", + "udp", +] } +embedded-io = "0.6.1" +embedded-io-async = "0.6.1" +esp-alloc = "0.8.0" +esp-backtrace = { version = "0.17.0", features = [ + "esp32", + "exception-handler", + "panic-handler", + "println", +] } +esp-println = { version = "0.15.0", features = ["esp32", "log-04", "defmt-espflash"] } +# for more networking protocol support see https://crates.io/crates/edge-net +critical-section = "1.2.0" +embassy-executor = { version = "0.7.0", features = [ + "log", + "task-arena-size-20480", +] } +embassy-time = { version = "0.5.0", features = ["log"] } +esp-hal-embassy = { version = "0.9.0", features = ["esp32", "log-04"] } +esp-wifi = { version = "0.15.0", features = [ + "builtin-scheduler", + "esp-alloc", + "esp32", + "log-04", + "smoltcp", + "wifi", +] } +smoltcp = { version = "0.12.0", default-features = false, features = [ + "log", + "medium-ethernet", + "multicast", + "proto-dhcpv4", + "proto-dns", + "proto-ipv4", + "proto-ipv6", + "socket-dns", + "socket-icmp", + "socket-raw", + "socket-tcp", + "socket-udp", +] } +static_cell = "2.1.1" +rust-mqtt = { version = "0.3.0", default-features = false, features = ["no_std"] } +embassy-futures = "0.1.2" +embassy-sync = "0.7.2" +heapless = "0.9.1" +mousefood = { git = "https://github.com/j-g00da/mousefood", branch = "main", default-features = false } +ssd1306 = "0.10.0" +ratatui = { version = "0.30.0", default-features = false, features = ["macros", "all-widgets", "portable-atomic"] } +embedded-hal-bus = "0.3.0" +embedded-hal = "1.0.0" +defmt = "1.0.1" + +[build-dependencies] +dotenvy = "0.15.7" + +[profile.dev] +# Rust debug is too slow. +# For debug builds always builds with some optimization +opt-level = "s" + +[profile.release] +codegen-units = 1 # LLVM can perform better optimizations using a single thread +debug = 2 +debug-assertions = false +incremental = false +lto = 'fat' +opt-level = 's' +overflow-checks = false diff --git a/tprais_semestralka1/Makefile b/tprais_semestralka1/Makefile new file mode 100644 index 0000000..d4b9f29 --- /dev/null +++ b/tprais_semestralka1/Makefile @@ -0,0 +1,12 @@ +.PHONY: all build flash + +all: build flash + +build: + cargo build --release + +flash: + cargo espflash flash --release --monitor + +info: + espflash board-info diff --git a/tprais_semestralka1/build.rs b/tprais_semestralka1/build.rs new file mode 100644 index 0000000..7b470c4 --- /dev/null +++ b/tprais_semestralka1/build.rs @@ -0,0 +1,73 @@ +fn main() { + // Explicitly load .env from the project root, even when called from other dirs + let project_root = std::env::var("CARGO_MANIFEST_DIR").unwrap(); + let dotenv_path = std::path::Path::new(&project_root).join(".env"); + if dotenvy::from_path(dotenv_path.clone()).is_ok() { + println!("cargo:rerun-if-changed={}", dotenv_path.display()); + } + + // Pass WIFI credentials into firmware + if let Ok(ssid) = std::env::var("SSID") { + println!("cargo:rustc-env=SSID={}", ssid); + } + if let Ok(password) = std::env::var("PASSWORD") { + println!("cargo:rustc-env=PASSWORD={}", password); + } + if let Ok(ip) = std::env::var("BROKER_IP") { + println!("cargo:rustc-env=BROKER_IP={}", ip); + } + if let Ok(port) = std::env::var("BROKER_PORT") { + println!("cargo:rustc-env=BROKER_PORT={}", port); + } + + linker_be_nice(); + + println!("cargo:rustc-link-arg=-Tlinkall.x"); +} + +fn linker_be_nice() { + let args: Vec = std::env::args().collect(); + if args.len() > 1 { + let kind = &args[1]; + let what = &args[2]; + + match kind.as_str() { + "undefined-symbol" => match what.as_str() { + "_defmt_timestamp" => { + eprintln!(); + eprintln!("💡 `defmt` not found - make sure `defmt.x` is added as a linker script and you have included `use defmt_rtt as _;`"); + eprintln!(); + } + "_stack_start" => { + eprintln!(); + eprintln!("💡 Is the linker script `linkall.x` missing?"); + eprintln!(); + } + "esp_wifi_preempt_enable" + | "esp_wifi_preempt_yield_task" + | "esp_wifi_preempt_task_create" => { + eprintln!(); + eprintln!("💡 `esp-wifi` has no scheduler enabled. Make sure you have the `builtin-scheduler` feature enabled, or that you provide an external scheduler."); + eprintln!(); + } + "embedded_test_linker_file_not_added_to_rustflags" => { + eprintln!(); + eprintln!("💡 `embedded-test` not found - make sure `embedded-test.x` is added as a linker script for tests"); + eprintln!(); + } + _ => (), + }, + // we don't have anything helpful for "missing-lib" yet + _ => { + std::process::exit(1); + } + } + + std::process::exit(0); + } + + println!( + "cargo:rustc-link-arg=-Wl,--error-handling-script={}", + std::env::current_exe().unwrap().display() + ); +} diff --git a/tprais_semestralka1/docs/critical_data_flow_points.mermaid b/tprais_semestralka1/docs/critical_data_flow_points.mermaid new file mode 100644 index 0000000..1ecc5bf --- /dev/null +++ b/tprais_semestralka1/docs/critical_data_flow_points.mermaid @@ -0,0 +1,37 @@ +graph TD + START[MPU reads @50ms = 20 Hz] --> A{IMU_CHANNEL
try_send} + + A -->|Full| DROP1[❌ DROP: Channel full
16 slots @ 50ms = 800ms buffer] + A -->|OK| B[Main Loop receive] + + B --> C[Drain loop:
Get freshest reading] + C --> D{Time check:
≥3s since last?} + + D -->|No| E[Skip MQTT] + D -->|Yes| F{mqtt_set_imu
try_lock IMU_LATEST} + + F -->|Locked| DROP2[❌ SKIP: Mutex busy] + F -->|OK| G[Store payload] + + E --> H[show_imu] + G --> H + + H --> I{DISPLAY_CHANNEL
try_send} + I -->|Full| DROP3[❌ DROP: Display slow
8 slots @ 100ms = 800ms buffer] + I -->|OK| J[Display renders] + + G --> K[MQTT Task loop] + K --> L{IMU_LATEST
try_lock} + + L -->|Empty/Locked| M[Skip this iteration] + L -->|Has data| N[Send to broker
QoS0 no retain] + + N --> O{TCP send result} + O -->|Fail| RECONNECT[❌ Session dies
Reconnect in 5s] + O -->|OK| P[✅ Data sent] + + style DROP1 fill:#ffcccc + style DROP2 fill:#ffcccc + style DROP3 fill:#ffcccc + style RECONNECT fill:#ffcccc + style P fill:#ccffcc diff --git a/tprais_semestralka1/docs/critical_data_flow_points.mermaid.svg b/tprais_semestralka1/docs/critical_data_flow_points.mermaid.svg new file mode 100644 index 0000000..9453639 --- /dev/null +++ b/tprais_semestralka1/docs/critical_data_flow_points.mermaid.svg @@ -0,0 +1 @@ +

Full

OK

No

Yes

Locked

OK

Full

OK

Empty/Locked

Has data

Fail

OK

MPU reads @50ms = 20 Hz

IMU_CHANNEL
try_send

❌ DROP: Channel full
16 slots @ 50ms = 800ms buffer

Main Loop receive

Drain loop:
Get freshest reading

Time check:
≥3s since last?

Skip MQTT

mqtt_set_imu
try_lock IMU_LATEST

❌ SKIP: Mutex busy

Store payload

show_imu

DISPLAY_CHANNEL
try_send

❌ DROP: Display slow
8 slots @ 100ms = 800ms buffer

Display renders

MQTT Task loop

IMU_LATEST
try_lock

Skip this iteration

Send to broker
QoS0 no retain

TCP send result

❌ Session dies
Reconnect in 5s

✅ Data sent

\ No newline at end of file diff --git a/tprais_semestralka1/docs/mpu_data_flow.mermaid b/tprais_semestralka1/docs/mpu_data_flow.mermaid new file mode 100644 index 0000000..59f1876 --- /dev/null +++ b/tprais_semestralka1/docs/mpu_data_flow.mermaid @@ -0,0 +1,54 @@ +sequenceDiagram + participant HW as MPU6050 Hardware + participant MPU as MPU Task
(Core 0) + participant CH as IMU_CHANNEL
[16 slots] + participant MAIN as Main Loop
(Core 0) + participant LATEST as IMU_LATEST
(Mutex) + participant MQTT as MQTT Task
(Core 1) + participant DISP as Display API + + Note over MPU: Every 50ms + MPU->>HW: Read sensor (I2C) + HW-->>MPU: Raw data + MPU->>MPU: Convert to ImuReading + MPU->>CH: try_send(reading) + + alt Channel full + CH--xMPU: Drop (log warning) + else Channel has space + CH-->>MPU: OK + end + + Note over MAIN: Continuous loop + MAIN->>CH: receive() [blocking] + CH-->>MAIN: reading + + Note over MAIN: Drain queue + loop While available + MAIN->>CH: try_receive() + CH-->>MAIN: newer reading + end + + MAIN->>DISP: show_imu(reading)
[try_send] + + Note over MAIN: Every 3 seconds + alt Time >= 3s since last + MAIN->>MAIN: Format JSON payload + MAIN->>LATEST: mqtt_set_imu()
[try_lock] + + alt Mutex available + LATEST-->>MAIN: Stored + else Mutex locked + LATEST--xMAIN: Skip + end + end + + Note over MQTT: Continuous loop + MQTT->>LATEST: try_lock() + + alt Data available + LATEST-->>MQTT: payload + MQTT->>MQTT: send_message("esp32/imu") + else No data + LATEST--xMQTT: None + end diff --git a/tprais_semestralka1/docs/mpu_data_flow.mermaid.svg b/tprais_semestralka1/docs/mpu_data_flow.mermaid.svg new file mode 100644 index 0000000..6c95931 --- /dev/null +++ b/tprais_semestralka1/docs/mpu_data_flow.mermaid.svg @@ -0,0 +1 @@ +Display APIMQTT Task(Core 1)IMU_LATEST(Mutex)Main Loop(Core 0)IMU_CHANNEL[16 slots]MPU Task(Core 0)MPU6050 HardwareDisplay APIMQTT Task(Core 1)IMU_LATEST(Mutex)Main Loop(Core 0)IMU_CHANNEL[16 slots]MPU Task(Core 0)MPU6050 HardwareEvery 50msalt[Channel full][Channel has space]Continuous loopDrain queueloop[While available]Every 3 secondsalt[Mutex available][Mutex locked]alt[Time >= 3s since last]Continuous loopalt[Data available][No data]Read sensor (I2C)Raw dataConvert to ImuReadingtry_send(reading)Drop (log warning)OKreceive() [blocking]readingtry_receive()newer readingshow_imu(reading)[try_send]Format JSON payloadmqtt_set_imu()[try_lock]StoredSkiptry_lock()payloadsend_message("esp32/imu")None \ No newline at end of file diff --git a/tprais_semestralka1/docs/overall_system_architecture.mermaid b/tprais_semestralka1/docs/overall_system_architecture.mermaid new file mode 100644 index 0000000..799b3ce --- /dev/null +++ b/tprais_semestralka1/docs/overall_system_architecture.mermaid @@ -0,0 +1,42 @@ +graph TB + subgraph "Core 0 - Application" + MPU[MPU Task
50ms sampling] + DISPLAY[Display Task
100ms refresh] + MAIN[Main Loop] + BUTTONS[Button Task] + end + + subgraph "Core 1 - Network" + WIFI[WiFi Connection Task] + NETWORK[Network Stack Runner] + MQTT[MQTT Task] + end + + subgraph "Shared Channels" + IMU_CH[(IMU_CHANNEL
size: 16)] + DISP_CH[(DISPLAY_CHANNEL
size: 8)] + CMD_CH[(CMD_CHAN
size: 8)] + EVT_CH[(EVT_CHAN
size: 8)] + IMU_LATEST[(IMU_LATEST
Mutex)] + end + + subgraph "Hardware" + MPU_HW[MPU6050
I2C 0x68] + OLED[SSD1306
I2C] + BROKER[MQTT Broker] + end + + MPU_HW -->|I2C Read| MPU + MPU -->|send| IMU_CH + IMU_CH -->|receive| MAIN + MAIN -->|try_send| DISP_CH + MAIN -->|mqtt_set_imu| IMU_LATEST + DISP_CH -->|receive| DISPLAY + DISPLAY -->|I2C Write| OLED + IMU_LATEST -->|try_lock| MQTT + MQTT <-->|TCP/IP| BROKER + BUTTONS -->|push_key| DISP_CH + + style IMU_CH fill:#ff9999 + style DISP_CH fill:#99ccff + style IMU_LATEST fill:#ffcc99 diff --git a/tprais_semestralka1/docs/overall_system_architecture.mermaid.svg b/tprais_semestralka1/docs/overall_system_architecture.mermaid.svg new file mode 100644 index 0000000..08a3328 --- /dev/null +++ b/tprais_semestralka1/docs/overall_system_architecture.mermaid.svg @@ -0,0 +1 @@ +

Hardware

Shared Channels

Core 1 - Network

Core 0 - Application

I2C Read

send

receive

try_send

mqtt_set_imu

receive

I2C Write

try_lock

TCP/IP

push_key

MPU Task
50ms sampling

Display Task
100ms refresh

Main Loop

Button Task

WiFi Connection Task

Network Stack Runner

MQTT Task

IMU_CHANNEL
size: 16

DISPLAY_CHANNEL
size: 8

CMD_CHAN
size: 8

EVT_CHAN
size: 8

IMU_LATEST
Mutex

MPU6050
I2C 0x68

SSD1306
I2C

MQTT Broker

\ No newline at end of file diff --git a/tprais_semestralka1/expanded.rs b/tprais_semestralka1/expanded.rs new file mode 100644 index 0000000..e69de29 diff --git a/tprais_semestralka1/old_main.rs b/tprais_semestralka1/old_main.rs new file mode 100644 index 0000000..7e4b2df --- /dev/null +++ b/tprais_semestralka1/old_main.rs @@ -0,0 +1,181 @@ +// src/bin/main.rs + +#![no_std] +#![no_main] +#![deny( + clippy::mem_forget, + reason = "mem::forget is generally not safe to do with esp_hal types" +)] + +use embassy_executor::Spawner; +use embassy_futures::select::{select, Either}; +use embassy_net::{Runner, StackResources}; +use embassy_time::{Duration, Timer}; +use esp_alloc as _; +use esp_backtrace as _; +use esp_hal::{clock::CpuClock, rng::Rng, timer::timg::TimerGroup}; +use esp_wifi::{ + init, + wifi::{ClientConfiguration, Configuration, WifiController, WifiDevice, WifiEvent, WifiState}, + EspWifiController, +}; +use log::info; +use rust_mqtt::packet::v5::publish_packet::QualityOfService; +use projekt_final::mqtt::client::{ + mqtt_events, mqtt_publish, mqtt_subscribe, mqtt_task, IncomingMsg, +}; +use defmt_rtt as _; + +extern crate alloc; + +esp_bootloader_esp_idf::esp_app_desc!(); + +macro_rules! mk_static { + ($t:ty,$val:expr) => {{ + static STATIC_CELL: static_cell::StaticCell<$t> = static_cell::StaticCell::new(); + #[deny(unused_attributes)] + let x = STATIC_CELL.uninit().write(($val)); + x + }}; +} + +const SSID: &str = env!("SSID"); +const PASSWORD: &str = env!("PASSWORD"); + +#[esp_hal_embassy::main] +async fn main(spawner: Spawner) -> ! { + esp_println::logger::init_logger_from_env(); + let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max()); + let peripherals = esp_hal::init(config); + + esp_alloc::heap_allocator!(size: 72 * 1024); + + let timg0 = TimerGroup::new(peripherals.TIMG0); + let mut rng = Rng::new(peripherals.RNG); + + let esp_wifi_ctrl = &*mk_static!( + EspWifiController<'static>, + init(timg0.timer0, rng.clone()).unwrap() + ); + + let (controller, interfaces) = + esp_wifi::wifi::new(&esp_wifi_ctrl, peripherals.WIFI).unwrap(); + + let wifi_interface = interfaces.sta; + + let timg1 = TimerGroup::new(peripherals.TIMG1); + esp_hal_embassy::init(timg1.timer0); + + let config = embassy_net::Config::dhcpv4(Default::default()); + + let seed = (rng.random() as u64) << 32 | rng.random() as u64; + + // Init network stack + let (stack, runner) = embassy_net::new( + wifi_interface, + config, + mk_static!(StackResources<3>, StackResources::<3>::new()), + seed, + ); + + spawner.spawn(connection(controller)).ok(); + spawner.spawn(net_task(runner)).ok(); + + // Wait for link up + loop { + if stack.is_link_up() { + break; + } + Timer::after(Duration::from_millis(500)).await; + } + + info!("Waiting to get IP address..."); + loop { + if let Some(config) = stack.config_v4() { + info!("Got IP: {}", config.address); + break; + } + Timer::after(Duration::from_millis(500)).await; + } + + spawner.spawn(mqtt_task(stack)).expect("failed to spawn MQTT task"); + info!("MQTT task started"); + + mqtt_publish("esp32/topic", b"hello from ESP32 (init)", QualityOfService::QoS1, false).await; + info!("Sent initial MQTT message"); + + mqtt_subscribe("esp32/topic").await; + + // Get a receiver for incoming MQTT messages + let mqtt_rx = mqtt_events(); + + loop { + // Drive both: either process an MQTT message or publish periodically + match select(mqtt_rx.receive(), Timer::after(Duration::from_secs(5))).await + { + // Received inbound MQTT message (from broker) + Either::First(msg) => { + handle_incoming(msg); + } + // Time-based example publish + Either::Second(_) => { + // mqtt_publish( + // "esp32/topic", + // b"hello from main", + // QualityOfService::QoS1, + // false, + // ) + // .await; + } + } + } +} + +fn handle_incoming(msg: IncomingMsg) { + if let Ok(txt) = core::str::from_utf8(&msg.payload) { + info!("MAIN RX [{}]: {}", msg.topic.as_str(), txt); + info!("Received MQTT message -> topic: '{}', payload: '{}'", msg.topic.as_str(), txt); + } else { + info!("MAIN RX [{}]: {:?}", msg.topic.as_str(), msg.payload); + } +} + +#[embassy_executor::task] +async fn connection(mut controller: WifiController<'static>) { + info!("start connection task"); + info!("Device capabilities: {:?}", controller.capabilities()); + loop { + match esp_wifi::wifi::wifi_state() { + WifiState::StaConnected => { + controller.wait_for_event(WifiEvent::StaDisconnected).await; + Timer::after(Duration::from_millis(5000)).await + } + _ => {} + } + if !matches!(controller.is_started(), Ok(true)) { + let client_config = Configuration::Client(ClientConfiguration { + ssid: SSID.into(), + password: PASSWORD.into(), + ..Default::default() + }); + controller.set_configuration(&client_config).unwrap(); + info!("Starting wifi"); + controller.start_async().await.unwrap(); + info!("Wifi started!"); + } + info!("About to connect..."); + + match controller.connect_async().await { + Ok(_) => info!("Wifi connected!"), + Err(e) => { + info!("Failed to connect to wifi: {e:?}"); + Timer::after(Duration::from_millis(5000)).await + } + } + } +} + +#[embassy_executor::task] +async fn net_task(mut runner: Runner<'static, WifiDevice<'static>>) { + runner.run().await +} diff --git a/tprais_semestralka1/rust-toolchain.toml b/tprais_semestralka1/rust-toolchain.toml new file mode 100644 index 0000000..a2f5ab5 --- /dev/null +++ b/tprais_semestralka1/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "esp" diff --git a/tprais_semestralka1/src/bin/main.rs b/tprais_semestralka1/src/bin/main.rs new file mode 100644 index 0000000..7c9f8a5 --- /dev/null +++ b/tprais_semestralka1/src/bin/main.rs @@ -0,0 +1,293 @@ +// src/bin/main.rs + +#![no_std] +#![no_main] +#![deny( + clippy::mem_forget, + reason = "mem::forget is generally not safe to do with esp_hal types" +)] +// TODO WARNING core 1 should be logic, core 0 wifi, its flipped now + +use embassy_executor::Spawner; +use embassy_futures::select::{select, Either, select3, Either3}; +use embassy_net::{Runner, StackResources}; +use embassy_sync::signal::Signal; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use embassy_time::{Duration, Timer, Instant}; +use projekt_final::bus::I2cInner; +use projekt_final::mqtt::client; + +use esp_alloc as _; +use esp_backtrace as _; + +use esp_hal::{ + gpio::InputConfig, + clock::CpuClock, + gpio::{Input, Pull}, + i2c::master::{Config as I2cConfig, I2c}, + rng::Rng, + system::{CpuControl, Stack}, + timer::timg::TimerGroup, +}; +use esp_wifi::{ + wifi::{ClientConfiguration, Configuration, WifiController, WifiDevice, WifiEvent, WifiState}, + EspWifiController, +}; + +use pages_tui::input::Key; +use log::info; +use rust_mqtt::packet::v5::publish_packet::QualityOfService; +use static_cell::StaticCell; +use core::cell::RefCell; +use heapless::String; +use core::fmt::Write; + +use projekt_final::{ + bus, + display, + mpu, + mqtt::client::{mqtt_events, mqtt_try_publish, mqtt_publish, mqtt_subscribe, mqtt_task, IncomingMsg}, +}; + +extern crate alloc; +use alloc::format; + +static I2C_BUS: StaticCell> = StaticCell::new(); +static APP_CORE_STACK: StaticCell> = StaticCell::new(); +static EXECUTOR_CORE1: StaticCell = StaticCell::new(); +static NETWORK_READY: Signal = Signal::new(); + +macro_rules! mk_static { + ($t:ty,$val:expr) => {{ + static STATIC_CELL: static_cell::StaticCell<$t> = static_cell::StaticCell::new(); + #[deny(unused_attributes)] + let x = STATIC_CELL.uninit().write(($val)); + x + }}; +} + +const SSID: &str = env!("SSID"); +const PASSWORD: &str = env!("PASSWORD"); +const MQTT_PUBLISH_DIVIDER: u32 = 10; + +esp_bootloader_esp_idf::esp_app_desc!(); + +#[esp_hal_embassy::main] +async fn main(spawner: Spawner) -> ! { + esp_println::logger::init_logger_from_env(); + info!("==============================="); + info!(" ESP32 IoT Firmware Starting"); + info!("==============================="); + + let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max()); + let peripherals = esp_hal::init(config); + esp_alloc::heap_allocator!(size: 72 * 1024); + + info!("Initializing I2C bus..."); + let i2c = I2c::new(peripherals.I2C0, I2cConfig::default()) + .expect("Failed to create I2C instance") + .with_sda(peripherals.GPIO21) + .with_scl(peripherals.GPIO22) + .into_async(); + + let i2c_bus = I2C_BUS.init(RefCell::new(i2c)); + let display_i2c = bus::new_device(i2c_bus); + let mpu_i2c = bus::new_device(i2c_bus); + + info!("Initializing WiFi..."); + let timg0 = TimerGroup::new(peripherals.TIMG0); + let mut rng = Rng::new(peripherals.RNG); + + let esp_wifi_ctrl = mk_static!( + EspWifiController<'static>, + esp_wifi::init(timg0.timer0, rng.clone()).unwrap() + ); + + let (controller, interfaces) = + esp_wifi::wifi::new(esp_wifi_ctrl, peripherals.WIFI).unwrap(); + + let wifi_interface = interfaces.sta; + let timg1 = TimerGroup::new(peripherals.TIMG1); + esp_hal_embassy::init([timg1.timer0, timg1.timer1]); + + let seed = (rng.random() as u64) << 32 | rng.random() as u64; + + // Start core 1 for WiFi and MQTT (network stack created there) + let mut cpu_control = CpuControl::new(peripherals.CPU_CTRL); + let _guard = cpu_control.start_app_core( + APP_CORE_STACK.init(Stack::new()), + move || { + let executor = EXECUTOR_CORE1.init(esp_hal_embassy::Executor::new()); + executor.run(|spawner| { + spawner.spawn(core1_network_task(spawner, controller, wifi_interface, seed)).ok(); + }); + } + ).unwrap(); + + // Wait for network to be ready (signaled from core 1) + NETWORK_READY.wait().await; + info!("Network ready, starting core 0 tasks"); + + let config = InputConfig::default().with_pull(Pull::Down); + let button_select = Input::new(peripherals.GPIO32, config); + let button_next = Input::new(peripherals.GPIO35, config); + spawner.spawn(button_detection_task(button_select, button_next)).unwrap(); + + // Core 0: display and MPU tasks + spawner.spawn(display::task::display_task(display_i2c)).expect("spawn display_task"); + spawner.spawn(mpu::task::mpu_task(mpu_i2c)).expect("spawn mpu_task"); + + display::api::set_status("Booting...").await; + mqtt_subscribe("esp32/read").await; + mqtt_publish("esp32/imu", b"online", QualityOfService::QoS1, false).await; + + display::api::set_status("Running").await; + display::api::set_mqtt_status(true, 0).await; + + let mqtt_rx = mqtt_events(); + let imu_rx = mpu::api::events(); + let mut imu_reading_count: u32 = 0; + let mut mqtt_msg_count: u32 = 0; + let mut mqtt_publish_drops: u32 = 0; + let mut last_mqtt_publish = Instant::now(); + let mqtt_publish_interval = Duration::from_secs(3); + + loop { + match select3( + mqtt_rx.receive(), + imu_rx.receive(), + Timer::after(Duration::from_secs(5)), + ).await { + Either3::First(msg) => { + mqtt_msg_count += 1; + handle_mqtt_message(msg).await; + display::api::set_mqtt_status(true, mqtt_msg_count).await; + } + Either3::Second(mut reading) => { + // Drain zabezpečuje, že 'reading' je najčerstvejšia možná hodnota + let mut drained = 0; + while let Ok(next) = imu_rx.try_receive() { + reading = next; + drained += 1; + } + + imu_reading_count += 1; + display::api::show_imu(reading); + + // 3. Nahraďte pôvodnú podmienku týmto časovým zámkom + if last_mqtt_publish.elapsed() >= mqtt_publish_interval { + let payload = client::encode_imu_json(&reading); + client::mqtt_set_imu_payload(payload); + last_mqtt_publish = Instant::now(); + } + } + Either3::Third(_) => { + crate::mpu::api::IMU_CHANNEL.clear(); + info!("IMU heartbeat: force-cleared queue, {} readings total, {} mqtt drops", + imu_reading_count, mqtt_publish_drops); + } + } + } +} + +// Runs on core 1 - creates and owns the network stack +#[embassy_executor::task] +async fn core1_network_task( + spawner: Spawner, + controller: WifiController<'static>, + wifi_interface: WifiDevice<'static>, + seed: u64, +) { + spawner.spawn(connection_task(controller)).ok(); + + let net_config = embassy_net::Config::dhcpv4(Default::default()); + let (stack, runner) = embassy_net::new( + wifi_interface, + net_config, + mk_static!(StackResources<3>, StackResources::<3>::new()), + seed, + ); + + spawner.spawn(net_task(runner)).ok(); + + // Wait for network + loop { + if stack.is_link_up() { break; } + Timer::after(Duration::from_millis(500)).await; + } + loop { + if let Some(config) = stack.config_v4() { + info!("Got IP: {}", config.address); + break; + } + Timer::after(Duration::from_millis(500)).await; + } + + // Signal core 0 that network is ready + NETWORK_READY.signal(()); + + spawner.spawn(mqtt_task(stack)).ok(); +} + +async fn handle_mqtt_message(msg: IncomingMsg) { + if let Ok(txt) = core::str::from_utf8(&msg.payload) { + match txt { + "clear" => { display::api::clear().await; } + "status" => { mqtt_publish("esp32/status", b"running", QualityOfService::QoS1, false).await; } + _ => { display::api::add_chat_message(txt).await; } + } + } +} + +#[embassy_executor::task] +async fn connection_task(mut controller: WifiController<'static>) { + loop { + if esp_wifi::wifi::wifi_state() == WifiState::StaConnected { + controller.wait_for_event(WifiEvent::StaDisconnected).await; + Timer::after(Duration::from_millis(5000)).await; + } + if !matches!(controller.is_started(), Ok(true)) { + let client_config = Configuration::Client(ClientConfiguration { + ssid: SSID.into(), + password: PASSWORD.into(), + ..Default::default() + }); + controller.set_configuration(&client_config).unwrap(); + info!("Wi-Fi starting..."); + controller.start_async().await.unwrap(); + } + match controller.connect_async().await { + Ok(_) => info!("Wifi connected!"), + Err(e) => { + info!("Failed to connect to wifi: {e:#?}"); + Timer::after(Duration::from_millis(5000)).await + } + } + } +} + +#[embassy_executor::task] +async fn net_task(mut runner: Runner<'static, WifiDevice<'static>>) { + runner.run().await +} + +#[embassy_executor::task] +async fn button_detection_task(mut select_btn: Input<'static>, mut next_btn: Input<'static>) { + loop { + match select( + select_btn.wait_for_rising_edge(), + next_btn.wait_for_rising_edge(), + ).await { + Either::First(_) => { + info!("Detection: GPIO 32 (Select) triggered!"); + display::api::push_key(Key::enter()).await; + } + Either::Second(_) => { + info!("Detection: GPIO 35 (Next) triggered!"); + display::api::push_key(Key::tab()).await + } + } + // Debounce: prevent mechanical bouncing from double-triggering + embassy_time::Timer::after(embassy_time::Duration::from_millis(200)).await; + } +} diff --git a/tprais_semestralka1/src/lib.rs b/tprais_semestralka1/src/lib.rs new file mode 100644 index 0000000..0087e1d --- /dev/null +++ b/tprais_semestralka1/src/lib.rs @@ -0,0 +1,4 @@ +#![no_std] +extern crate alloc; + +pub mod mqtt; diff --git a/tprais_semestralka1/src/mqtt/client.rs b/tprais_semestralka1/src/mqtt/client.rs new file mode 100644 index 0000000..a7d2f8b --- /dev/null +++ b/tprais_semestralka1/src/mqtt/client.rs @@ -0,0 +1,442 @@ +// src/mqtt/client.rs + +use embassy_net::{tcp::TcpSocket, Stack}; +use embassy_time::{Duration, Timer, Instant}; +use embassy_futures::select::{select, Either}; +use rust_mqtt::client::client::MqttClient; +use rust_mqtt::client::client_config::{ClientConfig, MqttVersion}; +use rust_mqtt::packet::v5::publish_packet::QualityOfService; +use rust_mqtt::packet::v5::reason_codes::ReasonCode; +use rust_mqtt::utils::rng_generator::CountingRng; + +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use embassy_sync::mutex::Mutex; +use embassy_sync::channel::{Channel, Receiver}; +use embassy_sync::signal::Signal; +use heapless::{String, Vec}; +use static_cell::ConstStaticCell; +use core::fmt::Write; +use log::{info, warn}; + +use crate::mqtt::config::mqtt_broker_endpoint; +use crate::contracts::ImuReading; + +const RECONNECT_DELAY_SECS: u64 = 5; +const KEEPALIVE_SECS: u64 = 60; +const PING_PERIOD: Duration = Duration::from_secs(KEEPALIVE_SECS / 2); +const SOCKET_POLL_TIMEOUT: Duration = Duration::from_secs(1); +const PING_TIMEOUT: Duration = Duration::from_secs(5); +// Must be > PING_PERIOD, ideally > KEEPALIVE +const NO_SUCCESS_TIMEOUT: Duration = Duration::from_secs(120); +const NO_IMU_SIG_WARN: Duration = Duration::from_secs(10); +const SUBS_MAX: usize = 8; + +// Limits for static buffers +pub const TOPIC_MAX: usize = 128; +pub const PAYLOAD_MAX: usize = 512; +const COMMAND_QUEUE: usize = 8; +const EVENT_QUEUE: usize = 8; + +// TCP socket buffers (for embassy-net TcpSocket) +static TCP_RX_BUFFER: ConstStaticCell<[u8; 2048]> = ConstStaticCell::new([0; 2048]); +static TCP_TX_BUFFER: ConstStaticCell<[u8; 2048]> = ConstStaticCell::new([0; 2048]); + +// MQTT client buffers (separate from the TcpSocket buffers) +static MQTT_TX_BUF: ConstStaticCell<[u8; 1024]> = ConstStaticCell::new([0; 1024]); +static MQTT_RX_BUF: ConstStaticCell<[u8; 1024]> = ConstStaticCell::new([0; 1024]); + +// Tie TcpSocket lifetime to session +type Client<'a, 'net> = MqttClient<'a, TcpSocket<'net>, 8, CountingRng>; + +#[derive(Clone)] +pub struct IncomingMsg { + pub topic: String, + pub payload: Vec, +} + +#[derive(Clone)] +struct PublishMsg { + topic: String, + payload: Vec, + qos: QualityOfService, + retain: bool, +} + +#[derive(Clone)] +enum Command { + Publish(PublishMsg), + Subscribe(String), +} + +// Command/info channels +static CMD_CHAN: Channel = Channel::new(); +static EVT_CHAN: Channel = Channel::new(); + +/// Latest-value + wake-up semantics for IMU publish payload (single consumer: MQTT task) +static IMU_SIG: Signal> = Signal::new(); + +static SUBS: Mutex, SUBS_MAX>> = + Mutex::new(Vec::new()); + +/// Public API + +pub async fn mqtt_publish(topic: &str, payload: &[u8], qos: QualityOfService, retain: bool) { + CMD_CHAN + .send(Command::Publish(PublishMsg { + topic: truncate_str::(topic), + payload: truncate_payload(payload), + qos, + retain, + })) + .await; +} + +pub fn mqtt_try_publish(topic: &str, payload: &[u8], qos: QualityOfService, retain: bool) -> bool { + CMD_CHAN + .try_send(Command::Publish(PublishMsg { + topic: truncate_str::(topic), + payload: truncate_payload(payload), + qos, + retain, + })) + .is_ok() +} + +pub fn mqtt_set_imu(reading: ImuReading) { + // Encode JSON into a bounded buffer (no alloc::format!) + let payload = encode_imu_json(&reading); + IMU_SIG.signal(payload); +} + +pub fn mqtt_set_imu_payload(payload: Vec) { + IMU_SIG.signal(payload); +} + +pub fn encode_imu_json(reading: &ImuReading) -> Vec { + let mut s: String<256> = String::new(); + let _ = write!( + &mut s, + "{{\"ax\":{:.2},\"ay\":{:.2},\"az\":{:.2},\"gx\":{:.1},\"gy\":{:.1},\"gz\":{:.1},\"t\":{:.1},\"ts\":{}}}", + reading.accel_g[0], reading.accel_g[1], reading.accel_g[2], + reading.gyro_dps[0], reading.gyro_dps[1], reading.gyro_dps[2], + reading.temp_c, + reading.timestamp_ms + ); + let mut v: Vec = Vec::new(); + let _ = v.extend_from_slice(s.as_bytes()); + v +} + +pub async fn mqtt_subscribe(topic: &str) { + let t = truncate_str::(topic); + { + let mut subs = SUBS.lock().await; + let exists = subs.iter().any(|s| s.as_str() == t.as_str()); + if !exists { + let _ = subs.push(t.clone()); + } + } + CMD_CHAN.send(Command::Subscribe(t)).await; +} + +pub fn mqtt_events( +) -> Receiver<'static, CriticalSectionRawMutex, IncomingMsg, EVENT_QUEUE> { + EVT_CHAN.receiver() +} + +/// Internals + +fn truncate_str(s: &str) -> String { + let mut h = String::new(); + if N == 0 { + return h; + } + if s.len() <= N { + let _ = h.push_str(s); + return h; + } + + let mut cut = N; + while cut > 0 && !s.is_char_boundary(cut) { + cut -= 1; + } + let _ = h.push_str(&s[..cut]); + h +} + +fn truncate_payload(data: &[u8]) -> Vec { + let mut v = Vec::new(); + let _ = v.extend_from_slice(&data[..data.len().min(PAYLOAD_MAX)]); + v +} + +async fn handle_command(client: &mut Client<'_, '_>, cmd: Command) -> Result<(), ReasonCode> { + match cmd { + Command::Publish(msg) => { + client + .send_message(msg.topic.as_str(), &msg.payload, msg.qos, msg.retain) + .await + } + Command::Subscribe(topic) => { + let res = client.subscribe_to_topic(topic.as_str()).await; + if res.is_ok() { + info!("Subscribed to '{}'", topic); + } + res + } + } +} + +async fn handle_incoming(result: Result<(&str, &[u8]), ReasonCode>) -> Result<(), ReasonCode> { + let (topic, payload) = result?; + let msg = IncomingMsg { + topic: truncate_str::(topic), + payload: truncate_payload(payload), + }; + if EVT_CHAN.try_send(msg).is_err() { + warn!("MQTT EVT queue full, dropping incoming message"); + } + Ok(()) +} + +async fn run_one_session( + stack: Stack<'static>, + tcp_rx: &mut [u8], + tcp_tx: &mut [u8], + mqtt_tx: &mut [u8], + mqtt_rx: &mut [u8], +) -> Result<(), ()> { + let mut socket = TcpSocket::new(stack, tcp_rx, tcp_tx); + socket.set_timeout(Some(SOCKET_POLL_TIMEOUT * 10)); + match socket.connect(mqtt_broker_endpoint()).await { + Ok(_) => info!("Connected TCP to MQTT broker"), + Err(e) => { + info!("TCP connect failed: {:#?}", e); + return Err(()); + } + } + + let mut cfg: ClientConfig<8, CountingRng> = + ClientConfig::new(MqttVersion::MQTTv5, CountingRng(0)); + cfg.keep_alive = KEEPALIVE_SECS as u16; + cfg.add_client_id("esp32-client"); + + let mut client = + MqttClient::new(socket, mqtt_tx, mqtt_tx.len(), mqtt_rx, mqtt_rx.len(), cfg); + + match client.connect_to_broker().await { + Ok(_) => info!("MQTT CONNACK received"), + Err(reason) => { + info!("MQTT connect failed: {:?}", reason); + return Err(()); + } + } + + // Re-subscribe after every (re)connect + let mut subs_snapshot: Vec, SUBS_MAX> = Vec::new(); + { + let subs = SUBS.lock().await; + for t in subs.iter() { + let _ = subs_snapshot.push(t.clone()); + } + } + for t in subs_snapshot.iter() { + match client.subscribe_to_topic(t.as_str()).await { + Ok(_) => info!("Subscribed to '{}'", t), + Err(e) => { + warn!("MQTT resubscribe failed: {:?}", e); + return Err(()); + } + } + } + + let mut next_ping_at = Instant::now() + PING_PERIOD; + let cmd_rx = CMD_CHAN.receiver(); + + // Only restart the session after N consecutive IMU publish failures + let mut imu_tx_fail_streak: u8 = 0; + let mut hb_at = Instant::now() + Duration::from_secs(10); + let mut tx_ok: u32 = 0; + let mut tx_err: u32 = 0; + let mut rx_ok: u32 = 0; + let mut ping_ok: u32 = 0; + let mut last_ok = Instant::now(); // last successful MQTT I/O (tx/rx/ping) + let mut last_imu_sig = Instant::now(); // last time we received IMU_SIG in MQTT task + + loop { + let now = Instant::now(); + + if now - last_ok > NO_SUCCESS_TIMEOUT { + warn!( + "MQTT no successful I/O for {:?} -> restart session", + now - last_ok + ); + return Err(()); + } + + if now - last_imu_sig > NO_IMU_SIG_WARN { + // This is diagnostic: if core0 claims it's sending, but this prints, you have cross-core signaling loss. + warn!( + "MQTT hasn't received IMU_SIG for {:?} (core0->core1 sync likely broken)", + now - last_imu_sig + ); + // Rate-limit the warning + last_imu_sig = now; + } + + let ping_in = if next_ping_at > now { next_ping_at - now } else { Duration::from_secs(0) }; + + // Timebox receive_message() even if lower layers misbehave. + let recv_fut = async { + match select(client.receive_message(), Timer::after(SOCKET_POLL_TIMEOUT)).await { + Either::First(res) => Some(res), + Either::Second(_) => None, + } + }; + + // 4-way select using nested selects to avoid relying on select4() + match select( + select(cmd_rx.receive(), IMU_SIG.wait()), + select(recv_fut, Timer::after(ping_in)), + ) + .await + { + // Command received + Either::First(Either::First(cmd)) => { + handle_command(&mut client, cmd).await.map_err(|_| ())?; + next_ping_at = Instant::now() + PING_PERIOD; + last_ok = Instant::now(); + + // Drain any additional queued commands quickly + while let Ok(cmd) = CMD_CHAN.try_receive() { + handle_command(&mut client, cmd).await.map_err(|_| ())?; + last_ok = Instant::now(); + next_ping_at = Instant::now() + PING_PERIOD; + } + } + + // IMU update signaled (latest value semantics) + Either::First(Either::Second(payload)) => { + last_imu_sig = Instant::now(); + // Enable temporarily for diagnostics: + // info!("IMU_SIG received in MQTT task (len={})", payload.len()); + + // Timebox the publish so we don't hang forever inside send_message().await + let send_res = match select( + client.send_message("esp32/imu", &payload, QualityOfService::QoS0, false), + Timer::after(Duration::from_secs(5)), + ) + .await + { + Either::First(res) => res, + Either::Second(_) => Err(ReasonCode::NetworkError), + }; + + match send_res { + Ok(_) => { + next_ping_at = Instant::now() + PING_PERIOD; + imu_tx_fail_streak = 0; + last_ok = Instant::now(); + + tx_ok = tx_ok.wrapping_add(1); + if (tx_ok % 10) == 0 { + info!( + "MQTT alive: tx_ok={} tx_err={} rx_ok={} streak={}", + tx_ok, tx_err, rx_ok, imu_tx_fail_streak + ); + } + } + Err(e) => { + tx_err = tx_err.wrapping_add(1); + imu_tx_fail_streak = imu_tx_fail_streak.saturating_add(1); + warn!("MQTT IMU TX fail {}/5: {:?}", imu_tx_fail_streak, e); + + if imu_tx_fail_streak >= 5 { + warn!("MQTT IMU TX fail 5x -> restart session"); + return Err(()); + } + } + } + } + + // Incoming message (or None on timeout) + Either::Second(Either::First(opt)) => { + if let Some(res) = opt { + match res { + Ok((topic, payload)) => { + rx_ok = rx_ok.wrapping_add(1); + let _ = handle_incoming(Ok((topic, payload))).await; + + last_ok = Instant::now(); + imu_tx_fail_streak = 0; + next_ping_at = Instant::now() + PING_PERIOD; + } + Err(ReasonCode::NetworkError) => { + // idle tick + } + Err(e) => { + warn!("MQTT receive error (fatal): {:?}", e); + return Err(()); + } + } + } + } + + // Ping timer fired + Either::Second(Either::Second(_)) => { + if Instant::now() >= hb_at { + info!( + "MQTT hb tx_ok={} tx_err={} rx_ok={} ping_ok={} streak={}", + tx_ok, tx_err, rx_ok, ping_ok, imu_tx_fail_streak + ); + hb_at = Instant::now() + Duration::from_secs(10); + } + + let ping_res = match select(client.send_ping(), Timer::after(PING_TIMEOUT)).await { + Either::First(res) => res, + Either::Second(_) => Err(ReasonCode::NetworkError), + }; + + match ping_res { + Ok(_) => { + ping_ok = ping_ok.wrapping_add(1); + imu_tx_fail_streak = 0; + last_ok = Instant::now(); + next_ping_at = Instant::now() + PING_PERIOD; + } + Err(e) => { + warn!("MQTT ping failed/timeout: {:?}", e); + return Err(()); + } + } + } + } + } +} + +#[embassy_executor::task] +pub async fn mqtt_task(stack: Stack<'static>) { + info!("MQTT task starting..."); + + let tcp_rx = TCP_RX_BUFFER.take(); + let tcp_tx = TCP_TX_BUFFER.take(); + let mqtt_tx = MQTT_TX_BUF.take(); + let mqtt_rx = MQTT_RX_BUF.take(); + + loop { + let _ = run_one_session( + stack, + &mut tcp_rx[..], + &mut tcp_tx[..], + &mut mqtt_tx[..], + &mut mqtt_rx[..], + ) + .await; + + info!( + "Reconnecting in {}s after session end/failure", + RECONNECT_DELAY_SECS + ); + Timer::after(Duration::from_secs(RECONNECT_DELAY_SECS)).await; + } +} diff --git a/tprais_semestralka1/src/mqtt/config.rs b/tprais_semestralka1/src/mqtt/config.rs new file mode 100644 index 0000000..c20d357 --- /dev/null +++ b/tprais_semestralka1/src/mqtt/config.rs @@ -0,0 +1,122 @@ +// src/mqtt/config.rs +#![allow(dead_code)] + +use embassy_net::{IpAddress, Ipv4Address, Ipv6Address}; + +// Compile-time values injected by build.rs +const BROKER_IP: &str = env!("BROKER_IP"); +const BROKER_PORT: &str = env!("BROKER_PORT"); + +pub fn mqtt_broker_endpoint() -> (IpAddress, u16) { + (parse_ip(BROKER_IP), parse_port(BROKER_PORT)) +} + +fn parse_port(s: &str) -> u16 { + let p: u16 = s + .parse() + .unwrap_or_else(|_| panic!("BROKER_PORT must be a valid u16 (1..=65535)")); + assert!(p != 0, "BROKER_PORT cannot be 0"); + p +} + +fn parse_ip(s: &str) -> IpAddress { + if s.contains(':') { + IpAddress::Ipv6(parse_ipv6(s)) + } else { + IpAddress::Ipv4(parse_ipv4(s)) + } +} + +fn parse_ipv4(s: &str) -> Ipv4Address { + let mut it = s.split('.'); + let a = parse_octet(it.next(), 1); + let b = parse_octet(it.next(), 2); + let c = parse_octet(it.next(), 3); + let d = parse_octet(it.next(), 4); + assert!(it.next().is_none(), "Too many IPv4 octets"); + Ipv4Address::new(a, b, c, d) +} + +fn parse_octet(part: Option<&str>, idx: usize) -> u8 { + let p = part.unwrap_or_else(|| panic!("IPv4 missing octet {}", idx)); + let v: u16 = p + .parse() + .unwrap_or_else(|_| panic!("Invalid IPv4 octet {}: {}", idx, p)); + assert!(v <= 255, "IPv4 octet {} out of range: {}", idx, v); + v as u8 +} + +// Minimal IPv6 parser with '::' compression. Does not handle IPv4-embedded IPv6. +fn parse_ipv6(s: &str) -> Ipv6Address { + assert!( + !s.contains('.'), + "IPv4-embedded IPv6 like ::ffff:192.0.2.1 not supported; \ + use pure hex IPv6" + ); + + let has_double = s.contains("::"); + let (left_s, right_s) = if has_double { + let mut sp = s.splitn(2, "::"); + (sp.next().unwrap_or(""), sp.next().unwrap_or("")) + } else { + (s, "") + }; + + let mut left = [0u16; 8]; + let mut right = [0u16; 8]; + let mut ll = 0usize; + let mut rl = 0usize; + + if !left_s.is_empty() { + for part in left_s.split(':') { + left[ll] = parse_group(part); + ll += 1; + assert!(ll <= 8, "Too many IPv6 groups on the left"); + } + } + + if !right_s.is_empty() { + for part in right_s.split(':') { + right[rl] = parse_group(part); + rl += 1; + assert!(rl <= 8, "Too many IPv6 groups on the right"); + } + } + + let zeros = if has_double { + assert!(ll + rl < 8, "Invalid IPv6 '::' usage"); + 8 - (ll + rl) + } else { + assert!(ll == 8, "IPv6 must have 8 groups without '::'"); + 0 + }; + + let mut g = [0u16; 8]; + let mut idx = 0usize; + + for i in 0..ll { + g[idx] = left[i]; + idx += 1; + } + for _ in 0..zeros { + g[idx] = 0; + idx += 1; + } + for i in 0..rl { + g[idx] = right[i]; + idx += 1; + } + assert!(idx == 8, "IPv6 did not resolve to 8 groups"); + + Ipv6Address::new(g[0], g[1], g[2], g[3], g[4], g[5], g[6], g[7]) +} + +fn parse_group(part: &str) -> u16 { + assert!( + !part.is_empty(), + "Empty IPv6 group (use '::' instead for compression)" + ); + assert!(part.len() <= 4, "IPv6 group too long: {}", part); + u16::from_str_radix(part, 16) + .unwrap_or_else(|_| panic!("Invalid IPv6 hex group: {}", part)) +} diff --git a/tprais_semestralka1/src/mqtt/mod.rs b/tprais_semestralka1/src/mqtt/mod.rs new file mode 100644 index 0000000..ef0bd6d --- /dev/null +++ b/tprais_semestralka1/src/mqtt/mod.rs @@ -0,0 +1,4 @@ +// src/mqtt/mod.rs + +pub mod client; +pub mod config;