events: rewrite how sensor statuses are reported, and implement some oled UI icons for it

This commit is contained in:
2025-11-08 12:04:22 +01:00
parent a36fe3d1ac
commit 092885f163
24 changed files with 845 additions and 111 deletions

595
Cargo.lock generated
View File

@@ -8,6 +8,41 @@ version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
[[package]]
name = "aead"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"
dependencies = [
"crypto-common",
"generic-array 0.14.7",
]
[[package]]
name = "aes"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
dependencies = [
"cfg-if",
"cipher",
"cpufeatures",
]
[[package]]
name = "aes-gcm"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1"
dependencies = [
"aead",
"aes",
"cipher",
"ctr",
"ghash",
"subtle",
]
[[package]]
name = "aligned-vec"
version = "0.6.4"
@@ -61,6 +96,27 @@ version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
[[package]]
name = "as-slice"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45403b49e3954a4b8428a0ac21a4b7afadccf92bfd96273f1a58cd4812496ae0"
dependencies = [
"generic-array 0.12.4",
"generic-array 0.13.3",
"generic-array 0.14.7",
"stable_deref_trait",
]
[[package]]
name = "atomic-polyfill"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4"
dependencies = [
"critical-section",
]
[[package]]
name = "autocfg"
version = "1.5.0"
@@ -96,6 +152,18 @@ version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973"
[[package]]
name = "base16ct"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf"
[[package]]
name = "base64"
version = "0.21.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
[[package]]
name = "basic-toml"
version = "0.1.10"
@@ -137,6 +205,12 @@ dependencies = [
"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.9.4"
@@ -189,6 +263,15 @@ dependencies = [
"uuid",
]
[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
"generic-array 0.14.7",
]
[[package]]
name = "bt-hci"
version = "0.3.2"
@@ -199,7 +282,17 @@ dependencies = [
"embedded-io",
"embedded-io-async",
"futures-intrusive",
"heapless",
"heapless 0.8.0",
]
[[package]]
name = "buffered-io"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5698b2eda4613b62f3aa3119805df1ca6739e00167a2600b3a234ac49b14803"
dependencies = [
"embedded-io",
"embedded-io-async",
]
[[package]]
@@ -275,12 +368,37 @@ dependencies = [
"num-traits",
]
[[package]]
name = "cipher"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
dependencies = [
"crypto-common",
"inout",
]
[[package]]
name = "color_quant"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
[[package]]
name = "const-oid"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
[[package]]
name = "cpufeatures"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
dependencies = [
"libc",
]
[[package]]
name = "crc32fast"
version = "1.5.0"
@@ -327,13 +445,25 @@ version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
[[package]]
name = "crypto-bigint"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76"
dependencies = [
"generic-array 0.14.7",
"rand_core 0.6.4",
"subtle",
"zeroize",
]
[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"generic-array 0.14.7",
"typenum",
]
@@ -358,6 +488,15 @@ dependencies = [
"memchr",
]
[[package]]
name = "ctr"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835"
dependencies = [
"cipher",
]
[[package]]
name = "darling"
version = "0.20.11"
@@ -438,13 +577,25 @@ dependencies = [
"syn 2.0.106",
]
[[package]]
name = "der"
version = "0.7.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb"
dependencies = [
"const-oid",
"zeroize",
]
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
"subtle",
]
[[package]]
@@ -491,6 +642,25 @@ version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
[[package]]
name = "elliptic-curve"
version = "0.13.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47"
dependencies = [
"base16ct",
"crypto-bigint",
"digest",
"ff",
"generic-array 0.14.7",
"group",
"hkdf",
"rand_core 0.6.4",
"sec1",
"subtle",
"zeroize",
]
[[package]]
name = "embassy-embedded-hal"
version = "0.3.2"
@@ -582,6 +752,23 @@ 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",
"managed",
"smoltcp",
]
[[package]]
name = "embassy-net-driver"
version = "0.2.0"
@@ -599,7 +786,7 @@ dependencies = [
"embedded-io-async",
"futures-sink",
"futures-util",
"heapless",
"heapless 0.8.0",
]
[[package]]
@@ -613,7 +800,7 @@ dependencies = [
"embedded-io-async",
"futures-core",
"futures-sink",
"heapless",
"heapless 0.8.0",
]
[[package]]
@@ -665,7 +852,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc55c748d16908a65b166d09ce976575fb8852cf60ccd06174092b41064d8f83"
dependencies = [
"embassy-executor",
"heapless",
"heapless 0.8.0",
]
[[package]]
@@ -761,6 +948,25 @@ 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"
@@ -776,6 +982,48 @@ dependencies = [
"embedded-storage",
]
[[package]]
name = "embedded-tls"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6efb76fdd004a4ef787640177237b83449e6c5847765ea50bf15900061fd601"
dependencies = [
"aes-gcm",
"atomic-polyfill",
"digest",
"embedded-io",
"embedded-io-async",
"generic-array 0.14.7",
"heapless 0.6.1",
"heapless 0.8.0",
"hkdf",
"hmac",
"p256",
"rand_core 0.6.4",
"sha2",
"typenum",
]
[[package]]
name = "enum-map"
version = "2.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6866f3bfdf8207509a033af1a75a7b08abda06bbaaeae6669323fd5a097df2e9"
dependencies = [
"enum-map-derive",
]
[[package]]
name = "enum-map-derive"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.106",
]
[[package]]
name = "enumset"
version = "1.1.10"
@@ -846,7 +1094,7 @@ dependencies = [
"cfg-if",
"esp-config",
"esp-println",
"heapless",
"heapless 0.8.0",
"semihosting",
]
@@ -885,7 +1133,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3887eda2917deef3d99e7a5c324f9190714e99055361ad36890dffd0a995b49"
dependencies = [
"bitfield 0.19.2",
"bitflags",
"bitflags 2.9.4",
"bytemuck",
"cfg-if",
"critical-section",
@@ -1040,6 +1288,18 @@ dependencies = [
"esp-metadata-generated",
]
[[package]]
name = "esp-storage"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f276ad8a3bdc6b47cd92a3e91013f2e42dce9b3fc5023392063387a1ce2ed69a"
dependencies = [
"critical-section",
"document-features",
"embedded-storage",
"esp-rom-sys",
]
[[package]]
name = "esp-synopsys-usb-otg"
version = "0.4.2"
@@ -1055,9 +1315,9 @@ dependencies = [
[[package]]
name = "esp-wifi"
version = "0.15.0"
version = "0.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84908f2e95cb99a200cf448abafc416576338be590778a15d9224eee237f3210"
checksum = "69336f3f30938a644077d2a9747e3cd325436dcaf57d9dc8d58f139e02104889"
dependencies = [
"allocator-api2",
"bt-hci",
@@ -1079,6 +1339,7 @@ dependencies = [
"portable-atomic",
"portable_atomic_enum",
"rand_core 0.9.3",
"smoltcp",
"xtensa-lx-rt",
]
@@ -1212,6 +1473,16 @@ dependencies = [
"simd-adler32",
]
[[package]]
name = "ff"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393"
dependencies = [
"rand_core 0.6.4",
"subtle",
]
[[package]]
name = "figments"
version = "0.0.2"
@@ -1361,6 +1632,24 @@ version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a"
[[package]]
name = "generic-array"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd"
dependencies = [
"typenum",
]
[[package]]
name = "generic-array"
version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f797e67af32588215eaaab8327027ee8e71b9dd0b2b26996aedf20c030fce309"
dependencies = [
"typenum",
]
[[package]]
name = "generic-array"
version = "0.14.7"
@@ -1369,6 +1658,7 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
"zeroize",
]
[[package]]
@@ -1394,6 +1684,16 @@ dependencies = [
"wasip2",
]
[[package]]
name = "ghash"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1"
dependencies = [
"opaque-debug",
"polyval",
]
[[package]]
name = "gif"
version = "0.13.3"
@@ -1404,6 +1704,17 @@ dependencies = [
"weezl",
]
[[package]]
name = "group"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63"
dependencies = [
"ff",
"rand_core 0.6.4",
"subtle",
]
[[package]]
name = "half"
version = "2.7.1"
@@ -1415,6 +1726,15 @@ dependencies = [
"zerocopy",
]
[[package]]
name = "hash32"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4041af86e63ac4298ce40e5cca669066e75b6f1aa3390fe2561ffa5e1d9f4cc"
dependencies = [
"byteorder",
]
[[package]]
name = "hash32"
version = "0.3.1"
@@ -1426,9 +1746,21 @@ dependencies = [
[[package]]
name = "hashbrown"
version = "0.15.5"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d"
[[package]]
name = "heapless"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "634bd4d29cbf24424d0a4bfcbf80c6960129dc24424752a7d1d1390607023422"
dependencies = [
"as-slice",
"generic-array 0.14.7",
"hash32 0.1.1",
"stable_deref_trait",
]
[[package]]
name = "heapless"
@@ -1436,7 +1768,7 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad"
dependencies = [
"hash32",
"hash32 0.3.1",
"stable_deref_trait",
]
@@ -1446,6 +1778,36 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "hkdf"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7"
dependencies = [
"hmac",
]
[[package]]
name = "hmac"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
dependencies = [
"digest",
]
[[package]]
name = "httparse"
version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
[[package]]
name = "ident_case"
version = "1.0.1"
@@ -1494,13 +1856,14 @@ checksum = "e7c5cedc30da3a610cac6b4ba17597bdf7152cf974e8aab3afb3d54455e371c8"
[[package]]
name = "indexmap"
version = "2.11.1"
version = "2.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "206a8042aec68fa4a62e8d3f7aa4ceb508177d9324faf261e1959e495b7a1921"
checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f"
dependencies = [
"equivalent",
"hashbrown",
"serde",
"serde_core",
]
[[package]]
@@ -1509,6 +1872,15 @@ version = "2.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd"
[[package]]
name = "inout"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01"
dependencies = [
"generic-array 0.14.7",
]
[[package]]
name = "instability"
version = "0.3.9"
@@ -1646,11 +2018,10 @@ dependencies = [
[[package]]
name = "lock_api"
version = "0.4.13"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765"
checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
dependencies = [
"autocfg",
"scopeguard",
]
@@ -1669,6 +2040,12 @@ dependencies = [
"imgref",
]
[[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"
@@ -1799,7 +2176,7 @@ dependencies = [
"arrayvec",
"cfg-if",
"chrono",
"heapless",
"heapless 0.8.0",
"nom",
"num-traits",
]
@@ -1820,6 +2197,12 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8"
[[package]]
name = "nourl"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa07b0722c63805057dec824444fdc814bdfd30d1c782a3a8f63bbcf67c4ed1c"
[[package]]
name = "num"
version = "0.4.3"
@@ -1919,6 +2302,22 @@ version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]]
name = "opaque-debug"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
[[package]]
name = "p256"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b"
dependencies = [
"elliptic-curve",
"primeorder",
]
[[package]]
name = "paste"
version = "1.0.15"
@@ -1949,13 +2348,25 @@ version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97baced388464909d42d89643fe4361939af9b7ce7a31ee32a168f832a70f2a0"
dependencies = [
"bitflags",
"bitflags 2.9.4",
"crc32fast",
"fdeflate",
"flate2",
"miniz_oxide",
]
[[package]]
name = "polyval"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25"
dependencies = [
"cfg-if",
"cpufeatures",
"opaque-debug",
"universal-hash",
]
[[package]]
name = "portable-atomic"
version = "1.11.1"
@@ -2002,12 +2413,21 @@ dependencies = [
]
[[package]]
name = "proc-macro-crate"
version = "3.3.0"
name = "primeorder"
version = "0.13.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35"
checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6"
dependencies = [
"toml_edit",
"elliptic-curve",
]
[[package]]
name = "proc-macro-crate"
version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983"
dependencies = [
"toml_edit 0.23.7",
]
[[package]]
@@ -2068,7 +2488,7 @@ version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "679341d22c78c6c649893cbd6c3278dcbe9fc4faa62fea3a9296ae2b50c14625"
dependencies = [
"bitflags",
"bitflags 2.9.4",
"memchr",
"unicase",
]
@@ -2240,10 +2660,14 @@ dependencies = [
"display-interface",
"embassy-embedded-hal 0.5.0",
"embassy-executor",
"embassy-net",
"embassy-sync 0.7.2",
"embassy-time 0.5.0",
"embedded-graphics",
"embedded-hal-async",
"embedded-storage",
"enum-map",
"enumset",
"esp-alloc",
"esp-backtrace",
"esp-bootloader-esp-idf",
@@ -2251,6 +2675,7 @@ dependencies = [
"esp-hal-embassy",
"esp-hal-smartled",
"esp-println",
"esp-storage",
"esp-wifi",
"figments",
"figments-render",
@@ -2261,14 +2686,37 @@ dependencies = [
"mpu6050-dmp",
"nalgebra 0.33.2",
"nmea",
"reqwless",
"rgb",
"rmp",
"smart-leds",
"smoltcp",
"ssd1306",
"static_cell",
"xtensa-lx-rt",
]
[[package]]
name = "reqwless"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb1be74cb817fa6dbda417110f575d9b9ad5488817f1eb65f2f6468fe6d5d663"
dependencies = [
"base64",
"buffered-io",
"embedded-io",
"embedded-io-async",
"embedded-nal-async",
"embedded-tls",
"heapless 0.8.0",
"hex",
"httparse",
"log",
"nourl",
"rand_chacha",
"rand_core 0.6.4",
]
[[package]]
name = "rgb"
version = "0.8.52"
@@ -2332,8 +2780,6 @@ dependencies = [
[[package]]
name = "rmp"
version = "0.8.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4"
dependencies = [
"byteorder",
"num-traits",
@@ -2358,6 +2804,19 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "sec1"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc"
dependencies = [
"base16ct",
"der",
"generic-array 0.14.7",
"subtle",
"zeroize",
]
[[package]]
name = "semihosting"
version = "0.1.20"
@@ -2416,6 +2875,17 @@ dependencies = [
"unsafe-libyaml",
]
[[package]]
name = "sha2"
version = "0.10.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "shlex"
version = "1.3.0"
@@ -2485,6 +2955,19 @@ dependencies = [
"rgb",
]
[[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",
"managed",
]
[[package]]
name = "ssd1306"
version = "0.10.0"
@@ -2542,6 +3025,12 @@ dependencies = [
"syn 2.0.106",
]
[[package]]
name = "subtle"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
name = "syn"
version = "1.0.109"
@@ -2634,8 +3123,8 @@ checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
"toml_edit",
"toml_datetime 0.6.11",
"toml_edit 0.22.27",
]
[[package]]
@@ -2647,6 +3136,15 @@ dependencies = [
"serde",
]
[[package]]
name = "toml_datetime"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533"
dependencies = [
"serde_core",
]
[[package]]
name = "toml_edit"
version = "0.22.27"
@@ -2656,7 +3154,28 @@ dependencies = [
"indexmap",
"serde",
"serde_spanned",
"toml_datetime",
"toml_datetime 0.6.11",
"winnow",
]
[[package]]
name = "toml_edit"
version = "0.23.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d"
dependencies = [
"indexmap",
"toml_datetime 0.7.3",
"toml_parser",
"winnow",
]
[[package]]
name = "toml_parser"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e"
dependencies = [
"winnow",
]
@@ -2684,6 +3203,16 @@ version = "1.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d"
[[package]]
name = "universal-hash"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea"
dependencies = [
"crypto-common",
"subtle",
]
[[package]]
name = "unsafe-libyaml"
version = "0.2.11"
@@ -2696,7 +3225,7 @@ version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98816b1accafbb09085168b90f27e93d790b4bfa19d883466b5e53315b5f06a6"
dependencies = [
"heapless",
"heapless 0.8.0",
"portable-atomic",
]
@@ -2916,6 +3445,12 @@ dependencies = [
"syn 2.0.106",
]
[[package]]
name = "zeroize"
version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
[[package]]
name = "zune-core"
version = "0.4.12"

View File

@@ -66,6 +66,8 @@ nalgebra = { version = "0.33.2", default-features = false, features = ["alloc",
xtensa-lx-rt = { version = "*", features = ["float-save-restore"] }
futures = { version = "0.3.31", default-features = false, features = ["async-await"] }
micromath = "2.1.0"
enumset = "1.1.10"
enum-map = "2.7.3"
# Telemetry outputs
esp-wifi = { version = "0.15.0", optional = true, features = [

7
assets/blank-icon.pbm Normal file
View File

@@ -0,0 +1,7 @@
P1
# Created by GIMP version 3.0.6 PNM plug-in
16 16
0000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000

7
assets/demo.pbm Normal file
View File

@@ -0,0 +1,7 @@
P1
# Created by GIMP version 3.0.6 PNM plug-in
16 16
1100000000000000101000000000000010100000000000001010111000000000101010
0000000000101010000000000011001100101000000000100011100000000010001110
0000000011101010111000000000101010100000000010101010000000001010101000
0000000000101000000000000010100000000000001110

View File

@@ -1,7 +1,7 @@
P1
# Created by GIMP version 3.0.4 PNM plug-in
# Created by GIMP version 3.0.6 PNM plug-in
16 16
0100001111000010111001000010011101111011110111100011111001111100000111
0000111000000111100111100000010111111010000000101111010000000010111101
0000000001111110000000001110011100000001111001111000001110100101110001
1100011000111011100001100001110100000000000010
0000000000000000011000000000011001111000000011100011110000011100001111
1000111000001011110111000001000111111000000100001111000000010000111110
0000001001111111000000101110011110000001110000111100001110000001110001
1101100011111001100001110001100000000000000000

View File

@@ -1,7 +1,7 @@
P1
# Created by GIMP version 3.0.4 PNM plug-in
# Created by GIMP version 3.0.6 PNM plug-in
16 16
0000001111000000000001111110000000001111111100000001111001111000000111
0000111000000111000011100000011110011110000000111111110000000011111111
0000000001111110000000000111111000000000001111000000000000111100000000
0000011000000000000001100000000000000000000000
0000000000000000000000000000101000001000000001000001110000011010001111
1000111000001111110111000001111111111000000111111111000000011111111110
0000001111111111000000111111111110000001111111111100000011111111100000
0001111111000000000001110000000000000000000000

View File

@@ -0,0 +1,7 @@
P1
# Created by GIMP version 3.0.6 PNM plug-in
16 16
0000000000000000000000000000000000000001100000000000000110000000000000
0110000000000000011000000000000001100000000000111111110000000001111110
0000000000111100000011100001100001110001110000111000000000111100000011
1000000000011100011100001110000000001111000000

View File

@@ -0,0 +1,7 @@
P1
# Created by GIMP version 3.0.6 PNM plug-in
16 16
0000000110000000000001111110000000001110011100000000110000110000000000
0000110000000000001110000000000001110000000000000110000000000000000000
0000000000011000000011100001100001110001110000111000000000111100000011
1000000000011100011100001110000000001111000000

7
assets/location-off.pbm Normal file
View File

@@ -0,0 +1,7 @@
P1
# Created by GIMP version 3.0.4 PNM plug-in
16 16
0100001111000010111001000010011101111011110111100011111001111100000111
0000111000000111100111100000010111111010000000101111010000000010111101
0000000001111110000000001110011100000001111001111000001110100101110001
1100011000111011100001100001110100000000000010

7
assets/location-on.pbm Normal file
View File

@@ -0,0 +1,7 @@
P1
# Created by GIMP version 3.0.4 PNM plug-in
16 16
0000001111000000000001111110000000001111111100000001111001111000000111
0000111000000111000011100000011110011110000000111111110000000011111111
0000000001111110000000000111111000000000001111000000000000111100000000
0000011000000000000001100000000000000000000000

7
assets/offline.pbm Normal file
View File

@@ -0,0 +1,7 @@
P1
# Created by GIMP version 3.0.6 PNM plug-in
16 16
0111000000000000101010000000000011011000000000001010100000000000011100
0000000000001001100000011000100111000011100010001110011100001000011111
1000001000001111000000100000111100000010000111111000001000111001110000
1001110000111000100110000001100010000000000000

View File

@@ -0,0 +1,7 @@
P1
# Created by GIMP version 3.0.6 PNM plug-in
16 16
0111000000000000101010000000000011011000000000001010100000000000011100
0000000000001000100000000000100101000000000010001000000000001001010000
0000001000100010000000100101010100000010001000100000001001010101001000
1000100010010100100101010100100010001000100101

7
assets/online-full.pbm Normal file
View File

@@ -0,0 +1,7 @@
P1
# Created by GIMP version 3.0.6 PNM plug-in
16 16
0111000000000000101010000000000011011000000000001010100000000000011100
0000000000001001110000000000100111000000000010011100000000001001110000
0000001001110111000000100111011100000010011101110000001001110111011100
1001110111011100100111011101110010011101110111

View File

@@ -0,0 +1,7 @@
P1
# Created by GIMP version 3.0.6 PNM plug-in
16 16
0111000000000000101010000000000011011000000000001010100000000000011100
0000000000001000100000000000100101000000000010001000000000001001010000
0000001000100111000000100101011100000010001001110000001001010111011100
1000100111011100100101011101110010001001110111

View File

@@ -0,0 +1,7 @@
P1
# Created by GIMP version 3.0.6 PNM plug-in
16 16
0111000000000000101010000000000011011000000000001010100000000000011100
0000000000001000100000000000100101000000000010001000000000001001010000
0000001000100010000000100101010100000010001000100000001001010101011100
1000100010011100100101010101110010001000100111

7
assets/tape.pbm Normal file
View File

@@ -0,0 +1,7 @@
P1
# Created by GIMP version 3.0.6 PNM plug-in
16 16
0000000000000000000000000000000000000000000000001111111111111111100000
0000000001101000000000010110001111111100011001011111101001100011111111
0001100000000000000110100111111001011000100000010001111111111111111100
0000000000000000000000000000000000000000000000

View File

@@ -5,7 +5,7 @@ use log::*;
use core::fmt::Debug;
use crate::{ego::{heading::HeadingEstimator, kalman::Ekf2D, orientation::OrientationEstimator}, events::{Notification, Prediction}, idle::IdleClock, Breaker, CircularBuffer};
use crate::{Breaker, CircularBuffer, ego::{heading::HeadingEstimator, kalman::Ekf2D, orientation::OrientationEstimator}, events::{Notification, Prediction, SensorSource, SensorState}, idle::IdleClock};
#[derive(PartialEq, Debug, Default, Clone, Copy)]
pub enum MotionState {
@@ -28,8 +28,10 @@ pub struct BikeStates {
reference_fix: Option<Vector2<f64>>, // The first GPS value, which is used to make sense out of the EKF output which is in meters offset from this point
// State switches
is_calibrated: Breaker<bool>,
has_down: Breaker<bool>,
has_forwards: Breaker<bool>,
motion_state: Breaker<MotionState>,
acquiring_data: Breaker<bool>,
// FIXME: pub
pub has_gps_fix: Breaker<bool>,
predicted_velocity: Breaker<f32>,
@@ -55,6 +57,7 @@ impl Debug for BikeStates {
impl BikeStates {
pub fn insert_gps(&mut self, gps_pos: Vector2<f64>) {
self.acquiring_data.set(true);
match self.reference_fix {
None => {
self.reference_fix = Some(gps_pos);
@@ -77,6 +80,7 @@ impl BikeStates {
}
pub fn insert_imu(&mut self, accel: Vector3<f32>, gyro: Vector3<f32>) {
self.acquiring_data.set(true);
self.orientation.insert(accel);
if self.orientation.has_down() {
@@ -98,19 +102,33 @@ impl BikeStates {
self.kf.update_zupt();
}
self.is_calibrated.set(true);
self.has_down.set(true);
if self.orientation.is_ready() {
self.has_forwards.set(true);
}
}
}
pub async fn commit(&mut self, predictions: &DynamicSender<'static, Prediction>, notifications: &DynPublisher<'static, Notification>) {
if let Some(true) = self.is_calibrated.read_tripped() {
notifications.publish(Notification::SensorOnline(crate::events::SensorSource::IMU)).await
if let Some(true) = self.acquiring_data.read_tripped() {
notifications.publish(Notification::SensorStatus(SensorSource::ForwardsReference, SensorState::AcquiringFix)).await;
notifications.publish(Notification::SensorStatus(SensorSource::GravityReference, SensorState::AcquiringFix)).await;
notifications.publish(Notification::SensorStatus(SensorSource::Location, SensorState::AcquiringFix)).await;
}
if let Some(true) = self.has_down.read_tripped() {
notifications.publish(Notification::SensorStatus(SensorSource::GravityReference, SensorState::Online)).await
}
if let Some(true) = self.has_forwards.read_tripped() {
notifications.publish(Notification::SensorStatus(SensorSource::ForwardsReference, SensorState::Online)).await
}
match self.has_gps_fix.read_tripped() {
None => (),
Some(true) => notifications.publish(Notification::SensorOnline(crate::events::SensorSource::GPS)).await,
Some(false) => notifications.publish(Notification::SensorOffline(crate::events::SensorSource::GPS)).await,
Some(true) => notifications.publish(Notification::SensorStatus(SensorSource::Location, SensorState::Online)).await,
Some(false) => notifications.publish(Notification::SensorStatus(SensorSource::Location, SensorState::Degraded)).await,
}
let est = self.kf.x;
@@ -182,7 +200,8 @@ impl Default for BikeStates {
last_stamp: Instant::now(),
speedo: Default::default(),
heading: Default::default(),
is_calibrated: Default::default(),
has_down: Default::default(),
has_forwards: Default::default(),
kf: Default::default(),
steady_timer: IdleClock::new(Duration::from_secs(3)),
last_fix: Default::default(),
@@ -191,7 +210,8 @@ impl Default for BikeStates {
predicted_location: Default::default(),
predicted_velocity: Default::default(),
reported_velocity: Default::default(),
wake_requested: Default::default()
wake_requested: Default::default(),
acquiring_data: Default::default()
}
}
}

View File

@@ -1,6 +1,8 @@
use embassy_sync::{blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex}, channel::Channel, pubsub::PubSubChannel};
use embassy_time::Duration;
use enum_map::Enum;
use enumset::EnumSetType;
use nalgebra::{Vector2, Vector3};
use crate::{graphics::display::DisplayControls, ego::engine::MotionState};
@@ -14,6 +16,22 @@ pub enum Scene {
Idle, // Default state when waking up from sleep, or entered when accelerometers and GPS both show zero motion for ~30 seconds
}
#[derive(Clone, Copy, Default, Debug)]
pub enum SensorState {
#[default]
// There is no connection to the sensor
Offline,
// Sensor is starting up
AcquiringFix,
// Sensor is ready and is generating data
Online,
// Sensor was previously fully functioning but currently is not (eg, gps fix lost)
Degraded,
}
#[derive(Clone, Copy, Debug)]
pub enum Measurement {
// GPS coordinates
@@ -22,8 +40,7 @@ pub enum Measurement {
IMU { accel: Vector3<f32>, gyro: Vector3<f32> },
// Hardware status updates
SensorOnline(SensorSource),
SensorOffline(SensorSource),
SensorHardwareStatus(SensorSource, SensorState),
// Simulation metadata updates
SimulationProgress(SensorSource, Duration, f32)
@@ -43,12 +60,7 @@ pub enum Notification {
SceneChange(Scene),
// States of external connections to the world
SensorOnline(SensorSource),
SensorOffline(SensorSource),
// TODO: Should be emitted by the prediction engine after it doesn't get any sensor data for some time. Perhaps the threads are somehow deadlocked and a reboot is needed if it doesn't recover
SensorsOffline,
SensorStatus(SensorSource, SensorState),
// The prediction engine has decided that the system should be woken up and begin running again
WakeUp,
// The prediction engine has decided that the system is inactive enough and it should go to low-power sleep
@@ -68,10 +80,20 @@ pub enum Telemetry {
Prediction(Prediction),
}
#[derive(Clone, Copy, Debug)]
#[derive(Debug, EnumSetType, Enum)]
pub enum SensorSource {
// Real hardware
IMU,
GPS
GPS,
// Fusion outputs
GravityReference,
ForwardsReference,
Location,
// Simulated sensors
Demo,
Simulation
}
#[derive(Debug)]

View File

@@ -1,14 +1,15 @@
use core::f32::consts::PI;
use core::fmt::Binary;
use alloc::format;
use embedded_graphics::image::ImageRaw;
use embedded_graphics::mono_font::ascii::*;
use embedded_graphics::mono_font::{MonoTextStyle, MonoTextStyleBuilder};
use embedded_graphics::pixelcolor::BinaryColor;
use embedded_graphics::prelude::Size;
use embedded_graphics::prelude::{DrawTarget, Size};
use embedded_graphics::primitives::{Line, PrimitiveStyle, PrimitiveStyleBuilder, StyledDrawable};
use embedded_graphics::text::{Alignment, Text};
use embedded_graphics::{image::Image, prelude::Point, Drawable};
use enum_map::EnumMap;
use figments::liber8tion::trig::sin8;
use figments::mappings::embedded_graphics::Matrix2DSpace;
use figments::{liber8tion::trig::cos8, mappings::embedded_graphics::EmbeddedGraphicsSampler};
@@ -17,6 +18,7 @@ use nalgebra::Vector2;
use micromath::F32Ext;
use embedded_graphics::geometry::OriginDimensions;
use crate::events::{SensorSource, SensorState};
use crate::graphics::images;
use crate::{ego::engine::MotionState, events::Scene};
@@ -26,8 +28,7 @@ pub struct OledUI {
pub motion: MotionState,
pub brakelight: bool,
pub headlight: bool,
pub gps_online: bool,
pub imu_online: bool,
pub sensor_states: EnumMap<SensorSource, SensorState>,
pub velocity: f32,
pub location: Vector2<f64>,
pub sleep: bool,
@@ -50,6 +51,90 @@ pub enum Screen {
Waking
}
struct SensorImage {
source: SensorSource,
on: &'static ImageRaw<'static, BinaryColor>,
off: &'static ImageRaw<'static, BinaryColor>,
}
struct SensorIcon<'a> {
anchor: embedded_graphics::geometry::Point,
image: &'a SensorImage,
state: SensorState,
frame: usize
}
impl<'a> SensorIcon<'a> {
pub const fn new(image: &'a SensorImage, state: SensorState, frame: usize, anchor: embedded_graphics::geometry::Point) -> Self {
Self {
anchor,
image,
state,
frame
}
}
pub fn draw<T: DrawTarget<Color = BinaryColor>>(&self, target: &mut T) -> Result<(), T::Error> {
match self.state {
SensorState::AcquiringFix => {
if (self.frame / 10) % 2 == 0 {
Image::new(self.image.off, self.anchor).draw(target)
} else {
Ok(())
}
},
SensorState::Online => {
Image::new(self.image.on, self.anchor).draw(target)
},
SensorState::Offline => {
Image::new(self.image.off, self.anchor).draw(target)
},
SensorState::Degraded => {
if (self.frame / 10) % 2 == 0 {
Image::new(self.image.on, self.anchor).draw(target)
} else {
Ok(())
}
}
}
}
}
const SENSOR_IMAGES: &[SensorImage] = &[
SensorImage {
source: SensorSource::GPS,
on: &images::GPS_ON, off: &images::GPS_OFF,
},
SensorImage {
source: SensorSource::IMU,
on: &images::IMU_ON, off: &images::IMU_OFF,
},
SensorImage {
source: SensorSource::GravityReference,
on: &images::GRAVITY_LOCATED, off: &images::GRAVITY_MISSING,
},
SensorImage {
source: SensorSource::Location,
on: &images::LOCATION_ON, off: &images::LOCATION_OFF,
},
#[cfg(feature="demo")]
SensorImage {
source: SensorSource::Demo,
on: &images::DEMO, off: &images::DEMO,
},
#[cfg(feature="simulation")]
SensorImage {
source: SensorSource::Simulation,
on: &images::TAPE, off: &images::TAPE
},
];
const DISPLAY_SIZE: Size = Size::new(128, 64);
const SENSOR_ICON_SIZE: u32 = 16;
const SENSOR_ICON_SPACING: u32 = 2;
const SENSOR_TRAY_SIZE: Size = Size::new(SENSOR_IMAGES.len() as u32 * (SENSOR_ICON_SIZE + SENSOR_ICON_SPACING), SENSOR_ICON_SIZE + SENSOR_ICON_SPACING);
const SPEEDO_TRAY_SIZE: Size = Size::new(DISPLAY_SIZE.width - SENSOR_TRAY_SIZE.width, SENSOR_TRAY_SIZE.height);
impl Screen {
pub fn draw_screen<'a, T>(&self, sampler: &mut EmbeddedGraphicsSampler<'a, T>, state: &OledUniforms) where T: Sample<'a, Matrix2DSpace>, T::Output: PixelSink<BinaryColor> {
match self {
@@ -74,36 +159,22 @@ impl Screen {
Screen::Home => {
// Status bar
// Sensor indicators
let gps_img = if state.ui.gps_online {
&images::GPS_ON
} else {
&images::GPS_OFF
};
let imu_img = if state.ui.imu_online {
&images::IMU_ON
} else {
&images::IMU_OFF
};
Image::new(gps_img, Point::zero()).draw(sampler).unwrap();
Image::new(imu_img, Point::new((gps_img.size().width + 2) as i32, 0)).draw(sampler).unwrap();
for (idx, sensor) in SENSOR_IMAGES.iter().enumerate() {
let offset = idx * (16 + 2);
let position = Point::new(offset as i32, 0);
SensorIcon::new(sensor, state.ui.sensor_states[sensor.source], state.frame, position)
.draw(sampler).unwrap();
}
#[cfg(feature="demo")]
Text::with_alignment("Demo", Point::new(128, 10), TEXT_STYLE, Alignment::Right)
.draw(sampler)
.unwrap();
let speedo_center = SENSOR_TRAY_SIZE.width + SPEEDO_TRAY_SIZE.width / 2;
#[cfg(feature="simulation")]
Text::with_alignment("Sim", Point::new(128, 10), TEXT_STYLE, Alignment::Right)
// Speed display at the top
Text::with_alignment(&format!("{}", state.ui.velocity), Point::new(speedo_center as i32, 12), SPEED_STYLE, Alignment::Center)
.draw(sampler)
.unwrap();
// Separates the status bar from the UI
Line::new(Point::new(0, 18), Point::new(128, 18)).draw_styled(&INACTIVE_STYLE, sampler).unwrap();
// Speed display at the top
Text::with_alignment(&format!("{}", state.ui.velocity), Point::new(128 / 2, 12), SPEED_STYLE, Alignment::Center)
.draw(sampler)
.unwrap();
Line::new(Point::new(0, SENSOR_TRAY_SIZE.height as i32), Point::new(128, SENSOR_TRAY_SIZE.height as i32)).draw_styled(&INACTIVE_STYLE, sampler).unwrap();
// The main UI content
Image::new(&images::BIKE, Point::new((128 / 2 - images::BIKE.size().width / 2) as i32, 24)).draw(sampler).unwrap();

View File

@@ -1,7 +1,7 @@
use embassy_sync::pubsub::DynPublisher;
use embassy_time::Timer;
use crate::events::{Notification, Scene};
use crate::events::{Notification, Scene, SensorSource, SensorState};
#[embassy_executor::task]
@@ -11,10 +11,16 @@ pub async fn demo_task(ui: DynPublisher<'static, Notification>) {
ui.publish(Notification::SetBrakelight(true)).await;
ui.publish(Notification::SetHeadlight(true)).await;
Timer::after_secs(10).await;
ui.publish(Notification::SensorStatus(SensorSource::Demo, SensorState::AcquiringFix)).await;
loop {
for scene in [Scene::Accelerating, Scene::Ready, Scene::Decelerating, Scene::Ready] {
Timer::after_secs(8).await;
ui.publish(Notification::SceneChange(scene)).await
};
ui.publish(Notification::SceneChange(scene)).await;
for state in [SensorState::Offline, SensorState::AcquiringFix, SensorState::Degraded, SensorState::Offline] {
for sensor in [SensorSource::ForwardsReference, SensorSource::GPS, SensorSource::GravityReference, SensorSource::IMU, SensorSource::Location] {
ui.publish(Notification::SensorStatus(sensor, state)).await;
}
Timer::after_secs(1).await;
}
}
}
}

View File

@@ -1,7 +1,7 @@
use embassy_sync::{channel::{DynamicReceiver, DynamicSender}, pubsub::DynPublisher};
use log::*;
use crate::{ego::engine::BikeStates, events::{Measurement, Notification, Prediction}};
use crate::{ego::engine::BikeStates, events::{Measurement, Notification, Prediction, SensorSource, SensorState}};
#[embassy_executor::task]
pub async fn motion_task(src: DynamicReceiver<'static, Measurement>, ui_sink: DynPublisher<'static, Notification>, prediction_sink: DynamicSender<'static, Prediction>) {
@@ -24,8 +24,10 @@ pub async fn motion_task(src: DynamicReceiver<'static, Measurement>, ui_sink: Dy
states.has_gps_fix.set(false);
},
// FIXME: This needs harmonized with the automatic data timeout from above, somehow?
Measurement::SensorOnline(source) => warn!("Sensor {source:?} reports online!"),
Measurement::SensorOffline(source) => warn!("Sensor {source:?} reports offline!"),
Measurement::SensorHardwareStatus(source, state) => {
warn!("Sensor {source:?} reports {state:?}!");
ui_sink.publish(Notification::SensorStatus(source, state)).await;
},
Measurement::SimulationProgress(source, duration, _pct) => debug!("{source:?} simulation time: {}", duration.as_secs()),
}
}

View File

@@ -31,7 +31,6 @@ fn gyro_raw_to_rads(raw: i16) -> f32 {
#[esp_hal::ram(rtc_fast, persistent)]
static mut MPU_WAS_CALIBRATED: u8 = 0;
//static mut MPU_CALIBRATION: Option<(Accel, Gyro)> = None;
#[embassy_executor::task]
pub async fn mpu_task(events: DynamicSender<'static, Measurement>, bus: I2cDevice<'static, CriticalSectionRawMutex, I2c<'static, Async>>) {
@@ -39,6 +38,7 @@ pub async fn mpu_task(events: DynamicSender<'static, Measurement>, bus: I2cDevic
let busref = RefCell::new(Some(bus));
backoff.forever().attempt::<_, (), ()>(async || {
events.send(Measurement::SensorHardwareStatus(SensorSource::IMU, crate::events::SensorState::Offline)).await;
let mut sensor = backoff.forever().attempt(async || {
warn!("Initializing connection to MPU");
match Mpu6050::new(busref.replace(None).unwrap(), Address::default()).await.map_err(|e| { e.i2c }) {
@@ -47,6 +47,7 @@ pub async fn mpu_task(events: DynamicSender<'static, Measurement>, bus: I2cDevic
Err(())
},
Ok(mut sensor) => {
events.send(Measurement::SensorHardwareStatus(SensorSource::IMU, crate::events::SensorState::AcquiringFix)).await;
match backoff.attempt(async || { mpu_init(&mut sensor).await }).await {
Err(_) => {
busref.replace(Some(sensor.release()));
@@ -60,7 +61,7 @@ pub async fn mpu_task(events: DynamicSender<'static, Measurement>, bus: I2cDevic
let sensor_ref = &mut sensor;
events.send(Measurement::SensorOnline(SensorSource::IMU)).await;
events.send(Measurement::SensorHardwareStatus(SensorSource::IMU, crate::events::SensorState::Online)).await;
//TODO: Need to read in a constant buffer of accelerometer measurements, which we can then use to determine where "forward" points in the body frame when converting from the sensor frame.
// From there, we can rotate the body frame into the world frame using gps headings to generate a compass north
fn lowpass(prev: f32, current: f32, alpha: f32) -> f32 {

View File

@@ -7,7 +7,7 @@ use figments::{mappings::embedded_graphics::Matrix2DSpace, prelude::{Coordinates
use figments_render::output::{Brightness, OutputAsync};
use log::*;
use crate::{animation::Animation, backoff::Backoff, events::{Notification, Prediction, SensorSource, Telemetry}, graphics::{display::DisplayControls, oled_ui::{OledUniforms, Screen}}};
use crate::{animation::Animation, backoff::Backoff, events::{Notification, Prediction, SensorSource, SensorState, Telemetry}, graphics::{display::DisplayControls, oled_ui::{OledUniforms, Screen}}};
#[cfg(feature="oled")]
pub type OledUiSurfacePool = BufferedSurfacePool<OledUniforms, Matrix2DSpace, BinaryColor>;
@@ -84,10 +84,7 @@ impl<S: core::fmt::Debug + Surface<CoordinateSpace = Matrix2DSpace, Pixel = Bina
Telemetry::Notification(Notification::SceneChange(scene)) => self.with_uniforms(|state| {state.ui.scene = scene}).await,
Telemetry::Notification(Notification::SetBrakelight(b)) => self.with_uniforms(|state| {state.ui.brakelight = b}).await,
Telemetry::Notification(Notification::SetHeadlight(b)) => self.with_uniforms(|state| {state.ui.headlight = b}).await,
Telemetry::Notification(Notification::SensorOffline(SensorSource::IMU)) => self.with_uniforms(|state| {state.ui.imu_online = false}).await,
Telemetry::Notification(Notification::SensorOnline(SensorSource::IMU)) => self.with_uniforms(|state| {state.ui.imu_online = true}).await,
Telemetry::Notification(Notification::SensorOffline(SensorSource::GPS)) => self.with_uniforms(|state| {state.ui.gps_online = false}).await,
Telemetry::Notification(Notification::SensorOnline(SensorSource::GPS)) => self.with_uniforms(|state| {state.ui.gps_online = true}).await,
Telemetry::Notification(Notification::SensorStatus(src, sensor_state)) => self.with_uniforms(|state| {state.ui.sensor_states[src] = sensor_state}).await,
_ => ()
}
}

View File

@@ -6,7 +6,7 @@ use core::fmt::Debug;
use futures::join;
use log::*;
use crate::{animation::{AnimatedSurface, Animation}, graphics::display::{SegmentSpace, Uniforms}, events::{Notification, Scene, SensorSource, Telemetry}, graphics::shaders::*};
use crate::{animation::{AnimatedSurface, Animation}, events::{Notification, Scene, SensorSource, SensorState, Telemetry}, graphics::{display::{SegmentSpace, Uniforms}, shaders::*}};
pub struct Ui<S: Surface> {
// Background layer provides an always-running background for everything to draw on
@@ -139,19 +139,13 @@ impl<S: Debug + Surface<Uniforms = Uniforms, CoordinateSpace = SegmentSpace, Pix
}
match event {
// TODO: We probably also want some events to indicate when the ESP has no calibration data or otherwise needs re-calibrated and is waiting for the bike to stand still
Notification::SensorOnline(SensorSource::IMU) => self.flash_notification_color(Rgb::new(0, 255, 0)).await,
Notification::SensorOffline(SensorSource::GPS) => self.flash_notification_color(Rgb::new(255, 0, 0)).await,
Notification::SensorOnline(SensorSource::GPS) => self.flash_notification_color(Rgb::new(0, 255, 255)).await,
Notification::SensorStatus(SensorSource::IMU, SensorState::Online) => self.flash_notification_color(Rgb::new(0, 255, 0)).await,
Notification::SensorStatus(SensorSource::Location, SensorState::Degraded) => self.flash_notification_color(Rgb::new(255, 0, 0)).await,
Notification::SensorStatus(SensorSource::GPS, SensorState::Online) => self.flash_notification_color(Rgb::new(0, 255, 255)).await,
// Scene change
Notification::SceneChange(scene) => self.apply_scene(scene).await,
Notification::SensorsOffline => {
self.flash_notification_color(Rgb::new(255, 0, 0)).await;
self.flash_notification_color(Rgb::new(0, 255, 0)).await;
self.flash_notification_color(Rgb::new(0, 0, 255)).await;
}
Notification::WakeUp => self.show().await,
_ => ()