diff --git a/.github/workflows/rust_ci.yaml b/.github/workflows/rust_ci.yaml index 1a44426..e56f746 100644 --- a/.github/workflows/rust_ci.yaml +++ b/.github/workflows/rust_ci.yaml @@ -20,11 +20,15 @@ jobs: matrix: action: - command: build - args: --no-default-features --target=riscv32imc-unknown-none-elf --release + args: --no-default-features --features v3 --target=riscv32imc-unknown-none-elf --release + - command: build + args: --no-default-features --features v4 --target=riscv32imc-unknown-none-elf --release - command: fmt args: --all -- --check --color always - command: clippy - args: --no-default-features --target=riscv32imc-unknown-none-elf --workspace -- -D warnings + args: --no-default-features --features v3 --target=riscv32imc-unknown-none-elf --workspace -- -D warnings + - command: clippy + args: --no-default-features --features v4 --target=riscv32imc-unknown-none-elf --workspace -- -D warnings steps: - name: Checkout repository uses: actions/checkout@v4 diff --git a/Cargo.lock b/Cargo.lock index 0decc63..defaba9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + [[package]] name = "adv-shift-registers" version = "0.2.5" @@ -56,6 +62,36 @@ dependencies = [ "embedded-hal-async", ] +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aligned" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee4508988c62edf04abd8d92897fca0c2995d907ce1dfeaf369dac3716a40685" +dependencies = [ + "as-slice 0.2.1", +] + +[[package]] +name = "aligned-vec" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b" +dependencies = [ + "equator", +] + [[package]] name = "allocator-api2" version = "0.3.1" @@ -68,6 +104,35 @@ version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" + +[[package]] +name = "arg_enum_proc_macro" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "arraydeque" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + [[package]] name = "as-slice" version = "0.1.5" @@ -80,12 +145,107 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "as-slice" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "516b6b4f0e40d50dcda9365d53964ec74560ad4284da2e7fc97122cd83174516" +dependencies = [ + "stable_deref_trait", +] + +[[package]] +name = "askama" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f75363874b771be265f4ffe307ca705ef6f3baa19011c149da8674a87f1b75c4" +dependencies = [ + "askama_derive", + "itoa", + "percent-encoding", + "serde", + "serde_json", +] + +[[package]] +name = "askama_derive" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "129397200fe83088e8a68407a8e2b1f826cf0086b21ccdb866a722c8bcd3a94f" +dependencies = [ + "askama_parser", + "memchr", + "proc-macro2", + "quote", + "rustc-hash", + "syn 2.0.117", +] + +[[package]] +name = "askama_parser" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6ab5630b3d5eaf232620167977f95eb51f3432fc76852328774afbd242d4358" +dependencies = [ + "memchr", + "winnow", +] + [[package]] name = "autocfg" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "av-scenechange" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f321d77c20e19b92c39e7471cf986812cbb46659d2af674adc4331ef3f18394" +dependencies = [ + "aligned", + "anyhow", + "arg_enum_proc_macro", + "arrayvec", + "log", + "num-rational", + "num-traits", + "pastey", + "rayon", + "thiserror", + "v_frame", + "y4m", +] + +[[package]] +name = "av1-grain" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cfddb07216410377231960af4fcab838eaa12e013417781b78bd95ee22077f8" +dependencies = [ + "anyhow", + "arrayvec", + "log", + "nom", + "num-rational", + "v_frame", +] + +[[package]] +name = "avif-serialize" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "375082f007bd67184fb9c0374614b29f9aaa604ec301635f72338bb65386a53d" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "az" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" + [[package]] name = "base16ct" version = "0.2.0" @@ -98,6 +258,12 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +[[package]] +name = "bit_field" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6" + [[package]] name = "bitfield" version = "0.19.4" @@ -130,6 +296,27 @@ version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +[[package]] +name = "bitstream-io" +version = "4.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60d4bd9d1db2c6bdf285e223a7fa369d5ce98ec767dec949c6ca62863ce61757" +dependencies = [ + "core2", +] + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -139,6 +326,22 @@ dependencies = [ "generic-array 0.14.7", ] +[[package]] +name = "bq27441" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "401a2308f1e83ceaaa9345f409759ac6e891259a4d909da8fb7332321ae428a4" +dependencies = [ + "defmt 0.3.100", + "device-driver", + "device-driver-generation", + "embedded-hal 1.0.0", + "embedded-hal-async", + "prettyplease", + "proc-macro2", + "syn 2.0.117", +] + [[package]] name = "bt-hci" version = "0.6.0" @@ -162,6 +365,18 @@ dependencies = [ "uuid", ] +[[package]] +name = "built" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4ad8f11f288f48ca24471bbd51ac257aaeaaa07adae295591266b792902ae64" + +[[package]] +name = "bumpalo" +version = "3.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" + [[package]] name = "bytemuck" version = "1.25.0" @@ -174,6 +389,24 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + +[[package]] +name = "cc" +version = "1.2.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + [[package]] name = "cfg-if" version = "1.0.4" @@ -201,6 +434,12 @@ dependencies = [ "digest", ] +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + [[package]] name = "const-default" version = "1.0.0" @@ -213,6 +452,15 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "convert_case" version = "0.8.0" @@ -222,6 +470,24 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "convert_case" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "affbf0190ed2caf063e3def54ff444b449371d55c58e513a95ab98eca50adb49" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "core2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505" +dependencies = [ + "memchr", +] + [[package]] name = "cpufeatures" version = "0.2.17" @@ -231,12 +497,52 @@ dependencies = [ "libc", ] +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + [[package]] name = "critical-section" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + [[package]] name = "crypto-bigint" version = "0.5.5" @@ -380,6 +686,58 @@ dependencies = [ "generic-array 0.14.7", ] +[[package]] +name = "dd-manifest-tree" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5793572036e0a6638977c7370c6afc423eac848ee8495f079b8fd3964de7b9f9" +dependencies = [ + "serde_json", + "toml", + "yaml-rust2", +] + +[[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.117", +] + +[[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.5" @@ -401,6 +759,47 @@ dependencies = [ "zeroize", ] +[[package]] +name = "device-driver" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3aa3d97b2acf349b9d52c75470e2ccfc7224c49597ec12c2fb0e28826e910495" +dependencies = [ + "defmt 0.3.100", + "device-driver-macros", + "embedded-io 0.6.1", + "embedded-io-async 0.6.1", +] + +[[package]] +name = "device-driver-generation" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d23ac9a75e0bba43928e1a50c7b1beaaa67a98b64eaa28f353a16de1a5fd985" +dependencies = [ + "anyhow", + "askama", + "bitvec", + "convert_case 0.6.0", + "dd-manifest-tree", + "itertools 0.14.0", + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "device-driver-macros" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dec62c8588239d60d7470326cd78ba2b264bef24f0afa20c666668487c843d03" +dependencies = [ + "device-driver-generation", + "proc-macro2", + "syn 2.0.117", +] + [[package]] name = "digest" version = "0.10.7" @@ -413,6 +812,23 @@ dependencies = [ "subtle", ] +[[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 = "dns-protocol" version = "0.1.2" @@ -650,9 +1066,51 @@ dependencies = [ name = "embedded-can" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9d2e857f87ac832df68fa498d18ddc679175cf3d2e4aa893988e5601baf9438" +checksum = "e9d2e857f87ac832df68fa498d18ddc679175cf3d2e4aa893988e5601baf9438" +dependencies = [ + "nb 1.1.0", +] + +[[package]] +name = "embedded-dma" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "994f7e5b5cb23521c22304927195f236813053eb9c065dd2226a32ba64695446" +dependencies = [ + "stable_deref_trait", +] + +[[package]] +name = "embedded-graphics" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e8da660bb0c829b34a56a965490597f82a55e767b91f9543be80ce8ccb416fe" +dependencies = [ + "az", + "byteorder", + "embedded-graphics-core", + "float-cmp", + "micromath", +] + +[[package]] +name = "embedded-graphics-core" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95743bef3ff70fcba3930246c4e6872882bbea0dcc6da2ca860112e0cd4bd09f" +dependencies = [ + "az", + "byteorder", +] + +[[package]] +name = "embedded-graphics-framebuf" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22354420f68727fa24d1e2741dae1e9a041065e80fb63b35a8d19c647a85be76" dependencies = [ - "nb 1.1.0", + "embedded-dma", + "embedded-graphics", ] [[package]] @@ -696,6 +1154,9 @@ name = "embedded-io" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" +dependencies = [ + "defmt 0.3.100", +] [[package]] name = "embedded-io" @@ -730,6 +1191,27 @@ dependencies = [ "embedded-io 0.7.1", ] +[[package]] +name = "embedded-layout" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a90553247f2b05c59ac7894ea13d830636c2b1203fa03bff400eddbd1fa9f52" +dependencies = [ + "embedded-graphics", + "embedded-layout-macros", +] + +[[package]] +name = "embedded-layout-macros" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f6e621fe4c7e05b695274b722dc0a60bacd1c8696b58191baa0154713d52400" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "embedded-nal" version = "0.9.0" @@ -764,6 +1246,17 @@ dependencies = [ "embedded-storage", ] +[[package]] +name = "embedded-text" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cf5c72c52db2f7dbe4a9c1ed81cd21301e8d66311b194fa41c04fb4f71843ba" +dependencies = [ + "az", + "embedded-graphics", + "object-chain", +] + [[package]] name = "embedded-tls" version = "0.19.0" @@ -789,6 +1282,15 @@ dependencies = [ "typenum", ] +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + [[package]] name = "enumset" version = "1.1.10" @@ -810,6 +1312,26 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "equator" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc" +dependencies = [ + "equator-macro", +] + +[[package]] +name = "equator-macro" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -1014,7 +1536,7 @@ dependencies = [ "esp-radio", "esp-rtos", "esp-storage", - "getrandom", + "getrandom 0.2.15", "heapless 0.8.0", "heapless 0.9.2", "log", @@ -1265,6 +1787,50 @@ dependencies = [ "vcell", ] +[[package]] +name = "exr" +version = "1.74.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4300e043a56aa2cb633c01af81ca8f699a321879a7854d3896a0ba89056363be" +dependencies = [ + "bit_field", + "half", + "lebe", + "miniz_oxide", + "rayon-core", + "smallvec", + "zune-inflate", +] + +[[package]] +name = "fax" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f05de7d48f37cd6730705cbca900770cab77a89f413d23e100ad7fad7795a0ab" +dependencies = [ + "fax_derive", +] + +[[package]] +name = "fax_derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + [[package]] name = "ff" version = "0.13.1" @@ -1275,6 +1841,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + [[package]] name = "fkm-firmware" version = "0.1.0" @@ -1282,7 +1854,10 @@ dependencies = [ "adv-shift-registers", "ag-lcd-async", "anyhow", + "bq27441", "critical-section", + "display-interface", + "display-interface-i2c", "dotenvy", "dyn-smooth", "embassy-executor", @@ -1290,11 +1865,15 @@ dependencies = [ "embassy-net", "embassy-sync 0.7.2", "embassy-time", + "embedded-graphics", + "embedded-graphics-framebuf", "embedded-hal 1.0.0", "embedded-hal-async", "embedded-hal-bus", "embedded-io-async 0.7.0", + "embedded-layout", "embedded-storage", + "embedded-text", "embedded-tls", "esp-alloc", "esp-backtrace", @@ -1309,12 +1888,14 @@ dependencies = [ "esp-rtos", "esp-storage", "esp32c3", - "getrandom", + "getrandom 0.2.15", "heapless 0.9.2", "log", "macros", "nb 1.1.0", + "oled_async", "portable-atomic", + "profont", "rand_core 0.6.4", "serde", "serde_json", @@ -1324,6 +1905,25 @@ dependencies = [ "ws-framer", ] +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[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" @@ -1339,6 +1939,12 @@ dependencies = [ "gcd", ] +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + [[package]] name = "futures" version = "0.3.32" @@ -1455,6 +2061,18 @@ dependencies = [ "wasi", ] +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + [[package]] name = "ghash" version = "0.5.1" @@ -1465,6 +2083,16 @@ dependencies = [ "polyval", ] +[[package]] +name = "gif" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5df2ba84018d80c213569363bdcd0c64e6933c67fe4c1d60ecf822971a3c35e" +dependencies = [ + "color_quant", + "weezl", +] + [[package]] name = "group" version = "0.13.0" @@ -1476,6 +2104,17 @@ dependencies = [ "subtle", ] +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "zerocopy", +] + [[package]] name = "hash32" version = "0.1.1" @@ -1494,19 +2133,37 @@ dependencies = [ "byteorder", ] +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", +] + [[package]] name = "hashbrown" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +[[package]] +name = "hashlink" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" +dependencies = [ + "hashbrown 0.14.5", +] + [[package]] name = "heapless" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "634bd4d29cbf24424d0a4bfcbf80c6960129dc24424752a7d1d1390607023422" dependencies = [ - "as-slice", + "as-slice 0.1.5", "generic-array 0.14.7", "hash32 0.1.1", "stable_deref_trait", @@ -1568,6 +2225,46 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +[[package]] +name = "image" +version = "0.25.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104" +dependencies = [ + "bytemuck", + "byteorder-lite", + "color_quant", + "exr", + "gif", + "image-webp", + "moxcms", + "num-traits", + "png", + "qoi", + "ravif", + "rayon", + "rgb", + "tiff", + "zune-core", + "zune-jpeg", +] + +[[package]] +name = "image-webp" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3" +dependencies = [ + "byteorder-lite", + "quick-error", +] + +[[package]] +name = "imgref" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c5cedc30da3a610cac6b4ba17597bdf7152cf974e8aab3afb3d54455e371c8" + [[package]] name = "indexmap" version = "2.13.0" @@ -1575,7 +2272,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.16.1", ] [[package]] @@ -1609,6 +2306,17 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "interpolate_name" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "itertools" version = "0.13.0" @@ -1618,6 +2326,15 @@ 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.17" @@ -1648,12 +2365,38 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] + +[[package]] +name = "lebe" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8" + [[package]] name = "libc" version = "0.2.182" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" +[[package]] +name = "libfuzzer-sys" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f12a681b7dd8ce12bff52488013ba614b869148d54dd79836ab85aafdd53f08d" +dependencies = [ + "arbitrary", + "cc", +] + [[package]] name = "linked_list_allocator" version = "0.10.5" @@ -1681,11 +2424,22 @@ version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +[[package]] +name = "loop9" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062" +dependencies = [ + "imgref", +] + [[package]] name = "macros" version = "0.1.0" dependencies = [ - "convert_case", + "anyhow", + "convert_case 0.11.0", + "image", "proc-macro2", "quote", "serde", @@ -1699,12 +2453,48 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d" +[[package]] +name = "maybe-rayon" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" +dependencies = [ + "cfg-if", + "rayon", +] + [[package]] name = "memchr" version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +[[package]] +name = "micromath" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c8dda44ff03a2f238717214da50f65d5a53b45cd213a7370424ffdb6fae815" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "moxcms" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b" +dependencies = [ + "num-traits", + "pxfm", +] + [[package]] name = "nb" version = "0.1.3" @@ -1720,6 +2510,37 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "nom" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" +dependencies = [ + "memchr", +] + +[[package]] +name = "noop_proc_macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + [[package]] name = "num-derive" version = "0.4.2" @@ -1731,6 +2552,26 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -1761,6 +2602,30 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "object-chain" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41af26158b0f5530f7b79955006c2727cd23d0d8e7c3109dc316db0a919784dd" + +[[package]] +name = "oled_async" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66a1a30da0097d4c0e9d7ba0757d62f2db86df3254f59d1e15c3988eb0bb24c4" +dependencies = [ + "defmt 0.3.100", + "display-interface", + "embedded-graphics-core", + "embedded-hal 1.0.0", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + [[package]] name = "opaque-debug" version = "0.3.1" @@ -1785,11 +2650,36 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pastey" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + [[package]] name = "pin-project-lite" version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "png" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" +dependencies = [ + "bitflags 2.11.0", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] [[package]] name = "polyval" @@ -1848,6 +2738,16 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.117", +] + [[package]] name = "primeorder" version = "0.13.6" @@ -1863,7 +2763,29 @@ version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" dependencies = [ - "toml_edit", + "toml_edit 0.23.10+spec-1.0.0", +] + +[[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.117", ] [[package]] @@ -1875,15 +2797,76 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "profiling" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773" +dependencies = [ + "profiling-procmacros", +] + +[[package]] +name = "profiling-procmacros" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b" +dependencies = [ + "quote", + "syn 2.0.117", +] + +[[package]] +name = "profont" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "016681370a9dd6e7ddb4c1a959922fd59dc45e5ebaa5ff5b13090267898ced34" +dependencies = [ + "embedded-graphics", +] + +[[package]] +name = "pxfm" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a041e753da8b807c9255f28de81879c78c876392ff2469cde94799b2896b9d" + +[[package]] +name = "qoi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + [[package]] name = "quote" -version = "1.0.44" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + [[package]] name = "rand" version = "0.8.5" @@ -1893,6 +2876,16 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", +] + [[package]] name = "rand_chacha" version = "0.3.1" @@ -1903,13 +2896,23 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + [[package]] name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.15", ] [[package]] @@ -1917,6 +2920,79 @@ name = "rand_core" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "rav1e" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43b6dd56e85d9483277cde964fd1bdb0428de4fec5ebba7540995639a21cb32b" +dependencies = [ + "aligned-vec", + "arbitrary", + "arg_enum_proc_macro", + "arrayvec", + "av-scenechange", + "av1-grain", + "bitstream-io", + "built", + "cfg-if", + "interpolate_name", + "itertools 0.14.0", + "libc", + "libfuzzer-sys", + "log", + "maybe-rayon", + "new_debug_unreachable", + "noop_proc_macro", + "num-derive", + "num-traits", + "paste", + "profiling", + "rand 0.9.2", + "rand_chacha 0.9.0", + "simd_helpers", + "thiserror", + "v_frame", + "wasm-bindgen", +] + +[[package]] +name = "ravif" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e52310197d971b0f5be7fe6b57530dcd27beb35c1b013f29d66c1ad73fbbcc45" +dependencies = [ + "avif-serialize", + "imgref", + "loop9", + "quick-error", + "rav1e", + "rayon", + "rgb", +] + +[[package]] +name = "rayon" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] [[package]] name = "rfc6979" @@ -1928,6 +3004,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "rgb" +version = "0.8.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b34b781b31e5d73e9fbc8689c70551fd1ade9a19e3e28cfec8580a79290cc4" + [[package]] name = "riscv" version = "0.15.0" @@ -2000,6 +3082,12 @@ dependencies = [ "svgbobdoc", ] +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + [[package]] name = "rustversion" version = "1.0.22" @@ -2067,6 +3155,7 @@ version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ + "indexmap", "itoa", "memchr", "serde", @@ -2074,6 +3163,15 @@ dependencies = [ "zmij", ] +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + [[package]] name = "serde_yaml" version = "0.9.34+deprecated" @@ -2098,6 +3196,12 @@ dependencies = [ "digest", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signature" version = "2.2.0" @@ -2108,6 +3212,27 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "simd-adler32" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" + +[[package]] +name = "simd_helpers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6" +dependencies = [ + "quote", +] + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + [[package]] name = "smoltcp" version = "0.12.0" @@ -2219,6 +3344,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "termcolor" version = "1.4.1" @@ -2248,6 +3379,42 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "tiff" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b63feaf3343d35b6ca4d50483f94843803b0f51634937cc2ec519fc32232bc52" +dependencies = [ + "fax", + "flate2", + "half", + "quick-error", + "weezl", + "zune-jpeg", +] + +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime 0.6.11", + "toml_edit 0.22.27", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + [[package]] name = "toml_datetime" version = "0.7.5+spec-1.1.0" @@ -2257,6 +3424,20 @@ dependencies = [ "serde_core", ] +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime 0.6.11", + "toml_write", + "winnow", +] + [[package]] name = "toml_edit" version = "0.23.10+spec-1.0.0" @@ -2264,7 +3445,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" dependencies = [ "indexmap", - "toml_datetime", + "toml_datetime 0.7.5+spec-1.1.0", "toml_parser", "winnow", ] @@ -2278,6 +3459,12 @@ dependencies = [ "winnow", ] +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + [[package]] name = "trouble-host" version = "0.5.1" @@ -2294,8 +3481,8 @@ dependencies = [ "futures", "heapless 0.9.2", "p256", - "rand", - "rand_chacha", + "rand 0.8.5", + "rand_chacha 0.3.1", "rand_core 0.6.4", "static_cell", "trouble-host-macros", @@ -2308,7 +3495,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bcb85bec3a8393c22ca1a7c25c82c2d33689ab412f3487c492fd01a033ede7c2" dependencies = [ - "convert_case", + "convert_case 0.8.0", "darling 0.20.11", "proc-macro2", "quote", @@ -2368,7 +3555,18 @@ version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3758f5e68192bb96cc8f9b7e2c2cfdabb435499a28499a42f8f984092adad4b" dependencies = [ - "getrandom", + "getrandom 0.2.15", +] + +[[package]] +name = "v_frame" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "666b7727c8875d6ab5db9533418d7c764233ac9c0cff1d469aec8fa127597be2" +dependencies = [ + "aligned-vec", + "num-traits", + "wasm-bindgen", ] [[package]] @@ -2395,6 +3593,66 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.117", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "weezl" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" + [[package]] name = "winapi-util" version = "0.1.11" @@ -2428,13 +3686,19 @@ dependencies = [ "memchr", ] +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" + [[package]] name = "ws-framer" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75a918023503304dc681e5f014fc291f68fcdcc886993f9cc6fffc0a0cef329e" dependencies = [ - "getrandom", + "getrandom 0.2.15", "httparse", "itoa", "ws-framer-macros", @@ -2446,12 +3710,21 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67fe343b024b086505b3c647de6eae0c26235934cb9138a180e3ac5f97a6aeda" dependencies = [ - "itertools", + "itertools 0.13.0", "proc-macro2", "quote", "syn 2.0.117", ] +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + [[package]] name = "xtensa-lx" version = "0.13.0" @@ -2483,6 +3756,23 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "y4m" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5a4b21e1a62b67a2970e6831bc091d7b87e119e7f9791aef9702e3bef04448" + +[[package]] +name = "yaml-rust2" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a1a1c0bc9823338a3bdf8c61f994f23ac004c6fa32c08cd152984499b445e8d" +dependencies = [ + "arraydeque", + "encoding_rs", + "hashlink", +] + [[package]] name = "zerocopy" version = "0.8.39" @@ -2514,3 +3804,27 @@ name = "zmij" version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" + +[[package]] +name = "zune-core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb8a0807f7c01457d0379ba880ba6322660448ddebc890ce29bb64da71fb40f9" + +[[package]] +name = "zune-inflate" +version = "0.2.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "zune-jpeg" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec5f41c76397b7da451efd19915684f727d7e1d516384ca6bd0ec43ec94de23c" +dependencies = [ + "zune-core", +] diff --git a/Cargo.toml b/Cargo.toml index f5aab4a..c8c9da8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,6 @@ portable-atomic = { version = "1.13.1", default-features = false } critical-section = "1.2.0" getrandom = { version = "=0.2.15", features = ["custom"] } uuid = { version = "=1.12.1", default-features = false, features = ["v4"] } -dyn-smooth = "0.2.0" esp-hal-ota = { version = "0.4.6", features = ["esp32c3"] } esp32c3 = { version = "0.31.0" } anyhow = { version = "1.0.102", default-features = false } @@ -44,16 +43,30 @@ embedded-hal-bus = { version = "0.3.0", features = ["async"] } #embedded-tls = { git = "https://github.com/drogue-iot/embedded-tls.git", default-features = false, features = ["alloc", "embedded-io-adapters", "log"] } embedded-tls = { git = "https://github.com/filipton/embedded-tls", default-features = false, features = ["alloc", "embedded-io-adapters", "log"] } rand_core = { version = "0.6.4", features = ["getrandom"] } -ag-lcd-async = { git = "https://github.com/filipton/ag-lcd-async", features = [] } esp-hal-mfrc522 = { version = "0.3.3", features = ["embassy-time"] } esp-bootloader-esp-idf = { version = "0.4.0", features = ["log-04", "esp32c3"] } trouble-host = { version = "0.5.1", features = ["scan", "security"] } +# v4 only +display-interface = { version = "0.5.0", optional = true } +display-interface-i2c = { version = "0.5.0", optional = true } +embedded-graphics = { version = "0.8.2", optional = true } +embedded-graphics-framebuf = { version = "0.5.0", optional = true } +oled_async = { version = "0.2.0", features = ["i2c"], optional = true } +bq27441 = { version = "0.1.0", features = ["async", "embassy"], optional = true } +profont = { version = "0.7.0", optional = true } +embedded-layout = { version = "0.4.2", optional = true } +embedded-text = { version = "0.7.3", optional = true } + +#v3 only +dyn-smooth = { version = "0.2.0", optional = true } +ag-lcd-async = { git = "https://github.com/filipton/ag-lcd-async", features = [], optional = true } + [patch.crates-io] elliptic-curve = { git = "https://github.com/filipton/rust-crypto-traits.git" } [features] -default = ["sleep"] +default = ["sleep", "v4"] gen_version = [] bat_dev_lcd = [] release_build = ["sleep"] @@ -61,6 +74,8 @@ e2e = [] qa = [] sleep = [] auto_add = [] +v3 = ["dep:dyn-smooth", "dep:ag-lcd-async"] +v4 = ["dep:display-interface", "dep:display-interface-i2c", "dep:embedded-graphics", "dep:embedded-graphics-framebuf", "dep:oled_async", "dep:bq27441", "dep:profont", "dep:embedded-layout", "dep:embedded-text"] [profile.dev] opt-level = 3 diff --git a/build.rs b/build.rs index 2237f2a..ffa7c55 100644 --- a/build.rs +++ b/build.rs @@ -34,9 +34,14 @@ fn main() { format!("D{epoch}") }; - // NOTE: change this if something changes in schematic, (but not MCU) - // This will enable firmware to be built for multiple hw revisions for example - let hw = "v3"; + let hw = if cfg!(feature = "v4") { + "v4" + } else if cfg!(feature = "v3") { + "v3" + } else { + "unknown" + }; + let generated = VERSION_TEMPLATE .replace("{version}", &version_str) .replace("{hw}", hw) diff --git a/macros/Cargo.lock b/macros/Cargo.lock index 8a644bc..42b57be 100644 --- a/macros/Cargo.lock +++ b/macros/Cargo.lock @@ -3,25 +3,482 @@ version = 4 [[package]] -name = "convert_case" +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "aligned" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee4508988c62edf04abd8d92897fca0c2995d907ce1dfeaf369dac3716a40685" +dependencies = [ + "as-slice", +] + +[[package]] +name = "aligned-vec" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b" +dependencies = [ + "equator", +] + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" + +[[package]] +name = "arg_enum_proc_macro" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "as-slice" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "516b6b4f0e40d50dcda9365d53964ec74560ad4284da2e7fc97122cd83174516" +dependencies = [ + "stable_deref_trait", +] + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "av-scenechange" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f321d77c20e19b92c39e7471cf986812cbb46659d2af674adc4331ef3f18394" +dependencies = [ + "aligned", + "anyhow", + "arg_enum_proc_macro", + "arrayvec", + "log", + "num-rational", + "num-traits", + "pastey", + "rayon", + "thiserror", + "v_frame", + "y4m", +] + +[[package]] +name = "av1-grain" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cfddb07216410377231960af4fcab838eaa12e013417781b78bd95ee22077f8" +dependencies = [ + "anyhow", + "arrayvec", + "log", + "nom", + "num-rational", + "v_frame", +] + +[[package]] +name = "avif-serialize" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "375082f007bd67184fb9c0374614b29f9aaa604ec301635f72338bb65386a53d" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "bit_field" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6" + +[[package]] +name = "bitflags" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" + +[[package]] +name = "bitstream-io" +version = "4.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60d4bd9d1db2c6bdf285e223a7fa369d5ce98ec767dec949c6ca62863ce61757" +dependencies = [ + "core2", +] + +[[package]] +name = "built" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baaaa0ecca5b51987b9423ccdc971514dd8b0bb7b4060b983d3664dad3f1f89f" +checksum = "f4ad8f11f288f48ca24471bbd51ac257aaeaaa07adae295591266b792902ae64" + +[[package]] +name = "bumpalo" +version = "3.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" + +[[package]] +name = "bytemuck" +version = "1.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" + +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + +[[package]] +name = "cc" +version = "1.2.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "convert_case" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "affbf0190ed2caf063e3def54ff444b449371d55c58e513a95ab98eca50adb49" dependencies = [ "unicode-segmentation", ] +[[package]] +name = "core2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505" +dependencies = [ + "memchr", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "equator" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc" +dependencies = [ + "equator-macro", +] + +[[package]] +name = "equator-macro" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "exr" +version = "1.74.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4300e043a56aa2cb633c01af81ca8f699a321879a7854d3896a0ba89056363be" +dependencies = [ + "bit_field", + "half", + "lebe", + "miniz_oxide", + "rayon-core", + "smallvec", + "zune-inflate", +] + +[[package]] +name = "fax" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f05de7d48f37cd6730705cbca900770cab77a89f413d23e100ad7fad7795a0ab" +dependencies = [ + "fax_derive", +] + +[[package]] +name = "fax_derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + +[[package]] +name = "gif" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5df2ba84018d80c213569363bdcd0c64e6933c67fe4c1d60ecf822971a3c35e" +dependencies = [ + "color_quant", + "weezl", +] + +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "zerocopy", +] + +[[package]] +name = "image" +version = "0.25.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104" +dependencies = [ + "bytemuck", + "byteorder-lite", + "color_quant", + "exr", + "gif", + "image-webp", + "moxcms", + "num-traits", + "png", + "qoi", + "ravif", + "rayon", + "rgb", + "tiff", + "zune-core", + "zune-jpeg", +] + +[[package]] +name = "image-webp" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3" +dependencies = [ + "byteorder-lite", + "quick-error", +] + +[[package]] +name = "imgref" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c5cedc30da3a610cac6b4ba17597bdf7152cf974e8aab3afb3d54455e371c8" + +[[package]] +name = "interpolate_name" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[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.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom", + "libc", +] + +[[package]] +name = "lebe" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8" + +[[package]] +name = "libc" +version = "0.2.183" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" + +[[package]] +name = "libfuzzer-sys" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f12a681b7dd8ce12bff52488013ba614b869148d54dd79836ab85aafdd53f08d" +dependencies = [ + "arbitrary", + "cc", +] + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "loop9" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062" +dependencies = [ + "imgref", +] + [[package]] name = "macros" version = "0.1.0" dependencies = [ + "anyhow", "convert_case", + "image", "proc-macro2", "quote", "serde", @@ -29,35 +486,327 @@ dependencies = [ "syn", ] +[[package]] +name = "maybe-rayon" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" +dependencies = [ + "cfg-if", + "rayon", +] + [[package]] name = "memchr" version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "moxcms" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b" +dependencies = [ + "num-traits", + "pxfm", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "nom" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" +dependencies = [ + "memchr", +] + +[[package]] +name = "noop_proc_macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[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", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pastey" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec" + +[[package]] +name = "png" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" +dependencies = [ + "bitflags", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + [[package]] name = "proc-macro2" -version = "1.0.101" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] +[[package]] +name = "profiling" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773" +dependencies = [ + "profiling-procmacros", +] + +[[package]] +name = "profiling-procmacros" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "pxfm" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a041e753da8b807c9255f28de81879c78c876392ff2469cde94799b2896b9d" + +[[package]] +name = "qoi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + [[package]] name = "quote" -version = "1.0.41" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] [[package]] -name = "ryu" -version = "1.0.19" +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rav1e" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" +checksum = "43b6dd56e85d9483277cde964fd1bdb0428de4fec5ebba7540995639a21cb32b" +dependencies = [ + "aligned-vec", + "arbitrary", + "arg_enum_proc_macro", + "arrayvec", + "av-scenechange", + "av1-grain", + "bitstream-io", + "built", + "cfg-if", + "interpolate_name", + "itertools", + "libc", + "libfuzzer-sys", + "log", + "maybe-rayon", + "new_debug_unreachable", + "noop_proc_macro", + "num-derive", + "num-traits", + "paste", + "profiling", + "rand", + "rand_chacha", + "simd_helpers", + "thiserror", + "v_frame", + "wasm-bindgen", +] + +[[package]] +name = "ravif" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e52310197d971b0f5be7fe6b57530dcd27beb35c1b013f29d66c1ad73fbbcc45" +dependencies = [ + "avif-serialize", + "imgref", + "loop9", + "quick-error", + "rav1e", + "rayon", + "rgb", +] + +[[package]] +name = "rayon" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "rgb" +version = "0.8.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b34b781b31e5d73e9fbc8689c70551fd1ade9a19e3e28cfec8580a79290cc4" + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "serde" @@ -91,28 +840,95 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.145" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", "memchr", - "ryu", "serde", "serde_core", + "zmij", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "simd-adler32" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" + +[[package]] +name = "simd_helpers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6" +dependencies = [ + "quote", ] +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + [[package]] name = "syn" -version = "2.0.107" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a26dbd934e5451d21ef060c018dae56fc073894c5a7896f882928a76e6d081b" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tiff" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b63feaf3343d35b6ca4d50483f94843803b0f51634937cc2ec519fc32232bc52" +dependencies = [ + "fax", + "flate2", + "half", + "quick-error", + "weezl", + "zune-jpeg", +] + [[package]] name = "unicode-ident" version = "1.0.13" @@ -124,3 +940,136 @@ name = "unicode-segmentation" version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "v_frame" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "666b7727c8875d6ab5db9533418d7c764233ac9c0cff1d469aec8fa127597be2" +dependencies = [ + "aligned-vec", + "num-traits", + "wasm-bindgen", +] + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "weezl" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" + +[[package]] +name = "y4m" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5a4b21e1a62b67a2970e6831bc091d7b87e119e7f9791aef9702e3bef04448" + +[[package]] +name = "zerocopy" +version = "0.8.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2578b716f8a7a858b7f02d5bd870c14bf4ddbbcf3a4c05414ba6503640505e3" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e6cc098ea4d3bd6246687de65af3f920c430e236bee1e3bf2e441463f08a02f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" + +[[package]] +name = "zune-core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb8a0807f7c01457d0379ba880ba6322660448ddebc890ce29bb64da71fb40f9" + +[[package]] +name = "zune-inflate" +version = "0.2.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "zune-jpeg" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec5f41c76397b7da451efd19915684f727d7e1d516384ca6bd0ec43ec94de23c" +dependencies = [ + "zune-core", +] diff --git a/macros/Cargo.toml b/macros/Cargo.toml index 2c18044..97b8c25 100644 --- a/macros/Cargo.toml +++ b/macros/Cargo.toml @@ -7,9 +7,11 @@ edition = "2021" proc-macro = true [dependencies] -convert_case = "0.8.0" -proc-macro2 = "1.0.95" -quote = "1.0.40" -serde = { version = "1.0.219", features = ["derive"] } -serde_json = "1.0.142" -syn = { version = "2.0.104", features = ["extra-traits", "full"] } +anyhow = "1.0.102" +convert_case = "0.11.0" +image = "0.25.10" +proc-macro2 = "1.0.106" +quote = "1.0.45" +serde = { version = "1.0.228", features = ["derive"] } +serde_json = "1.0.149" +syn = { version = "2.0.117", features = ["extra-traits", "full"] } diff --git a/macros/src/lib.rs b/macros/src/lib.rs index 80ff700..c3619fc 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -1,5 +1,6 @@ #![feature(proc_macro_span)] +mod pixelart; mod translations; use proc_macro::TokenStream; @@ -204,6 +205,11 @@ pub fn load_default_translations(args: TokenStream) -> TokenStream { translations::load_translations_macro(args) } +#[proc_macro] +pub fn load_lcd_resources(args: TokenStream) -> TokenStream { + pixelart::load_lcd_resources(args) +} + // Maybe not useful, most variables in functions that can fail are owned :( /* struct MacroInput { diff --git a/macros/src/pixelart.rs b/macros/src/pixelart.rs new file mode 100644 index 0000000..cc367db --- /dev/null +++ b/macros/src/pixelart.rs @@ -0,0 +1,152 @@ +use convert_case::Casing; +use image::{GenericImageView, ImageReader}; +use proc_macro::TokenStream; +use quote::{format_ident, quote}; +use std::path::PathBuf; +use syn::{ + parse::{Parse, ParseStream}, + LitStr, +}; + +#[derive(Debug)] +#[allow(dead_code)] +struct PixelArtHandler { + path: String, +} + +impl Parse for PixelArtHandler { + fn parse(input: ParseStream) -> Result { + let path = input.parse::()?; + + Ok(PixelArtHandler { path: path.value() }) + } +} + +pub fn load_lcd_resources(args: TokenStream) -> TokenStream { + let PixelArtHandler { path } = syn::parse_macro_input!(args as PixelArtHandler); + + let mut resources = Vec::new(); + let mut res = std::fs::read_dir(path).expect("Cannot read specified path"); + while let Some(Ok(e)) = res.next() { + let metadata = e.metadata().unwrap(); + if metadata.is_file() { + if let Ok((width, height, data)) = parse_img(e.path()) { + let name = format_ident!( + "{}", + e.file_name() + .to_string_lossy() + .split(".") + .next() + .unwrap() + .to_case(convert_case::Case::Constant) + ); + let data_tokens = quote! { &[#(#data),*] }; + + resources.push(quote! { + pub const #name: PixelArt = PixelArt::new(#data_tokens, #width, #height); + }); + } + } + } + + quote! { + pub struct Resources {} + + impl Resources { + #(#resources)* + } + } + .into() +} + +fn parse_img(path: PathBuf) -> anyhow::Result<(u32, u32, Vec)> { + let img = ImageReader::open(path)?.decode()?; + let (w, h) = img.dimensions(); + + let mut bounding_box_left = 0; + let mut bounding_box_right = w; + let mut bounding_box_top = h; + let mut bounding_box_bottom = 0; + + for x in 0..w { + let mut all_clear = true; + for y in 0..h { + let px = img.get_pixel(x, y).0; + if px == [0, 0, 0, 255] { + all_clear = false; + break; + } + } + + if !all_clear { + bounding_box_right = x; + } + } + + for x in (0..w).rev() { + let mut all_clear = true; + for y in 0..h { + let px = img.get_pixel(x, y).0; + if px == [0, 0, 0, 255] { + all_clear = false; + break; + } + } + + if !all_clear { + bounding_box_left = x; + } + } + + for y in 0..h { + let mut all_clear = true; + for x in 0..w { + let px = img.get_pixel(x, y).0; + if px == [0, 0, 0, 255] { + all_clear = false; + break; + } + } + + if !all_clear { + bounding_box_top = y; + } + } + + for y in (0..h).rev() { + let mut all_clear = true; + for x in 0..w { + let px = img.get_pixel(x, y).0; + if px == [0, 0, 0, 255] { + all_clear = false; + break; + } + } + + if !all_clear { + bounding_box_bottom = y; + } + } + + let x_size = bounding_box_right - bounding_box_left + 1; + let y_size = bounding_box_top - bounding_box_bottom + 1; + + let bytes_per_row = (x_size + 7) / 8; + let mut data = vec![0u8; (bytes_per_row * y_size) as usize]; + for y in bounding_box_bottom..=bounding_box_top { + for x in bounding_box_left..=bounding_box_right { + let px = img.get_pixel(x, y).0; + + if px == [0, 0, 0, 255] { + let relative_x = x - bounding_box_left; + let relative_y = y - bounding_box_bottom; + + let byte_idx = (relative_y * bytes_per_row + relative_x / 8) as usize; + let bit_idx = 7 - (relative_x % 8); + data[byte_idx] |= 1 << bit_idx; + } + } + } + + Ok((x_size, y_size, data)) +} diff --git a/release.sh b/release.sh index e0a6751..3f213d6 100755 --- a/release.sh +++ b/release.sh @@ -24,14 +24,17 @@ while [ -z "$RELEASE_VERSION" ]; do done source ~/export-esp.sh -RELEASE_BUILD="$RELEASE_VERSION" cargo build -r - EPOCH=$(date +%s) +RELEASE_BUILD="$RELEASE_VERSION" cargo build -r --no-default-features --features v3,sleep mkdir -p /tmp/fkm-build &> /dev/null espflash save-image --chip esp32c3 ./target/riscv32imc-unknown-none-elf/release/fkm-firmware "/tmp/fkm-build/v3_STATION_${RELEASE_VERSION}.bin" ./append_metadata.sh "/tmp/fkm-build/v3_STATION_${RELEASE_VERSION}.bin" "$RELEASE_VERSION" "STATION" "v3" "$EPOCH" +RELEASE_BUILD="$RELEASE_VERSION" cargo build -r --no-default-features --features v4,sleep +espflash save-image --chip esp32c3 ./target/riscv32imc-unknown-none-elf/release/fkm-firmware "/tmp/fkm-build/v4_STATION_${RELEASE_VERSION}.bin" +./append_metadata.sh "/tmp/fkm-build/v4_STATION_${RELEASE_VERSION}.bin" "$RELEASE_VERSION" "STATION" "v4" "$EPOCH" + cd $SCRIPT_DIR echo "Version: $RELEASE_VERSION" diff --git a/src/battery.rs b/src/battery_v3.rs similarity index 100% rename from src/battery.rs rename to src/battery_v3.rs diff --git a/src/battery_v4.rs b/src/battery_v4.rs new file mode 100644 index 0000000..f5dbe0a --- /dev/null +++ b/src/battery_v4.rs @@ -0,0 +1,110 @@ +use crate::{consts::BATTERY_SEND_INTERVAL_MS, state::sleep_state, utils::shared_i2c::SharedI2C}; +use embassy_time::{Instant, Timer}; + +const BATTERY_CURVE: [(f64, u8); 11] = [ + (3350.0, 0), + (3400.0, 13), + (3450.0, 19), + (3500.0, 25), + (3550.0, 31), + (3600.0, 38), + (3700.0, 50), + (3800.0, 63), + (3900.0, 75), + (4000.0, 88), + (4100.0, 100), +]; +const BAT_MIN: f64 = BATTERY_CURVE[0].0; +const BAT_MAX: f64 = BATTERY_CURVE[BATTERY_CURVE.len() - 1].0; + +#[embassy_executor::task] +pub async fn battery_read_task(i2c: SharedI2C, state: crate::state::GlobalState) { + let Ok(mut gauge) = bq27441::Bq27441Async::new(i2c).await else { + log::error!("BQ27441 init failed!"); + return; + }; + + if let Ok(soc) = gauge.state_of_charge().await + && soc == 0 + { + log::warn!("Battery was removed before boot!"); + } + + let mut last_soc = 101; + let mut last_charging = true; + let mut last_sent = Instant::now(); + loop { + if sleep_state() { + Timer::after_millis(500).await; + continue; + } + + let mut soc = gauge.state_of_charge().await.unwrap_or(0) as u8; + let mv = gauge.voltage().await.unwrap_or(0) as f64; + if soc == 0 { + soc = bat_percentage(calculate(mv)); + } + let ma = gauge.average_current().await.unwrap_or(0); + let charging = ma >= 0; + + if last_soc != soc || last_charging != charging { + { + let mut state = state.state.lock().await; + state.battery_status = (soc, charging) + } + + state.show_battery.signal(soc); + last_soc = soc; + last_charging = charging; + } + + if last_sent.elapsed().as_millis() >= BATTERY_SEND_INTERVAL_MS { + if state.state.lock().await.server_connected == Some(true) { + crate::ws::send_packet(crate::structs::TimerPacket { + tag: None, + data: crate::structs::TimerPacketInner::Battery { + level: Some(soc as f64), + voltage: Some(mv), + }, + }) + .await; + } + + log::info!("Battery {mv}mv {soc}% (avg current: {ma}mA)"); + last_sent = Instant::now(); + } + + Timer::after_millis(100).await; + } +} + +fn interpolate(v1: f64, p1: u8, v2: f64, p2: u8, voltage: f64) -> u8 { + let percentage = p1 as f64 + (voltage - v1) * (p2 as f64 - p1 as f64) / (v2 - v1); + percentage as u8 +} + +fn bat_percentage(mv: f64) -> u8 { + if mv <= BAT_MIN { + return 0; + } + if mv >= BAT_MAX { + return 100; + } + + // Find the two closest voltage points in our curve + for window in BATTERY_CURVE.windows(2) { + let (v1, p1) = window[0]; + let (v2, p2) = window[1]; + + if mv >= v1 && mv <= v2 { + return interpolate(v1, p1, v2, p2, mv); + } + } + + // Fallback to linear interpolation if something goes wrong + ((mv - BAT_MIN) / (BAT_MAX - BAT_MIN) * 100.0) as u8 +} + +fn calculate(x: f64) -> f64 { + 1.69874 * x + 66.6103 +} diff --git a/src/board.rs b/src/board.rs index 29e88bf..7473e1f 100644 --- a/src/board.rs +++ b/src/board.rs @@ -1,8 +1,5 @@ -use crate::utils::stackmat::{DEC_DIGITS, DOT_MOD}; -use adv_shift_registers::wrappers::ShifterValueRange; -use embedded_hal::digital::OutputPin; use esp_hal::{ - gpio::{AnyPin, Input, InputConfig, Level, Output, Pin, Pull}, + gpio::{AnyPin, Input, InputConfig, Output, Pin, Pull}, peripherals::{ ADC1, AES, BT, FLASH, Peripherals, SPI2, SW_INTERRUPT, TIMG0, TIMG1, UART1, WIFI, }, @@ -10,6 +7,12 @@ use esp_hal::{ timer::timg::TimerGroup, }; +#[cfg(feature = "v3")] +use crate::utils::stackmat::{DEC_DIGITS, DOT_MOD}; + +#[cfg(feature = "v4")] +use crate::utils::shared_i2c::SharedI2C; + #[allow(dead_code)] pub struct Board { // peripherals @@ -27,18 +30,35 @@ pub struct Board { pub sw_interrupt: SW_INTERRUPT<'static>, // spi + #[cfg(feature = "v3")] pub miso: AnyPin<'static>, + #[cfg(feature = "v3")] pub mosi: AnyPin<'static>, + #[cfg(feature = "v3")] pub sck: AnyPin<'static>, + #[cfg(feature = "v3")] pub cs: adv_shift_registers::wrappers::ShifterPin, + #[cfg(feature = "v4")] + pub display_rst: Output<'static>, + #[cfg(feature = "v4")] + pub i2c: SharedI2C, + pub stackmat_rx: AnyPin<'static>, + #[cfg(feature = "v4")] + pub buttons: [Input<'static>; 4], + + #[cfg(feature = "v3")] pub battery: esp_hal::peripherals::GPIO2<'static>, + #[cfg(feature = "v3")] pub button_input: Input<'static>, - pub digits_shifters: ShifterValueRange, + #[cfg(feature = "v3")] + pub digits_shifters: adv_shift_registers::wrappers::ShifterValueRange, + #[cfg(feature = "v3")] pub buttons_shifter: adv_shift_registers::wrappers::ShifterValue, + #[cfg(feature = "v3")] pub lcd: adv_shift_registers::wrappers::ShifterValue, // usb pins @@ -46,8 +66,102 @@ pub struct Board { pub usb_dm: AnyPin<'static>, } +#[cfg(feature = "v4")] +impl Board { + pub fn init(peripherals: Peripherals) -> Board { + let timg0 = TimerGroup::new(peripherals.TIMG0); + let timg1 = TimerGroup::new(peripherals.TIMG1); + let rng = Rng::new(); + let uart1 = peripherals.UART1; + let spi2 = peripherals.SPI2; + let spi_dma = peripherals.DMA_CH0; + let adc1 = peripherals.ADC1; + let wifi = peripherals.WIFI; + let bt = peripherals.BT; + let aes = peripherals.AES; + let flash = peripherals.FLASH; + let sw_interrupt = peripherals.SW_INTERRUPT; + + let stackmat_rx = peripherals.GPIO20.degrade(); + let usb_dp = peripherals.GPIO19.degrade(); + let usb_dm = peripherals.GPIO18.degrade(); + + let display_rst = Output::new( + peripherals.GPIO7, + esp_hal::gpio::Level::Low, + Default::default(), + ); + + let b1 = Input::new( + peripherals.GPIO0, + InputConfig::default().with_pull(Pull::Down), + ); + + let b2 = Input::new( + peripherals.GPIO1, + InputConfig::default().with_pull(Pull::Down), + ); + + let b3 = Input::new( + peripherals.GPIO2, + InputConfig::default().with_pull(Pull::Down), + ); + + let b4 = Input::new( + peripherals.GPIO3, + InputConfig::default().with_pull(Pull::Down), + ); + + let i2c = esp_hal::i2c::master::I2c::new( + peripherals.I2C0, + esp_hal::i2c::master::Config::default() + .with_frequency(esp_hal::time::Rate::from_khz(400)), + ); + + let i2c = match i2c { + Ok(i2c) => { + let i2c = i2c + .with_sda(peripherals.GPIO8) + .with_scl(peripherals.GPIO9) + .into_async(); + + SharedI2C::new(Some(i2c)) + } + Err(_) => SharedI2C::new(None), + }; + + Board { + timg0, + timg1, + rng, + uart1, + spi2, + spi_dma, + adc1, + wifi, + bt, + aes, + flash, + sw_interrupt, + + i2c, + + display_rst, + stackmat_rx, + buttons: [b1, b2, b3, b4], + + usb_dp, + usb_dm, + } + } +} + +#[cfg(feature = "v3")] impl Board { pub fn init(peripherals: Peripherals) -> Board { + use embedded_hal::digital::OutputPin; + use esp_hal::gpio::Level; + let timg0 = TimerGroup::new(peripherals.TIMG0); let timg1 = TimerGroup::new(peripherals.TIMG1); let rng = Rng::new(); diff --git a/src/buttons.rs b/src/buttons.rs index efb4616..48e2937 100644 --- a/src/buttons.rs +++ b/src/buttons.rs @@ -15,8 +15,9 @@ macros::generate_button_handler_enum!(triggered: &ButtonTrigger, hold_time: u64, #[embassy_executor::task] pub async fn buttons_task( state: GlobalState, - button_input: Input<'static>, - button_reg: adv_shift_registers::wrappers::ShifterValue, + #[cfg(feature = "v4")] button_inputs: [Input<'static>; 4], + #[cfg(feature = "v3")] button_input: Input<'static>, + #[cfg(feature = "v3")] button_reg: adv_shift_registers::wrappers::ShifterValue, ) { let mut handler = ButtonsHandler::new(Some(wakeup_button())); handler.add_handler(Button::Third, ButtonTrigger::Up, submit_up()); @@ -55,7 +56,10 @@ pub async fn buttons_task( ); handler.add_handler(Button::Second, ButtonTrigger::Up, delegate_hold()); + #[cfg(feature = "v3")] handler.run(&state, &button_input, &button_reg).await; + #[cfg(feature = "v4")] + handler.run(&state, &button_inputs).await; } #[macros::button_handler] @@ -174,6 +178,7 @@ async fn submit_up( match state_val.menu_scene { Some(MenuScene::Signing) | Some(MenuScene::Unsigning) => { state_val.menu_scene = None; + state_val.selected_config_menu = Some(0); state.state.signal(); return Ok(true); } @@ -206,6 +211,7 @@ async fn submit_up( state_val.menu_scene = None; state_val.selected_bluetooth_item = 0; + state_val.selected_config_menu = Some(0); state.state.signal(); return Ok(true); } diff --git a/src/consts.rs b/src/consts.rs index f0ad7c4..9e00f4a 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -16,6 +16,7 @@ pub const LOG_SEND_INTERVAL_MS: u64 = 5000; pub const BATTERY_SEND_INTERVAL_MS: u64 = 60000; +#[allow(dead_code)] pub const SCROLL_TICKER_INVERVAL_MS: u64 = 500; pub const LCD_INSPECTION_FRAME_TIME: u64 = 1000 / 30; diff --git a/src/lcd.rs b/src/lcd_v3.rs similarity index 99% rename from src/lcd.rs rename to src/lcd_v3.rs index d742682..0f37065 100644 --- a/src/lcd.rs +++ b/src/lcd_v3.rs @@ -642,7 +642,7 @@ async fn process_lcd_overwrite( } if current_state.server_connected == Some(false) { - if current_state.wifi_conn_lost { + if current_state.wifi_connected == Some(false) { // TODO: maybe add to this translation _ = lcd_driver.print(0, "Wi-Fi", PrintAlign::Center, true); _ = lcd_driver.print(1, "Connection lost", PrintAlign::Center, true); diff --git a/src/lcd_v4.rs b/src/lcd_v4.rs new file mode 100644 index 0000000..b6fe145 --- /dev/null +++ b/src/lcd_v4.rs @@ -0,0 +1,817 @@ +use crate::{ + consts::{ + DEEPER_SLEEP_AFTER_MS, INSPECTION_TIME_PLUS2, LCD_INSPECTION_FRAME_TIME, SLEEP_AFTER_MS, + }, + state::{ + GlobalState, MenuScene, Scene, SignaledGlobalStateInner, deeper_sleep_state, sleep_state, + }, + translations::{TranslationKey, get_translation, get_translation_params}, + utils::{ + lcd_resourcese::{CrossedIcon, Resources}, + shared_i2c::SharedI2C, + stackmat::ms_to_time_str, + }, +}; +use alloc::{format, rc::Rc, string::ToString}; +use anyhow::{Result, anyhow}; +use display_interface_i2c::I2CInterface; +use embassy_sync::{blocking_mutex::raw::NoopRawMutex, signal::Signal}; +use embassy_time::{Delay, Instant, Timer}; +use embedded_graphics::{ + Drawable, + mono_font::MonoTextStyle, + pixelcolor::BinaryColor, + prelude::*, + primitives::{Line, PrimitiveStyle, Rectangle}, + text::{Alignment, Baseline, Text, TextStyle, TextStyleBuilder}, +}; +use embedded_graphics_framebuf::FrameBuf; +use embedded_layout::{ + layout::linear::{FixedMargin, Horizontal, LinearLayout}, + prelude::*, + view_group::ViewGroup, +}; +use embedded_text::{ + TextBox, + alignment::{HorizontalAlignment, VerticalAlignment}, + style::TextBoxStyleBuilder, +}; +use esp_hal::gpio::Output; +use oled_async::{displays::ssd1309::Ssd1309_128_64, mode::GraphicsMode}; + +pub const FBUF_WIDTH: usize = 128; +pub const FBUF_HEIGHT: usize = 64; +pub const FBUF_SIZE: usize = FBUF_WIDTH * FBUF_HEIGHT; + +pub struct OledData<'a> { + pub fbuf: FrameBuf, + pub disp: GraphicsMode>, +} + +impl OledData<'_> { + pub async fn flush(&mut self) -> Result<()> { + self.disp + .draw_iter(&self.fbuf) + .map_err(|e| anyhow!("{e:?}"))?; + self.disp.flush().await.map_err(|e| anyhow!("{e:?}"))?; + + Ok(()) + } + + pub fn clear_main(&mut self) -> Result<()> { + self.fbuf.fill_solid(&MAIN_RECT, BinaryColor::Off); + Ok(()) + } +} + +pub const MAIN_RECT: Rectangle = Rectangle::new(Point::new(0, 11), Size::new(128, 53)); +pub const TOPBAR_RECT: Rectangle = Rectangle::new(Point::new(0, 0), Size::new(128, 10)); +pub const NORMAL_FONT: MonoTextStyle<'_, BinaryColor> = MonoTextStyle::new( + &embedded_graphics::mono_font::ascii::FONT_7X13, + BinaryColor::On, +); +pub const SMALL_FONT: MonoTextStyle<'_, BinaryColor> = MonoTextStyle::new( + &embedded_graphics::mono_font::ascii::FONT_6X9, + BinaryColor::On, +); +pub const TIMER_FONT: MonoTextStyle<'_, BinaryColor> = + MonoTextStyle::new(&profont::PROFONT_14_POINT, BinaryColor::On); + +pub const TEXT_CENTER: TextStyle = TextStyleBuilder::new() + .alignment(Alignment::Center) + .baseline(Baseline::Middle) + .build(); +pub const TEXT_TOPBAR: TextStyle = TextStyleBuilder::new() + .alignment(Alignment::Right) + .baseline(Baseline::Top) + .build(); + +fn center_layout( + content: VG, +) -> LinearLayout, VG> { + LinearLayout::horizontal(content) + .with_alignment(embedded_layout::align::vertical::Center) + .arrange() + .align_to( + &MAIN_RECT, + embedded_layout::align::horizontal::Center, + embedded_layout::align::vertical::Center, + ) +} + +fn center_text_layout(text: &str) -> TextBox<'_, MonoTextStyle<'_, BinaryColor>> { + let textbox_style = TextBoxStyleBuilder::new() + .alignment(HorizontalAlignment::Center) + .vertical_alignment(VerticalAlignment::Middle) + .build(); + + TextBox::with_textbox_style(text, MAIN_RECT, NORMAL_FONT, textbox_style) +} + +fn draw_scrollable_menu(target: &mut D, items: &[&str], selected: usize) +where + D: DrawTarget, +{ + const LINE_HEIGHT: i32 = 10; + const VISIBLE: usize = 5; + const PADDING_X: i32 = 4; + + let menu_font = MonoTextStyle::new( + &embedded_graphics::mono_font::ascii::FONT_6X9, + BinaryColor::On, + ); + let menu_font_inv = MonoTextStyle::new( + &embedded_graphics::mono_font::ascii::FONT_6X9, + BinaryColor::Off, + ); + + let total = items.len(); + let scroll_start = if selected + 1 >= VISIBLE { + (selected + 1 - VISIBLE).min(total.saturating_sub(VISIBLE)) + } else { + 0 + }; + + let start_y = MAIN_RECT.top_left.y; + + for (row, item) in items[scroll_start..].iter().take(VISIBLE).enumerate() { + let item_idx = scroll_start + row; + let y = start_y + row as i32 * LINE_HEIGHT; + let text_y = y + LINE_HEIGHT / 2; + + if item_idx == selected { + let bar = Rectangle::new(Point::new(0, y), Size::new(128, LINE_HEIGHT as u32)); + bar.into_styled(PrimitiveStyle::with_fill(BinaryColor::On)) + .draw(target) + .ok(); + Text::with_text_style( + item, + Point::new(PADDING_X, text_y), + menu_font_inv, + TextStyleBuilder::new() + .alignment(Alignment::Left) + .baseline(Baseline::Middle) + .build(), + ) + .draw(target) + .ok(); + } else { + Text::with_text_style( + item, + Point::new(PADDING_X, text_y), + menu_font, + TextStyleBuilder::new() + .alignment(Alignment::Left) + .baseline(Baseline::Middle) + .build(), + ) + .draw(target) + .ok(); + } + + if scroll_start > 0 && row == 0 { + Text::with_text_style("^", Point::new(122, text_y), menu_font, TEXT_CENTER) + .draw(target) + .ok(); + } + if scroll_start + VISIBLE < total && row == VISIBLE - 1 { + Text::with_text_style("v", Point::new(122, text_y), menu_font, TEXT_CENTER) + .draw(target) + .ok(); + } + } +} + +#[embassy_executor::task] +pub async fn lcd_task( + i2c: SharedI2C, + mut display_rst: Output<'static>, + global_state: GlobalState, + wifi_setup_sig: Rc>, +) { + let di = display_interface_i2c::I2CInterface::new(i2c, 0x3C, 0x40); + let raw_disp = + oled_async::builder::Builder::new(oled_async::displays::ssd1309::Ssd1309_128_64 {}) + .with_rotation(oled_async::prelude::DisplayRotation::Rotate0) + .connect(di); + + let mut disp: oled_async::mode::GraphicsMode<_, _> = raw_disp.into(); + disp.reset(&mut display_rst, &mut Delay); + + let disp_init = async { + disp.init().await?; + disp.clear(); + disp.flush().await?; + + anyhow::Result::<(), display_interface::DisplayError>::Ok(()) + } + .await; + + if let Err(e) = disp_init { + log::error!("Disp init error: {e:?} (but continuing i guess)"); + } + + let mut data = alloc::vec![embedded_graphics::pixelcolor::BinaryColor::Off; FBUF_SIZE]; + let Some(data): Option<&mut [BinaryColor; FBUF_SIZE]> = data.as_mut_array() else { + log::error!("Disp framebuffer data alloc failed!"); + return; + }; + let fbuf = embedded_graphics_framebuf::FrameBuf::new(data, FBUF_WIDTH, FBUF_HEIGHT); + + let mut oled = OledData { fbuf, disp }; + + global_state.show_battery.wait().await; + _ = process_top_bar( + &global_state.state.value().await.clone(), + &global_state, + &mut oled, + ) + .await; + + let text = format!( + "S/N: {:X}\nVER: {}", + crate::utils::get_efuse_u32(), + crate::version::VERSION + ); + let text = Text::with_text_style(&text, Point::zero(), NORMAL_FONT, TEXT_CENTER); + + center_layout(Chain::new(text)).draw(&mut oled.fbuf); + _ = oled.flush().await; + + Timer::after_millis(2500).await; + + let mut last_update; + loop { + let current_state = global_state.state.value().await.clone(); + log::debug!("lcd current_state: {current_state:?}"); + last_update = Instant::now(); + + if sleep_state() { + unsafe { + crate::state::SLEEP_STATE = false; + } + log::warn!("Sleep wakeup!"); + } + + let current_scene = current_state.scene.clone(); + let fut = async { + oled.fbuf.clear(BinaryColor::Off); + _ = process_top_bar(¤t_state, &global_state, &mut oled).await; + _ = process_main(¤t_state, &global_state, &wifi_setup_sig, &mut oled).await; + _ = oled.flush().await; + + loop { + Timer::after_millis(1000).await; + if global_state.show_battery.signaled() { + oled.fbuf.fill_solid(&TOPBAR_RECT, BinaryColor::Off); + let current_state = global_state.state.value().await; + _ = process_top_bar(¤t_state, &global_state, &mut oled).await; + _ = oled.flush().await; + + global_state.show_battery.reset(); + } + + #[cfg(not(any(feature = "e2e", feature = "qa")))] + if !sleep_state() + && (Instant::now() - last_update).as_millis() > SLEEP_AFTER_MS + && current_scene.can_sleep() + { + oled.fbuf.clear(BinaryColor::Off); + + let text = + Text::with_text_style("Sleep", Point::zero(), NORMAL_FONT, TEXT_CENTER); + + center_layout(Chain::new(text)).draw(&mut oled.fbuf); + _ = oled.flush().await; + + { + global_state.state.lock().await.server_connected = Some(false); + } + + unsafe { + crate::state::SLEEP_STATE = true; + crate::state::TRUST_SERVER = false; + } + + global_state.state.signal_reset(); + } + + #[cfg(not(any(feature = "e2e", feature = "qa")))] + if sleep_state() + && !deeper_sleep_state() + && (Instant::now() - last_update).as_millis() > DEEPER_SLEEP_AFTER_MS + { + use esp_hal::rtc_cntl::{Rtc, sleep::RtcioWakeupSource}; + + oled.fbuf.clear(BinaryColor::Off); + let text = Text::with_text_style( + "Deep Sleep", + Point::zero(), + NORMAL_FONT, + TEXT_CENTER, + ); + + center_layout(Chain::new(text)).draw(&mut oled.fbuf); + _ = oled.flush().await; + + unsafe { + use esp_hal::rtc_cntl::sleep::WakeupLevel; + + let wakeup_pins: &mut [( + &mut dyn esp_hal::gpio::RtcPinWithResistors, + esp_hal::rtc_cntl::sleep::WakeupLevel, + )] = &mut [ + (&mut esp_hal::peripherals::GPIO0::steal(), WakeupLevel::High), + (&mut esp_hal::peripherals::GPIO1::steal(), WakeupLevel::High), + (&mut esp_hal::peripherals::GPIO2::steal(), WakeupLevel::High), + (&mut esp_hal::peripherals::GPIO3::steal(), WakeupLevel::High), + ]; + let rtcio = RtcioWakeupSource::new(wakeup_pins); + Rtc::new(esp_hal::peripherals::LPWR::steal()).sleep_deep(&[&rtcio]); + } + } + } + }; + + let res = embassy_futures::select::select(fut, global_state.state.wait()).await; + match res { + embassy_futures::select::Either::First(_) => {} + embassy_futures::select::Either::Second(_) => { + continue; + } + } + } +} + +fn battery_layout( + content: VG, +) -> LinearLayout, VG> { + LinearLayout::horizontal(content) + .with_alignment(embedded_layout::align::vertical::Center) + .with_spacing(FixedMargin(1)) + .arrange() + .align_to( + &Rectangle::new(Point::new(0, 0), Size::new(128, 10)), + embedded_layout::align::horizontal::Right, + embedded_layout::align::vertical::Center, + ) +} + +fn topbar_icons_layout( + content: VG, +) -> LinearLayout, VG> { + LinearLayout::horizontal(content) + .with_alignment(embedded_layout::align::vertical::Center) + .with_spacing(FixedMargin(2)) + .arrange() + .align_to( + &Rectangle::new(Point::new(0, 0), Size::new(128, 10)), + embedded_layout::align::horizontal::Left, + embedded_layout::align::vertical::Center, + ) +} + +async fn process_top_bar( + current_state: &SignaledGlobalStateInner, + _global_state: &GlobalState, + oled: &mut OledData<'_>, +) -> Result<()> { + let text = format!("{}%", current_state.battery_status.0); + let text = Text::with_text_style(&text, Point::zero(), NORMAL_FONT, TEXT_TOPBAR); + if current_state.battery_status.1 { + battery_layout(Chain::new(Resources::CHARGING).append(text)).draw(&mut oled.fbuf)?; + } else { + battery_layout(Chain::new(text)).draw(&mut oled.fbuf)?; + } + + topbar_icons_layout( + Chain::new(CrossedIcon::new( + Resources::WIFI, + !current_state.wifi_connected.unwrap_or(false), + 9, + )) + .append(CrossedIcon::new( + Resources::SERVER, + !current_state.server_connected.unwrap_or(false), + 9, + )) + .append(CrossedIcon::new( + Resources::TIMER, + !current_state.stackmat_connected.unwrap_or(false), + 9, + )), + ) + .draw(&mut oled.fbuf)?; + + let text = if current_state.selected_config_menu.is_some() { + Some("CONFIG") + } else { + match current_state.menu_scene { + Some(MenuScene::Signing) => Some("SIGN"), + Some(MenuScene::Unsigning) => Some("UNSIGN"), + Some(MenuScene::BtDisplay) => Some("BTDISP"), + None => None, + } + }; + if let Some(text) = text { + Text::with_text_style(text, Point::new(64, 5), SMALL_FONT, TEXT_CENTER) + .draw(&mut oled.fbuf)?; + } + + Line::new(Point::new(0, 10), Point::new(128, 10)) + .into_styled(PrimitiveStyle::with_stroke(BinaryColor::On, 1)) + .draw(&mut oled.fbuf)?; + + Ok(()) +} + +async fn process_main( + current_state: &SignaledGlobalStateInner, + global_state: &GlobalState, + wifi_setup_sig: &Signal, + oled: &mut OledData<'_>, +) -> Result<()> { + if let Some(ref error_text) = current_state.error_text { + center_text_layout(&format!( + "{}\n{}", + get_translation(TranslationKey::ERROR_HEADER), + error_text + )) + .draw(&mut oled.fbuf)?; + + return Ok(()); + } + + // display custom message on top of everything! + if let Some((line1, line2)) = ¤t_state.custom_message { + center_text_layout(&format!("{line1}\n{line2}")).draw(&mut oled.fbuf)?; + return Ok(()); + } + + if let Some(sel) = current_state.selected_config_menu { + let items: alloc::vec::Vec = crate::structs::CONFIG_MENU_ITEMS + .iter() + .enumerate() + .map(|(i, name)| alloc::format!("{}. {}", i + 1, name)) + .collect(); + let item_refs: alloc::vec::Vec<&str> = items.iter().map(|s| s.as_str()).collect(); + draw_scrollable_menu(&mut oled.fbuf, &item_refs, sel); + return Ok(()); + } + + match current_state.menu_scene { + Some(MenuScene::Signing) | Some(MenuScene::Unsigning) => { + let prefix = if current_state.menu_scene == Some(MenuScene::Signing) { + "S" + } else { + "Uns" + }; + + let main_text = format!("{prefix}igning"); + + if global_state.sign_unsign_progress.signaled() { + let status = if global_state.sign_unsign_progress.wait().await { + "OK" + } else { + "FAIL" + }; + + center_text_layout(&format!("{main_text}\nOperation: {status}")) + .draw(&mut oled.fbuf)?; + oled.flush().await?; + + Timer::after_millis(300).await; + oled.clear_main()?; + center_text_layout(&format!("{main_text}\nScan the card\n\nSubmit to exit")) + .draw(&mut oled.fbuf)?; + } else { + center_text_layout(&format!("{main_text}\nScan the card\n\nSubmit to exit")) + .draw(&mut oled.fbuf)?; + } + + return Ok(()); + } + Some(crate::state::MenuScene::BtDisplay) => { + let mut items: alloc::vec::Vec = current_state + .discovered_bluetooth_devices + .iter() + .map(|dev| alloc::format!("{} [{:X?}]", dev.name, dev.addr)) + .collect(); + items.push("Unpair".into()); + items.push("Exit".into()); + + let sel = current_state.selected_bluetooth_item; + if sel >= items.len() { + global_state.state.lock().await.selected_bluetooth_item = 0; + } else { + let item_refs: alloc::vec::Vec<&str> = items.iter().map(|s| s.as_str()).collect(); + draw_scrollable_menu(&mut oled.fbuf, &item_refs, sel); + } + return Ok(()); + } + None => {} + } + + let overwritten = process_main_overwrite(current_state, global_state, oled).await; + if overwritten { + return Ok(()); + } + + if let Some(time) = current_state.delegate_hold { + let delegate_remaining = 3 - time; + + if delegate_remaining == 0 { + center_text_layout(&format!( + "{}\n{}", + get_translation(TranslationKey::WAITING_FOR_DELEGATE_HEADER), + get_translation(TranslationKey::WAITING_FOR_DELEGATE_FOOTER) + )) + .draw(&mut oled.fbuf)?; + } else { + center_text_layout(&format!( + "{}\n{}", + get_translation(TranslationKey::CALLING_FOR_DELEGATE_HEADER), + get_translation_params( + TranslationKey::CALLING_FOR_DELEGATE_FOOTER, + &[delegate_remaining], + ) + )) + .draw(&mut oled.fbuf)?; + } + + return Ok(()); + } + + match current_state.scene { + Scene::WifiConnect => { + center_text_layout(&format!( + "{}\n{}", + get_translation(TranslationKey::WAITING_FOR_WIFI_HEADER), + get_translation(TranslationKey::WAITING_FOR_WIFI_FOOTER) + )) + .draw(&mut oled.fbuf)?; + oled.flush().await?; + + wifi_setup_sig.wait().await; + global_state.state.lock().await.scene = Scene::AutoSetupWait; + } + Scene::AutoSetupWait => { + let wifi_ssid = alloc::format!("FKM-{:X}", crate::utils::get_efuse_u32()); + + center_text_layout(&format!( + "{}\n{wifi_ssid}", + get_translation(TranslationKey::WIFI_SETUP_HEADER), + )) + .draw(&mut oled.fbuf)?; + } + Scene::MdnsWait => { + center_text_layout(&format!( + "{}\n{}", + get_translation(TranslationKey::WAITING_FOR_MDNS_HEADER), + get_translation(TranslationKey::WAITING_FOR_MDNS_FOOTER) + )) + .draw(&mut oled.fbuf)?; + } + Scene::GroupSelect => { + let lt = Text::with_text_style("<", Point::zero(), TIMER_FONT, TEXT_CENTER); + let gt = Text::with_text_style(">", Point::zero(), TIMER_FONT, TEXT_CENTER); + LinearLayout::horizontal(Chain::new(lt)) + .with_alignment(embedded_layout::align::vertical::Center) + .arrange() + .align_to( + &MAIN_RECT, + embedded_layout::align::horizontal::Left, + embedded_layout::align::vertical::Center, + ) + .draw(&mut oled.fbuf)?; + + LinearLayout::horizontal(Chain::new(gt)) + .with_alignment(embedded_layout::align::vertical::Center) + .arrange() + .align_to( + &MAIN_RECT, + embedded_layout::align::horizontal::Right, + embedded_layout::align::vertical::Center, + ) + .draw(&mut oled.fbuf)?; + + center_text_layout(&format!( + "{}\n{}", + get_translation(TranslationKey::SELECT_GROUP), + current_state.possible_groups[current_state.group_selected_idx].secondary_text + )) + .draw(&mut oled.fbuf)?; + } + Scene::WaitingForCompetitor => { + if let Some(solve_time) = current_state.solve_time { + let time_str = ms_to_time_str(solve_time); + center_text_layout(&format!( + "{}\n{}", + get_translation(TranslationKey::SCAN_COMPETITOR_CARD_HEADER), + &get_translation_params( + TranslationKey::SCAN_COMPETITOR_CARD_WITH_TIME_FOOTER, + &[time_str], + ) + )) + .draw(&mut oled.fbuf)?; + } else { + center_text_layout(&format!( + "{}\n{}", + get_translation(TranslationKey::SCAN_COMPETITOR_CARD_HEADER), + get_translation(TranslationKey::SCAN_COMPETITOR_CARD_FOOTER), + )) + .draw(&mut oled.fbuf)?; + } + } + Scene::CompetitorInfo => { + let mut text = current_state + .competitor_display + .clone() + .unwrap_or("------".to_string()) + .to_string(); + + if let Some(ref group) = current_state.solve_group { + text += &format!("\n{}", group.secondary_text); + } + + center_text_layout(&text).draw(&mut oled.fbuf)?; + } + Scene::Inspection => { + oled.clear_main()?; + oled.flush().await?; + let inspection_start = global_state + .state + .value() + .await + .inspection_start + .unwrap_or(Instant::now()); + + _ = Text::with_text_style("Inspection", Point::new(64, 50), NORMAL_FONT, TEXT_CENTER) + .draw(&mut oled.disp); + + let text_rect = Rectangle::new(Point::new(0, 28), Size::new(128, 17)); + loop { + let elapsed = (Instant::now() - inspection_start).as_millis(); + let time_str = ms_to_time_str(elapsed); + + _ = oled.disp.fill_solid(&text_rect, BinaryColor::Off); + _ = Text::with_text_style(&time_str, Point::new(64, 36), TIMER_FONT, TEXT_CENTER) + .draw(&mut oled.disp); + _ = oled.disp.flush().await; + + Timer::after_millis(LCD_INSPECTION_FRAME_TIME).await; + } + } + Scene::Timer => { + oled.clear_main()?; + oled.flush().await?; + let text_rect = Rectangle::new(Point::new(0, 28), Size::new(128, 17)); + + loop { + let time = global_state.timer_signal.wait().await; + let time_str = ms_to_time_str(time); + + _ = oled.disp.fill_solid(&text_rect, BinaryColor::Off); + _ = Text::with_text_style(&time_str, Point::new(64, 36), TIMER_FONT, TEXT_CENTER) + .draw(&mut oled.disp); + _ = oled.disp.flush().await; + } + } + Scene::Finished => { + let solve_time = current_state.solve_time.unwrap_or(0); + let time_str = ms_to_time_str(solve_time); + + let inspection_time = + match (current_state.inspection_start, current_state.inspection_end) { + (Some(start), Some(end)) => { + Some(end.saturating_duration_since(start).as_millis()) + } + _ => None, + }; + + let time_display = if current_state.use_inspection() + && inspection_time.unwrap_or(0) > INSPECTION_TIME_PLUS2 + { + let inspection_seconds = inspection_time.unwrap_or(0) / 1000; + alloc::format!("{time_str}+{inspection_seconds}s") + } else { + alloc::format!("{time_str}") + }; + + let penalty = current_state.penalty.unwrap_or(0); + let penalty_str: alloc::string::String = match penalty { + -2 => "DNS".into(), + -1 => "DNF".into(), + 1.. => alloc::format!("+{penalty}"), + _ => alloc::string::String::new(), + }; + + if penalty_str.is_empty() { + let time_text = + Text::with_text_style(&time_display, Point::zero(), TIMER_FONT, TEXT_CENTER); + LinearLayout::horizontal(Chain::new(time_text)) + .with_alignment(embedded_layout::align::vertical::Center) + .arrange() + .align_to( + &MAIN_RECT, + embedded_layout::align::horizontal::Center, + embedded_layout::align::vertical::Top, + ) + .translate(Point::new(0, 10)) + .draw(&mut oled.fbuf)?; + } else { + let time_text = + Text::with_text_style(&time_display, Point::zero(), TIMER_FONT, TEXT_CENTER); + let penalty_text = + Text::with_text_style(&penalty_str, Point::zero(), TIMER_FONT, TEXT_CENTER); + LinearLayout::horizontal(Chain::new(time_text).append(penalty_text)) + .with_alignment(embedded_layout::align::vertical::Center) + .with_spacing(embedded_layout::layout::linear::spacing::FixedMargin(4)) + .arrange() + .align_to( + &MAIN_RECT, + embedded_layout::align::horizontal::Center, + embedded_layout::align::vertical::Top, + ) + .translate(Point::new(0, 10)) + .draw(&mut oled.fbuf)?; + } + + let status = if !current_state.time_confirmed { + Some(get_translation(TranslationKey::CONFIRM_TIME)) + } else if current_state.current_judge.is_none() { + Some(get_translation(TranslationKey::SCAN_JUDGE_CARD)) + } else if current_state.current_competitor.is_some() + && current_state.current_judge.is_some() + { + Some(get_translation(TranslationKey::SCAN_COMPETITOR_CARD)) + } else { + None + }; + + if let Some(status_str) = status { + let textbox_style = TextBoxStyleBuilder::new() + .alignment(HorizontalAlignment::Center) + .vertical_alignment(VerticalAlignment::Bottom) + .build(); + + TextBox::with_textbox_style(&status_str, MAIN_RECT, NORMAL_FONT, textbox_style) + .draw(&mut oled.fbuf)?; + } + } + Scene::Update => loop { + let progress = global_state.update_progress.wait().await; + oled.clear_main()?; + center_text_layout(&format!("Updating\n{progress}%")).draw(&mut oled.fbuf)?; + oled.flush().await?; + }, + } + + Ok(()) +} + +async fn process_main_overwrite( + current_state: &SignaledGlobalStateInner, + _global_state: &GlobalState, + oled: &mut OledData<'_>, +) -> bool { + if !current_state.scene.can_be_lcd_overwritten() { + return false; + } + + if current_state.server_connected == Some(false) { + if current_state.wifi_connected == Some(false) { + _ = center_text_layout("Wi-Fi\nConnection lost").draw(&mut oled.fbuf); + } else { + let text = format!( + "{}\n{}", + get_translation(TranslationKey::SERVER_DISCONNECTED_HEADER), + get_translation(TranslationKey::SERVER_DISCONNECTED_FOOTER) + ); + _ = center_text_layout(&text).draw(&mut oled.fbuf); + } + } else if current_state.device_added == Some(false) { + #[cfg(not(feature = "e2e"))] + let lines = ( + &get_translation(TranslationKey::DEVICE_NOT_ADDED_HEADER), + &get_translation(TranslationKey::DEVICE_NOT_ADDED_FOOTER), + ); + + #[cfg(feature = "e2e")] + let lines = ("Press submit", "To start HIL"); + + let text = format!("{}\n{}", lines.0, lines.1); + _ = center_text_layout(&text).draw(&mut oled.fbuf); + } else if current_state.stackmat_connected == Some(false) { + let text = format!( + "{}\n{}", + get_translation(TranslationKey::STACKMAT_DISCONNECTED_HEADER), + get_translation(TranslationKey::STACKMAT_DISCONNECTED_FOOTER) + ); + _ = center_text_layout(&text).draw(&mut oled.fbuf); + } else { + return false; + } + + true +} diff --git a/src/main.rs b/src/main.rs index d696a05..17e43af 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,6 @@ #![no_std] #![no_main] #![feature(impl_trait_in_assoc_type)] -#![feature(asm_experimental_arch)] #![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic)] extern crate alloc; @@ -21,12 +20,10 @@ use structs::ConnSettings; use utils::{logger::FkmLogger, set_brownout_detection}; use ws_framer::{WsUrl, WsUrlOwned}; -mod battery; mod bluetooth; mod board; mod buttons; mod consts; -mod lcd; mod mdns; mod rfid; mod stackmat; @@ -37,6 +34,16 @@ mod utils; mod version; mod ws; +#[cfg(feature = "v3")] +mod battery_v3; +#[cfg(feature = "v3")] +mod lcd_v3; + +#[cfg(feature = "v4")] +mod battery_v4; +#[cfg(feature = "v4")] +mod lcd_v4; + #[cfg(feature = "qa")] mod qa; @@ -106,6 +113,10 @@ async fn main(spawner: Spawner) { } }; + let reason = esp_hal::rtc_cntl::reset_reason(esp_hal::system::Cpu::ProCpu); + let wake_reason = esp_hal::rtc_cntl::wakeup_cause(); + log::info!("Wake reason: {:?} {:?}", reason, wake_reason); + let global_state = Rc::new(GlobalStateInner::new(&nvs, board.aes)); let wifi_setup_sig = Rc::new(Signal::new()); let wifi_conn_sig = Rc::new(Signal::new()); @@ -114,35 +125,63 @@ async fn main(spawner: Spawner) { unsafe { crate::state::SIGN_KEY = sign_key }; } - spawner.must_spawn(lcd::lcd_task( + #[cfg(feature = "v3")] + spawner.must_spawn(lcd_v3::lcd_task( board.lcd, global_state.clone(), wifi_setup_sig.clone(), board.digits_shifters.clone(), )); + #[cfg(feature = "v4")] + spawner.must_spawn(lcd_v4::lcd_task( + board.i2c.clone(), + board.display_rst, + global_state.clone(), + wifi_setup_sig.clone(), + )); - spawner.must_spawn(battery::battery_read_task( + #[cfg(feature = "v3")] + spawner.must_spawn(battery_v3::battery_read_task( board.battery, board.adc1, global_state.clone(), )); + #[cfg(feature = "v4")] + spawner.must_spawn(battery_v4::battery_read_task( + board.i2c.clone(), + global_state.clone(), + )); + spawner.must_spawn(buttons::buttons_task( global_state.clone(), + #[cfg(feature = "v4")] + board.buttons, + #[cfg(feature = "v3")] board.button_input, + #[cfg(feature = "v3")] board.buttons_shifter, )); spawner.must_spawn(stackmat::stackmat_task( board.uart1, board.stackmat_rx, + #[cfg(feature = "v3")] board.digits_shifters, global_state.clone(), )); spawner.must_spawn(rfid::rfid_task( + #[cfg(feature = "v4")] + board.i2c.clone(), + #[cfg(feature = "v3")] board.miso, + #[cfg(feature = "v3")] board.mosi, + #[cfg(feature = "v3")] board.sck, + #[cfg(feature = "v3")] board.cs, + #[cfg(feature = "v3")] board.spi2, + #[cfg(feature = "v3")] board.spi_dma, global_state.clone(), )); @@ -194,6 +233,10 @@ async fn main(spawner: Spawner) { esp_hal::system::software_reset(); }; + { + global_state.state.lock().await.wifi_connected = Some(true); + } + #[cfg(feature = "qa")] crate::qa::send_qa_resp(crate::qa::QaSignal::WifiSetup); diff --git a/src/resources/CHARGING.png b/src/resources/CHARGING.png new file mode 100644 index 0000000..5288b1c Binary files /dev/null and b/src/resources/CHARGING.png differ diff --git a/src/resources/SERVER.png b/src/resources/SERVER.png new file mode 100644 index 0000000..cb0872e Binary files /dev/null and b/src/resources/SERVER.png differ diff --git a/src/resources/TIMER.png b/src/resources/TIMER.png new file mode 100644 index 0000000..f5f10be Binary files /dev/null and b/src/resources/TIMER.png differ diff --git a/src/resources/WIFI.png b/src/resources/WIFI.png new file mode 100644 index 0000000..82d22a4 Binary files /dev/null and b/src/resources/WIFI.png differ diff --git a/src/rfid.rs b/src/rfid.rs index 072e6d9..8eb5b0a 100644 --- a/src/rfid.rs +++ b/src/rfid.rs @@ -5,36 +5,50 @@ use crate::translations::{TranslationKey, get_translation}; use alloc::string::ToString; use anyhow::{Result, anyhow}; use embassy_time::{Duration, Instant, Timer}; +use esp_hal_mfrc522::consts::UidSize; + +#[cfg(feature = "v3")] use esp_hal::time::Rate; +#[cfg(feature = "v3")] use esp_hal::{ dma::{DmaRxBuf, DmaTxBuf}, dma_buffers, gpio::AnyPin, spi::{Mode, master::Spi}, }; -use esp_hal_mfrc522::consts::UidSize; #[embassy_executor::task] pub async fn rfid_task( - miso: AnyPin<'static>, - mosi: AnyPin<'static>, - sck: AnyPin<'static>, - cs_pin: adv_shift_registers::wrappers::ShifterPin, - spi: esp_hal::peripherals::SPI2<'static>, - dma_chan: esp_hal::peripherals::DMA_CH0<'static>, + #[cfg(feature = "v4")] i2c: crate::utils::shared_i2c::SharedI2C, + #[cfg(feature = "v3")] miso: AnyPin<'static>, + #[cfg(feature = "v3")] mosi: AnyPin<'static>, + #[cfg(feature = "v3")] sck: AnyPin<'static>, + #[cfg(feature = "v3")] cs_pin: adv_shift_registers::wrappers::ShifterPin, + #[cfg(feature = "v3")] spi: esp_hal::peripherals::SPI2<'static>, + #[cfg(feature = "v3")] dma_chan: esp_hal::peripherals::DMA_CH0<'static>, global_state: GlobalState, ) { + #[cfg(feature = "v4")] + let mut mfrc522 = { + let driver = esp_hal_mfrc522::drivers::I2CDriver::new(i2c, 0x28); + esp_hal_mfrc522::MFRC522::new(driver) + }; + #[allow(clippy::manual_div_ceil)] + #[cfg(feature = "v3")] let (rx_buffer, rx_descriptors, tx_buffer, tx_descriptors) = dma_buffers!(512); + #[cfg(feature = "v3")] let Ok(dma_tx_buf) = DmaTxBuf::new(tx_descriptors, tx_buffer) else { log::error!("Dma tx buf failed"); return; }; + #[cfg(feature = "v3")] let Ok(dma_rx_buf) = DmaRxBuf::new(rx_descriptors, rx_buffer) else { log::error!("Dma rx buf failed"); return; }; + #[cfg(feature = "v3")] let Ok(spi) = Spi::new( spi, esp_hal::spi::master::Config::default() @@ -53,6 +67,7 @@ pub async fn rfid_task( return; }; + #[cfg(feature = "v3")] let mut mfrc522 = { let Ok(spi) = embedded_hal_bus::spi::ExclusiveDevice::new(spi, cs_pin, embassy_time::Delay) else { @@ -84,11 +99,11 @@ pub async fn rfid_task( if sleep_state() != rfid_sleep { rfid_sleep = sleep_state(); - /* match rfid_sleep { true => _ = mfrc522.pcd_soft_power_down().await, false => { _ = mfrc522.pcd_soft_power_up().await; + Timer::after_millis(100).await; loop { _ = mfrc522.pcd_init().await; if mfrc522.pcd_is_init().await { @@ -102,7 +117,6 @@ pub async fn rfid_task( } } } - */ } if rfid_sleep { diff --git a/src/stackmat.rs b/src/stackmat.rs index e88ba68..32faf9b 100644 --- a/src/stackmat.rs +++ b/src/stackmat.rs @@ -1,11 +1,8 @@ use crate::{ consts::{INSPECTION_TIME_DNF, INSPECTION_TIME_PLUS2}, state::{GlobalState, Scene, sleep_state}, - utils::stackmat::{ - StackmatTimerState, ms_to_time_str, parse_stackmat_data, time_str_to_display, - }, + utils::stackmat::{StackmatTimerState, parse_stackmat_data}, }; -use adv_shift_registers::wrappers::ShifterValueRange; use alloc::string::ToString; use embassy_time::{Instant, Timer}; use esp_hal::{gpio::AnyPin, peripherals::UART1, uart::UartRx}; @@ -16,7 +13,7 @@ pub static mut CURRENT_TIME: u64 = 0; pub async fn stackmat_task( uart: UART1<'static>, uart_pin: AnyPin<'static>, - display: ShifterValueRange, + #[cfg(feature = "v3")] display: adv_shift_registers::wrappers::ShifterValueRange, global_state: GlobalState, ) { let serial_config = esp_hal::uart::Config::default().with_baudrate(1200); @@ -50,12 +47,12 @@ pub async fn stackmat_task( && last_state != Some(false) { last_state = Some(false); + #[cfg(feature = "v3")] display.set_data(&[255; 6]); let mut state = global_state.state.lock().await; state.stackmat_connected = Some(false); - // TODO: re-think this and maybe reset whole state? if state.scene == Scene::Timer { if state.current_competitor.is_some() { state.scene = Scene::CompetitorInfo; @@ -159,6 +156,7 @@ pub async fn stackmat_task( state.scene = Scene::Timer; } } else if parsed.0 == StackmatTimerState::Stopped { + log::info!("Timer stopped: {}ms", parsed.1); let mut state = global_state.state.lock().await; let last_solve_diff = if cfg!(not(any(feature = "e2e", feature = "qa"))) { state.last_solve_time.unwrap_or(0).abs_diff(parsed.1) @@ -202,8 +200,13 @@ pub async fn stackmat_task( saved_state.to_nvs(&global_state.nvs).await; } - let time_str = ms_to_time_str(parsed.1); - display.set_data(&time_str_to_display(&time_str)); + #[cfg(feature = "v3")] + { + let time_str = crate::utils::stackmat::ms_to_time_str(parsed.1); + display.set_data(&crate::utils::stackmat::time_str_to_display( + &time_str, + )); + } #[cfg(feature = "qa")] crate::qa::send_qa_resp(crate::qa::QaSignal::Stackmat(parsed.1)); @@ -237,6 +240,7 @@ pub async fn stackmat_task( state.time_confirmed = true; } + #[cfg(feature = "v3")] display.set_data(&[255; 6]); } diff --git a/src/state.rs b/src/state.rs index c165369..cb55ba1 100644 --- a/src/state.rs +++ b/src/state.rs @@ -148,10 +148,10 @@ pub struct GlobalStateInner { pub state: SignaledMutex, pub timer_signal: Signal, pub bt_display_signal: Signal, - pub show_battery: Signal, pub update_progress: Signal, pub sign_unsign_progress: Signal, pub ble_sig: Signal, + pub show_battery: Signal, pub nvs: Nvs, pub aes: Mutex>, @@ -166,10 +166,10 @@ impl GlobalStateInner { state: SignaledMutex::new(SignaledGlobalStateInner::new()), timer_signal: Signal::new(), bt_display_signal: Signal::new(), - show_battery: Signal::new(), update_progress: Signal::new(), sign_unsign_progress: Signal::new(), ble_sig: Signal::new(), + show_battery: Signal::new(), nvs: nvs.clone(), aes: Mutex::new(Aes::new(aes)), @@ -180,7 +180,7 @@ impl GlobalStateInner { } } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone)] pub struct SignaledGlobalStateInner { pub scene: Scene, pub menu_scene: Option, @@ -206,8 +206,9 @@ pub struct SignaledGlobalStateInner { pub device_added: Option, pub server_connected: Option, - pub wifi_conn_lost: bool, + pub wifi_connected: Option, pub stackmat_connected: Option, + pub current_competitor: Option, pub current_judge: Option, pub competitor_display: Option, @@ -215,6 +216,9 @@ pub struct SignaledGlobalStateInner { pub delegate_used: bool, pub delegate_hold: Option, + #[cfg(feature = "v4")] + pub battery_status: (u8, bool), + #[cfg(feature = "bat_dev_lcd")] pub current_bat_read: Option, @@ -259,7 +263,7 @@ impl SignaledGlobalStateInner { device_added: None, server_connected: None, - wifi_conn_lost: false, + wifi_connected: None, stackmat_connected: None, current_competitor: None, current_judge: None, @@ -268,6 +272,9 @@ impl SignaledGlobalStateInner { delegate_used: false, delegate_hold: None, + #[cfg(feature = "v4")] + battery_status: (0, false), + #[cfg(feature = "bat_dev_lcd")] current_bat_read: None, @@ -367,6 +374,8 @@ impl SignaledGlobalStateInner { } pub fn parse_saved_state(&mut self, saved: SavedGlobalState) { + log::warn!("Parsed saved state: {saved:?}"); + self.session_id = Some(saved.session_id); self.penalty = Some(saved.penalty); self.solve_time = Some(saved.solve_time); @@ -460,3 +469,42 @@ impl SavedGlobalState { pub async fn clear_saved_global_state(_nvs: &Nvs) {} } + +impl PartialEq for SignaledGlobalStateInner { + fn eq(&self, other: &Self) -> bool { + let result = self.scene == other.scene + && self.menu_scene == other.menu_scene + && self.inspection_start == other.inspection_start + && self.inspection_end == other.inspection_end + && self.solve_time == other.solve_time + && self.last_solve_time == other.last_solve_time + && self.penalty == other.penalty + && self.session_id == other.session_id + && self.time_confirmed == other.time_confirmed + && self.solve_group == other.solve_group + && self.error_text == other.error_text + && self.possible_groups == other.possible_groups + && self.group_selected_idx == other.group_selected_idx + && self.selected_config_menu == other.selected_config_menu + && self.discovered_bluetooth_devices == other.discovered_bluetooth_devices + && self.selected_bluetooth_item == other.selected_bluetooth_item + && self.device_added == other.device_added + && self.server_connected == other.server_connected + && self.wifi_connected == other.wifi_connected + && self.stackmat_connected == other.stackmat_connected + && self.current_competitor == other.current_competitor + && self.current_judge == other.current_judge + && self.competitor_display == other.competitor_display + && self.delegate_used == other.delegate_used + && self.delegate_hold == other.delegate_hold + // battery_status intentionally excluded (v4 hw) + && self.custom_message == other.custom_message; + + #[cfg(feature = "bat_dev_lcd")] + let result = result + && self.current_bat_read == other.current_bat_read + && self.avg_bat_read == other.avg_bat_read; + + result + } +} diff --git a/src/utils/buttons.rs b/src/utils/buttons.rs index 7203acd..329e8c0 100644 --- a/src/utils/buttons.rs +++ b/src/utils/buttons.rs @@ -68,8 +68,9 @@ impl ButtonsHandler { pub async fn run( &mut self, state: &GlobalState, - button_input: &Input<'static>, - button_reg: &adv_shift_registers::wrappers::ShifterValue, + #[cfg(feature = "v4")] button_inputs: &[Input<'static>], + #[cfg(feature = "v3")] button_input: &Input<'static>, + #[cfg(feature = "v3")] button_reg: &adv_shift_registers::wrappers::ShifterValue, ) { let mut debounce_time = esp_hal::time::Instant::now(); let mut old_debounced = i32::MAX; @@ -104,6 +105,16 @@ impl ButtonsHandler { } } + #[cfg(feature = "v4")] + { + for (i, btn) in button_inputs.iter().enumerate().take(4) { + if btn.is_high() { + out_val |= 1 << i; + } + } + } + + #[cfg(feature = "v3")] { let mut val = 0b10000000; for i in 0..4 { diff --git a/src/utils/lcd_resourcese.rs b/src/utils/lcd_resourcese.rs new file mode 100644 index 0000000..c42dc04 --- /dev/null +++ b/src/utils/lcd_resourcese.rs @@ -0,0 +1,213 @@ +use embedded_graphics::{ + pixelcolor::BinaryColor, + prelude::*, + primitives::{Line, PrimitiveStyle, Rectangle}, +}; + +macros::load_lcd_resources!("src/resources"); + +#[derive(Clone, Copy)] +pub struct PixelArt { + data: &'static [u8], // packed bits, MSB first, row by row + width: u32, + height: u32, + top_left: Point, +} + +impl PixelArt { + pub const fn new(data: &'static [u8], width: u32, height: u32) -> Self { + Self { + data, + width, + height, + top_left: Point::zero(), + } + } + + fn bytes_per_row(&self) -> u32 { + self.width.div_ceil(8) + } +} + +impl Dimensions for PixelArt { + fn bounding_box(&self) -> Rectangle { + Rectangle::new(self.top_left, Size::new(self.width, self.height)) + } +} + +impl Transform for PixelArt { + fn translate(&self, by: Point) -> Self { + Self { + top_left: self.top_left + by, + ..*self + } + } + fn translate_mut(&mut self, by: Point) -> &mut Self { + self.top_left += by; + self + } +} + +impl Drawable for PixelArt { + type Color = BinaryColor; + type Output = (); + + fn draw>(&self, target: &mut D) -> Result<(), D::Error> { + let origin = self.top_left; + let bpr = self.bytes_per_row(); + let (w, h) = (self.width, self.height); + let data = self.data; + + target.draw_iter((0..h).flat_map(move |y| { + (0..w).map(move |x| { + let byte = data[(y * bpr + x / 8) as usize]; + let on = byte & (0x80 >> (x % 8)) != 0; + Pixel( + origin + Point::new(x as i32, y as i32), + if on { + BinaryColor::On + } else { + BinaryColor::Off + }, + ) + }) + })) + } +} + +#[allow(dead_code)] +pub struct Overlay { + base: A, + overlay: B, + top_left: Point, +} + +#[allow(dead_code)] +impl Overlay { + pub fn new(base: A, overlay: B) -> Self { + let base_box = base.bounding_box(); + let overlay_box = overlay.bounding_box(); + + // center overlay over base + let offset = Point::new( + (base_box.size.width as i32 - overlay_box.size.width as i32) / 2, + (base_box.size.height as i32 - overlay_box.size.height as i32) / 2, + ); + let overlay = overlay.translate(base_box.top_left + offset); + + Self { + top_left: base_box.top_left, + base, + overlay, + } + } +} + +impl Dimensions for Overlay { + fn bounding_box(&self) -> Rectangle { + Rectangle::new(self.top_left, self.base.bounding_box().size) + } +} + +impl Transform for Overlay { + fn translate(&self, by: Point) -> Self { + Self { + top_left: self.top_left + by, + base: self.base.translate(by), + overlay: self.overlay.translate(by), + } + } + fn translate_mut(&mut self, by: Point) -> &mut Self { + self.top_left += by; + self.base.translate_mut(by); + self.overlay.translate_mut(by); + self + } +} + +impl Drawable for Overlay +where + A: Drawable, + B: Drawable, +{ + type Color = BinaryColor; + type Output = (); + + fn draw>(&self, target: &mut D) -> Result<(), D::Error> { + self.base.draw(target)?; + self.overlay.draw(target)?; + Ok(()) + } +} + +pub struct CrossedIcon { + base: A, + top_left: Point, + crossed: bool, + cross_size: u32, +} + +impl CrossedIcon { + pub fn new(base: A, crossed: bool, cross_size: u32) -> Self { + let base_box = base.bounding_box(); + Self { + base, + top_left: base_box.top_left, + crossed, + cross_size, + } + } +} + +impl Dimensions for CrossedIcon { + fn bounding_box(&self) -> Rectangle { + Rectangle::new(self.top_left, self.base.bounding_box().size) + } +} + +impl Transform for CrossedIcon { + fn translate(&self, by: Point) -> Self { + Self { + top_left: self.top_left + by, + base: self.base.translate(by), + crossed: self.crossed, + cross_size: self.cross_size, + } + } + fn translate_mut(&mut self, by: Point) -> &mut Self { + self.top_left += by; + self.base.translate_mut(by); + self + } +} + +impl Drawable for CrossedIcon +where + A: Drawable + Dimensions, +{ + type Color = BinaryColor; + type Output = (); + fn draw>(&self, target: &mut D) -> Result<(), D::Error> { + self.base.draw(target)?; + if self.crossed { + let thin_stroke = PrimitiveStyle::with_stroke(BinaryColor::On, 1); + let bb = self.bounding_box(); + + // Center the cross over the bounding box + let offset = Point::new( + (bb.size.width as i32 - self.cross_size as i32) / 2, + (bb.size.height as i32 - self.cross_size as i32) / 2, + ); + let tl = bb.top_left + offset; + let s = self.cross_size as i32 - 1; + + Line::new(tl, tl + Point::new(s, s)) + .into_styled(thin_stroke) + .draw(target)?; + Line::new(tl + Point::new(0, s), tl + Point::new(s, 0)) + .into_styled(thin_stroke) + .draw(target)?; + } + Ok(()) + } +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 671ddb1..8bfe1cd 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,12 +1,20 @@ pub mod arc; pub mod backtrace_store; pub mod buttons; -pub mod lcd_abstract; pub mod logger; pub mod rolling_average; pub mod signaled_mutex; pub mod stackmat; +#[cfg(feature = "v3")] +pub mod lcd_abstract; + +#[cfg(feature = "v4")] +pub mod shared_i2c; + +#[cfg(feature = "v4")] +pub mod lcd_resourcese; + pub fn set_brownout_detection(state: bool) { unsafe { let rtc_cntl = &*esp32c3::RTC_CNTL::ptr(); @@ -35,6 +43,7 @@ pub fn get_efuse_u32() -> u32 { mac as u32 } +#[cfg(feature = "v3")] /// Sets cpu clock to 10mHz (not reversable) pub fn deeper_sleep() { esp32c3_set_cpu_freq_10mhz(); @@ -42,6 +51,7 @@ pub fn deeper_sleep() { unsafe { crate::state::DEEPER_SLEEP = true }; } +#[cfg(feature = "v3")] #[allow(unused)] #[inline(always)] fn ets_update_cpu_frequency_rom(ticks_per_us: u32) { @@ -52,6 +62,7 @@ fn ets_update_cpu_frequency_rom(ticks_per_us: u32) { unsafe { ets_update_cpu_frequency(ticks_per_us) }; } +#[cfg(feature = "v3")] fn esp32c3_set_cpu_freq_10mhz() { use esp32c3::{RTC_CNTL, SYSTEM}; diff --git a/src/utils/shared_i2c.rs b/src/utils/shared_i2c.rs new file mode 100644 index 0000000..0cd9a6b --- /dev/null +++ b/src/utils/shared_i2c.rs @@ -0,0 +1,44 @@ +use alloc::{rc::Rc, vec::Vec}; +use embassy_sync::{blocking_mutex::raw::NoopRawMutex, mutex::Mutex}; +use esp_hal::{Async, i2c::master::I2c}; + +#[derive(Clone)] +pub struct SharedI2C { + inner: Option>>>, +} + +impl embedded_hal::i2c::ErrorType for SharedI2C { + type Error = esp_hal::i2c::master::Error; +} + +impl embedded_hal_async::i2c::I2c for SharedI2C { + async fn transaction( + &mut self, + address: u8, + operations: &mut [embedded_hal::i2c::Operation<'_>], + ) -> Result<(), Self::Error> { + let Some(ref i2c) = self.inner else { + return Err(esp_hal::i2c::master::Error::Timeout); + }; + + i2c.lock().await.transaction( + address, + operations + .iter_mut() + .map(esp_hal::i2c::master::Operation::from) + .collect::>() + .iter_mut(), + ) + } +} + +impl SharedI2C { + pub fn new(i2c: Option>) -> Self { + match i2c { + Some(i2c) => SharedI2C { + inner: Some(Rc::new(Mutex::new(i2c))), + }, + None => SharedI2C { inner: None }, + } + } +} diff --git a/src/utils/stackmat.rs b/src/utils/stackmat.rs index d48a2be..8d2b623 100644 --- a/src/utils/stackmat.rs +++ b/src/utils/stackmat.rs @@ -1,4 +1,6 @@ +#[cfg(feature = "v3")] pub const DEC_DIGITS: [u8; 10] = [215, 132, 203, 206, 156, 94, 95, 196, 223, 222]; +#[cfg(feature = "v3")] pub const DOT_MOD: u8 = 32; pub fn parse_stackmat_data(data: &[u8; 8]) -> Result<(StackmatTimerState, u64), ()> { @@ -84,6 +86,7 @@ pub fn generate_stackmat_data(state: &StackmatTimerState, time_ms: u64) -> [u8; data } +#[cfg(feature = "v3")] pub fn time_str_to_display(time: &str) -> [u8; 6] { let mut data = [255; 6]; let mut i = 0; diff --git a/src/ws.rs b/src/ws.rs index 409fc42..12c97a4 100644 --- a/src/ws.rs +++ b/src/ws.rs @@ -143,7 +143,7 @@ async fn ws_loop( if let Err(e) = r { // but if wifi conneceted signal was sent remove wifi connection lost msg if wifi_conn_sig.signaled() && wifi_conn_sig.wait().await { - global_state.state.lock().await.wifi_conn_lost = false; + global_state.state.lock().await.wifi_connected = Some(true); } log::error!("connect error: {e:?}"); @@ -175,7 +175,7 @@ async fn ws_loop( { let mut state = global_state.state.lock().await; state.server_connected = Some(true); - state.wifi_conn_lost = false; // reset conn lost flag + state.wifi_connected = Some(true); } log::info!("connected!"); @@ -355,7 +355,7 @@ async fn ws_rw( continue; } - global_state.state.lock().await.wifi_conn_lost = true; + global_state.state.lock().await.wifi_connected = Some(false); log::error!("Wifi disconnected, ws_rw stop."); return Err(WsRwError::WifiDisconnected); }